|
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* date.c
|
|
|
|
|
* implements DATE and TIME data types specified in SQL standard
|
|
|
|
|
*
|
|
|
|
|
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
* Portions Copyright (c) 1994-5, Regents of the University of California
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* IDENTIFICATION
|
|
|
|
|
* src/backend/utils/adt/date.c
|
|
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "postgres.h"
|
|
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include <float.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
|
|
#include "access/xact.h"
|
|
|
|
|
#include "catalog/pg_type.h"
|
|
|
|
|
#include "common/hashfn.h"
|
Support +/- infinity in the interval data type.
This adds support for infinity to the interval data type, using the
same input/output representation as the other date/time data types
that support infinity. This allows various arithmetic operations on
infinite dates, timestamps and intervals.
The new values are represented by setting all fields of the interval
to INT32/64_MIN for -infinity, and INT32/64_MAX for +infinity. This
ensures that they compare as less/greater than all other interval
values, without the need for any special-case comparison code.
Note that, since those 2 values were formerly accepted as legal finite
intervals, pg_upgrade and dump/restore from an old database will turn
them from finite to infinite intervals. That seems OK, since those
exact values should be extremely rare in practice, and they are
outside the documented range supported by the interval type, which
gives us a certain amount of leeway.
Bump catalog version.
Joseph Koshakow, Jian He, and Ashutosh Bapat, reviewed by me.
Discussion: https://postgr.es/m/CAAvxfHea4%2BsPybKK7agDYOMo9N-Z3J6ZXf3BOM79pFsFNcRjwA%40mail.gmail.com
2 years ago
|
|
|
#include "common/int.h"
|
|
|
|
|
#include "libpq/pqformat.h"
|
|
|
|
|
#include "miscadmin.h"
|
|
|
|
|
#include "nodes/supportnodes.h"
|
|
|
|
|
#include "parser/scansup.h"
|
|
|
|
|
#include "utils/array.h"
|
|
|
|
|
#include "utils/builtins.h"
|
|
|
|
|
#include "utils/date.h"
|
|
|
|
|
#include "utils/datetime.h"
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
#include "utils/numeric.h"
|
|
|
|
|
#include "utils/sortsupport.h"
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* gcc's -ffast-math switch breaks routines that expect exact results from
|
|
|
|
|
* expressions like timeval / SECS_PER_HOUR, where timeval is double.
|
|
|
|
|
*/
|
|
|
|
|
#ifdef __FAST_MATH__
|
|
|
|
|
#error -ffast-math is known to break this code
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* common code for timetypmodin and timetztypmodin */
|
|
|
|
|
static int32
|
|
|
|
|
anytime_typmodin(bool istz, ArrayType *ta)
|
|
|
|
|
{
|
|
|
|
|
int32 *tl;
|
|
|
|
|
int n;
|
|
|
|
|
|
|
|
|
|
tl = ArrayGetIntegerTypmods(ta, &n);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* we're not too tense about good error message here because grammar
|
|
|
|
|
* shouldn't allow wrong number of modifiers for TIME
|
|
|
|
|
*/
|
|
|
|
|
if (n != 1)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
|
errmsg("invalid type modifier")));
|
|
|
|
|
|
|
|
|
|
return anytime_typmod_check(istz, tl[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* exported so parse_expr.c can use it */
|
|
|
|
|
int32
|
|
|
|
|
anytime_typmod_check(bool istz, int32 typmod)
|
|
|
|
|
{
|
|
|
|
|
if (typmod < 0)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
|
errmsg("TIME(%d)%s precision must not be negative",
|
|
|
|
|
typmod, (istz ? " WITH TIME ZONE" : ""))));
|
|
|
|
|
if (typmod > MAX_TIME_PRECISION)
|
|
|
|
|
{
|
|
|
|
|
ereport(WARNING,
|
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
|
errmsg("TIME(%d)%s precision reduced to maximum allowed, %d",
|
|
|
|
|
typmod, (istz ? " WITH TIME ZONE" : ""),
|
|
|
|
|
MAX_TIME_PRECISION)));
|
|
|
|
|
typmod = MAX_TIME_PRECISION;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return typmod;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* common code for timetypmodout and timetztypmodout */
|
|
|
|
|
static char *
|
|
|
|
|
anytime_typmodout(bool istz, int32 typmod)
|
|
|
|
|
{
|
|
|
|
|
const char *tz = istz ? " with time zone" : " without time zone";
|
|
|
|
|
|
|
|
|
|
if (typmod >= 0)
|
|
|
|
|
return psprintf("(%d)%s", (int) typmod, tz);
|
|
|
|
|
else
|
|
|
|
|
return pstrdup(tz);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
* Date ADT
|
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
|
|
|
|
|
/* date_in()
|
|
|
|
|
* Given date text string, convert to internal date format.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
date_in(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
char *str = PG_GETARG_CSTRING(0);
|
|
|
|
|
Node *escontext = fcinfo->context;
|
|
|
|
|
DateADT date;
|
|
|
|
|
fsec_t fsec;
|
|
|
|
|
struct pg_tm tt,
|
|
|
|
|
*tm = &tt;
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
int tzp;
|
|
|
|
|
int dtype;
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
int nf;
|
|
|
|
|
int dterr;
|
|
|
|
|
char *field[MAXDATEFIELDS];
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
int ftype[MAXDATEFIELDS];
|
|
|
|
|
char workbuf[MAXDATELEN + 1];
|
|
|
|
|
DateTimeErrorExtra extra;
|
|
|
|
|
|
|
|
|
|
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
|
|
|
|
field, ftype, MAXDATEFIELDS, &nf);
|
|
|
|
|
if (dterr == 0)
|
|
|
|
|
dterr = DecodeDateTime(field, ftype, nf,
|
|
|
|
|
&dtype, tm, &fsec, &tzp, &extra);
|
|
|
|
|
if (dterr != 0)
|
|
|
|
|
{
|
|
|
|
|
DateTimeParseError(dterr, &extra, str, "date", escontext);
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (dtype)
|
|
|
|
|
{
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
case DTK_DATE:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_EPOCH:
|
|
|
|
|
GetEpochTime(tm);
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_LATE:
|
|
|
|
|
DATE_NOEND(date);
|
|
|
|
|
PG_RETURN_DATEADT(date);
|
|
|
|
|
|
|
|
|
|
case DTK_EARLY:
|
|
|
|
|
DATE_NOBEGIN(date);
|
|
|
|
|
PG_RETURN_DATEADT(date);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
DateTimeParseError(DTERR_BAD_FORMAT, &extra, str, "date", escontext);
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Prevent overflow in Julian-day routines */
|
|
|
|
|
if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
|
|
|
|
|
ereturn(escontext, (Datum) 0,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("date out of range: \"%s\"", str)));
|
|
|
|
|
|
|
|
|
|
date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
|
|
|
|
|
|
|
|
|
|
/* Now check for just-out-of-range dates */
|
|
|
|
|
if (!IS_VALID_DATE(date))
|
|
|
|
|
ereturn(escontext, (Datum) 0,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("date out of range: \"%s\"", str)));
|
|
|
|
|
|
|
|
|
|
PG_RETURN_DATEADT(date);
|
|
|
|
|
}
|
|
|
|
|
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
/* date_out()
|
|
|
|
|
* Given internal format date, convert to text string.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
date_out(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT date = PG_GETARG_DATEADT(0);
|
|
|
|
|
char *result;
|
|
|
|
|
struct pg_tm tt,
|
|
|
|
|
*tm = &tt;
|
|
|
|
|
char buf[MAXDATELEN + 1];
|
|
|
|
|
|
|
|
|
|
if (DATE_NOT_FINITE(date))
|
|
|
|
|
EncodeSpecialDate(date, buf);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
j2date(date + POSTGRES_EPOCH_JDATE,
|
|
|
|
|
&(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
|
|
|
|
|
EncodeDateOnly(tm, DateStyle, buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = pstrdup(buf);
|
|
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
|
}
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* date_recv - converts external binary format to date
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
date_recv(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
|
|
|
|
DateADT result;
|
|
|
|
|
|
|
|
|
|
result = (DateADT) pq_getmsgint(buf, sizeof(DateADT));
|
|
|
|
|
|
|
|
|
|
/* Limit to the same range that date_in() accepts. */
|
|
|
|
|
if (DATE_NOT_FINITE(result))
|
|
|
|
|
/* ok */ ;
|
|
|
|
|
else if (!IS_VALID_DATE(result))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("date out of range")));
|
|
|
|
|
|
|
|
|
|
PG_RETURN_DATEADT(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* date_send - converts date to binary format
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
date_send(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT date = PG_GETARG_DATEADT(0);
|
|
|
|
|
StringInfoData buf;
|
|
|
|
|
|
|
|
|
|
pq_begintypsend(&buf);
|
|
|
|
|
pq_sendint32(&buf, date);
|
|
|
|
|
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* make_date - date constructor
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
make_date(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
struct pg_tm tm;
|
|
|
|
|
DateADT date;
|
|
|
|
|
int dterr;
|
|
|
|
|
bool bc = false;
|
|
|
|
|
|
|
|
|
|
tm.tm_year = PG_GETARG_INT32(0);
|
|
|
|
|
tm.tm_mon = PG_GETARG_INT32(1);
|
|
|
|
|
tm.tm_mday = PG_GETARG_INT32(2);
|
|
|
|
|
|
|
|
|
|
/* Handle negative years as BC */
|
|
|
|
|
if (tm.tm_year < 0)
|
|
|
|
|
{
|
|
|
|
|
bc = true;
|
|
|
|
|
tm.tm_year = -tm.tm_year;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dterr = ValidateDate(DTK_DATE_M, false, false, bc, &tm);
|
|
|
|
|
|
|
|
|
|
if (dterr != 0)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
|
|
|
|
|
errmsg("date field value out of range: %d-%02d-%02d",
|
|
|
|
|
tm.tm_year, tm.tm_mon, tm.tm_mday)));
|
|
|
|
|
|
|
|
|
|
/* Prevent overflow in Julian-day routines */
|
|
|
|
|
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",
|
|
|
|
|
tm.tm_year, tm.tm_mon, tm.tm_mday)));
|
|
|
|
|
|
|
|
|
|
date = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
|
|
|
|
|
|
|
|
|
|
/* Now check for just-out-of-range dates */
|
|
|
|
|
if (!IS_VALID_DATE(date))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("date out of range: %d-%02d-%02d",
|
|
|
|
|
tm.tm_year, tm.tm_mon, tm.tm_mday)));
|
|
|
|
|
|
|
|
|
|
PG_RETURN_DATEADT(date);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Convert reserved date values to string.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
EncodeSpecialDate(DateADT dt, char *str)
|
|
|
|
|
{
|
|
|
|
|
if (DATE_IS_NOBEGIN(dt))
|
|
|
|
|
strcpy(str, EARLY);
|
|
|
|
|
else if (DATE_IS_NOEND(dt))
|
|
|
|
|
strcpy(str, LATE);
|
|
|
|
|
else /* shouldn't happen */
|
|
|
|
|
elog(ERROR, "invalid argument for EncodeSpecialDate");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* GetSQLCurrentDate -- implements CURRENT_DATE
|
|
|
|
|
*/
|
|
|
|
|
DateADT
|
|
|
|
|
GetSQLCurrentDate(void)
|
|
|
|
|
{
|
|
|
|
|
struct pg_tm tm;
|
|
|
|
|
|
|
|
|
|
static int cache_year = 0;
|
|
|
|
|
static int cache_mon = 0;
|
|
|
|
|
static int cache_mday = 0;
|
|
|
|
|
static DateADT cache_date;
|
|
|
|
|
|
|
|
|
|
GetCurrentDateTime(&tm);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* date2j involves several integer divisions; moreover, unless our session
|
|
|
|
|
* lives across local midnight, we don't really have to do it more than
|
|
|
|
|
* once. So it seems worth having a separate cache here.
|
|
|
|
|
*/
|
|
|
|
|
if (tm.tm_year != cache_year ||
|
|
|
|
|
tm.tm_mon != cache_mon ||
|
|
|
|
|
tm.tm_mday != cache_mday)
|
|
|
|
|
{
|
|
|
|
|
cache_date = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
|
|
|
|
|
cache_year = tm.tm_year;
|
|
|
|
|
cache_mon = tm.tm_mon;
|
|
|
|
|
cache_mday = tm.tm_mday;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cache_date;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* GetSQLCurrentTime -- implements CURRENT_TIME, CURRENT_TIME(n)
|
|
|
|
|
*/
|
|
|
|
|
TimeTzADT *
|
|
|
|
|
GetSQLCurrentTime(int32 typmod)
|
|
|
|
|
{
|
|
|
|
|
TimeTzADT *result;
|
|
|
|
|
struct pg_tm tt,
|
|
|
|
|
*tm = &tt;
|
|
|
|
|
fsec_t fsec;
|
|
|
|
|
int tz;
|
|
|
|
|
|
|
|
|
|
GetCurrentTimeUsec(tm, &fsec, &tz);
|
|
|
|
|
|
|
|
|
|
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
|
|
|
|
|
tm2timetz(tm, fsec, tz, result);
|
|
|
|
|
AdjustTimeForTypmod(&(result->time), typmod);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* GetSQLLocalTime -- implements LOCALTIME, LOCALTIME(n)
|
|
|
|
|
*/
|
|
|
|
|
TimeADT
|
|
|
|
|
GetSQLLocalTime(int32 typmod)
|
|
|
|
|
{
|
|
|
|
|
TimeADT result;
|
|
|
|
|
struct pg_tm tt,
|
|
|
|
|
*tm = &tt;
|
|
|
|
|
fsec_t fsec;
|
|
|
|
|
int tz;
|
|
|
|
|
|
|
|
|
|
GetCurrentTimeUsec(tm, &fsec, &tz);
|
|
|
|
|
|
|
|
|
|
tm2time(tm, fsec, &result);
|
|
|
|
|
AdjustTimeForTypmod(&result, typmod);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Comparison functions for dates
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_eq(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal1 = PG_GETARG_DATEADT(0);
|
|
|
|
|
DateADT dateVal2 = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(dateVal1 == dateVal2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_ne(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal1 = PG_GETARG_DATEADT(0);
|
|
|
|
|
DateADT dateVal2 = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(dateVal1 != dateVal2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_lt(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal1 = PG_GETARG_DATEADT(0);
|
|
|
|
|
DateADT dateVal2 = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(dateVal1 < dateVal2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_le(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal1 = PG_GETARG_DATEADT(0);
|
|
|
|
|
DateADT dateVal2 = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(dateVal1 <= dateVal2);
|
|
|
|
|
}
|
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!
29 years ago
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_gt(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!
29 years ago
|
|
|
{
|
|
|
|
|
DateADT dateVal1 = PG_GETARG_DATEADT(0);
|
|
|
|
|
DateADT dateVal2 = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(dateVal1 > dateVal2);
|
|
|
|
|
}
|
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!
29 years ago
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_ge(PG_FUNCTION_ARGS)
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
{
|
|
|
|
|
DateADT dateVal1 = PG_GETARG_DATEADT(0);
|
|
|
|
|
DateADT dateVal2 = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(dateVal1 >= dateVal2);
|
|
|
|
|
}
|
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!
29 years ago
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_cmp(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal1 = PG_GETARG_DATEADT(0);
|
|
|
|
|
DateADT dateVal2 = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
if (dateVal1 < dateVal2)
|
|
|
|
|
PG_RETURN_INT32(-1);
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
else if (dateVal1 > dateVal2)
|
|
|
|
|
PG_RETURN_INT32(1);
|
|
|
|
|
PG_RETURN_INT32(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_sortsupport(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
|
|
|
|
|
|
|
|
|
|
ssup->comparator = ssup_datum_int32_cmp;
|
|
|
|
|
PG_RETURN_VOID();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_finite(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT date = PG_GETARG_DATEADT(0);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(!DATE_NOT_FINITE(date));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_larger(PG_FUNCTION_ARGS)
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
{
|
|
|
|
|
DateADT dateVal1 = PG_GETARG_DATEADT(0);
|
|
|
|
|
DateADT dateVal2 = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_DATEADT((dateVal1 > dateVal2) ? dateVal1 : dateVal2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_smaller(PG_FUNCTION_ARGS)
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
{
|
|
|
|
|
DateADT dateVal1 = PG_GETARG_DATEADT(0);
|
|
|
|
|
DateADT dateVal2 = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_DATEADT((dateVal1 < dateVal2) ? dateVal1 : dateVal2);
|
|
|
|
|
}
|
|
|
|
|
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
/* Compute difference between two dates in days.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
date_mi(PG_FUNCTION_ARGS)
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
{
|
|
|
|
|
DateADT dateVal1 = PG_GETARG_DATEADT(0);
|
|
|
|
|
DateADT dateVal2 = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
|
|
|
|
if (DATE_NOT_FINITE(dateVal1) || DATE_NOT_FINITE(dateVal2))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("cannot subtract infinite dates")));
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT32((int32) (dateVal1 - dateVal2));
|
|
|
|
|
}
|
|
|
|
|
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
/* Add a number of days to a date, giving a new date.
|
|
|
|
|
* Must handle both positive and negative numbers of days.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
date_pli(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(0);
|
|
|
|
|
int32 days = PG_GETARG_INT32(1);
|
|
|
|
|
DateADT result;
|
|
|
|
|
|
|
|
|
|
if (DATE_NOT_FINITE(dateVal))
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
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
9 years ago
|
|
|
PG_RETURN_DATEADT(dateVal); /* can't change infinity */
|
|
|
|
|
|
|
|
|
|
result = dateVal + days;
|
|
|
|
|
|
|
|
|
|
/* Check for integer overflow and out-of-allowed-range */
|
|
|
|
|
if ((days >= 0 ? (result < dateVal) : (result > dateVal)) ||
|
|
|
|
|
!IS_VALID_DATE(result))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("date out of range")));
|
|
|
|
|
|
|
|
|
|
PG_RETURN_DATEADT(result);
|
|
|
|
|
}
|
|
|
|
|
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
/* Subtract a number of days from a date, giving a new date.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
date_mii(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(0);
|
|
|
|
|
int32 days = PG_GETARG_INT32(1);
|
|
|
|
|
DateADT result;
|
|
|
|
|
|
|
|
|
|
if (DATE_NOT_FINITE(dateVal))
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
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
9 years ago
|
|
|
PG_RETURN_DATEADT(dateVal); /* can't change infinity */
|
|
|
|
|
|
|
|
|
|
result = dateVal - days;
|
|
|
|
|
|
|
|
|
|
/* Check for integer overflow and out-of-allowed-range */
|
|
|
|
|
if ((days >= 0 ? (result > dateVal) : (result < dateVal)) ||
|
|
|
|
|
!IS_VALID_DATE(result))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("date out of range")));
|
|
|
|
|
|
|
|
|
|
PG_RETURN_DATEADT(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Promote date to timestamp.
|
|
|
|
|
*
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
* On successful conversion, *overflow is set to zero if it's not NULL.
|
|
|
|
|
*
|
|
|
|
|
* If the date is finite but out of the valid range for timestamp, then:
|
|
|
|
|
* if overflow is NULL, we throw an out-of-range error.
|
|
|
|
|
* if overflow is not NULL, we store +1 or -1 there to indicate the sign
|
|
|
|
|
* of the overflow, and return the appropriate timestamp infinity.
|
|
|
|
|
*
|
|
|
|
|
* Note: *overflow = -1 is actually not possible currently, since both
|
|
|
|
|
* datatypes have the same lower bound, Julian day zero.
|
|
|
|
|
*/
|
|
|
|
|
Timestamp
|
|
|
|
|
date2timestamp_opt_overflow(DateADT dateVal, int *overflow)
|
|
|
|
|
{
|
|
|
|
|
Timestamp result;
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
if (overflow)
|
|
|
|
|
*overflow = 0;
|
|
|
|
|
|
|
|
|
|
if (DATE_IS_NOBEGIN(dateVal))
|
|
|
|
|
TIMESTAMP_NOBEGIN(result);
|
|
|
|
|
else if (DATE_IS_NOEND(dateVal))
|
|
|
|
|
TIMESTAMP_NOEND(result);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Since dates have the same minimum values as timestamps, only upper
|
|
|
|
|
* boundary need be checked for overflow.
|
|
|
|
|
*/
|
|
|
|
|
if (dateVal >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
|
|
|
|
|
{
|
|
|
|
|
if (overflow)
|
|
|
|
|
{
|
|
|
|
|
*overflow = 1;
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
TIMESTAMP_NOEND(result);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("date out of range for timestamp")));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* date is days since 2000, timestamp is microseconds since same... */
|
|
|
|
|
result = dateVal * USECS_PER_DAY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
* Promote date to timestamp, throwing error for overflow.
|
|
|
|
|
*/
|
|
|
|
|
static TimestampTz
|
|
|
|
|
date2timestamp(DateADT dateVal)
|
|
|
|
|
{
|
|
|
|
|
return date2timestamp_opt_overflow(dateVal, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Promote date to timestamp with time zone.
|
|
|
|
|
*
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
* On successful conversion, *overflow is set to zero if it's not NULL.
|
|
|
|
|
*
|
|
|
|
|
* If the date is finite but out of the valid range for timestamptz, then:
|
|
|
|
|
* if overflow is NULL, we throw an out-of-range error.
|
|
|
|
|
* if overflow is not NULL, we store +1 or -1 there to indicate the sign
|
|
|
|
|
* of the overflow, and return the appropriate timestamptz infinity.
|
|
|
|
|
*/
|
|
|
|
|
TimestampTz
|
|
|
|
|
date2timestamptz_opt_overflow(DateADT dateVal, int *overflow)
|
|
|
|
|
{
|
|
|
|
|
TimestampTz result;
|
|
|
|
|
struct pg_tm tt,
|
|
|
|
|
*tm = &tt;
|
|
|
|
|
int tz;
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
if (overflow)
|
|
|
|
|
*overflow = 0;
|
|
|
|
|
|
|
|
|
|
if (DATE_IS_NOBEGIN(dateVal))
|
|
|
|
|
TIMESTAMP_NOBEGIN(result);
|
|
|
|
|
else if (DATE_IS_NOEND(dateVal))
|
|
|
|
|
TIMESTAMP_NOEND(result);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Since dates have the same minimum values as timestamps, only upper
|
|
|
|
|
* boundary need be checked for overflow.
|
|
|
|
|
*/
|
|
|
|
|
if (dateVal >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
|
|
|
|
|
{
|
|
|
|
|
if (overflow)
|
|
|
|
|
{
|
|
|
|
|
*overflow = 1;
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
TIMESTAMP_NOEND(result);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("date out of range for timestamp")));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
j2date(dateVal + POSTGRES_EPOCH_JDATE,
|
|
|
|
|
&(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
|
|
|
|
|
tm->tm_hour = 0;
|
|
|
|
|
tm->tm_min = 0;
|
|
|
|
|
tm->tm_sec = 0;
|
|
|
|
|
tz = DetermineTimeZoneOffset(tm, session_timezone);
|
|
|
|
|
|
|
|
|
|
result = dateVal * USECS_PER_DAY + tz * USECS_PER_SEC;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Since it is possible to go beyond allowed timestamptz range because
|
|
|
|
|
* of time zone, check for allowed timestamp range after adding tz.
|
|
|
|
|
*/
|
|
|
|
|
if (!IS_VALID_TIMESTAMP(result))
|
|
|
|
|
{
|
|
|
|
|
if (overflow)
|
|
|
|
|
{
|
|
|
|
|
if (result < MIN_TIMESTAMP)
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
{
|
|
|
|
|
*overflow = -1;
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
TIMESTAMP_NOBEGIN(result);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
*overflow = 1;
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
TIMESTAMP_NOEND(result);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("date out of range for timestamp")));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
* Promote date to timestamptz, throwing error for overflow.
|
|
|
|
|
*/
|
|
|
|
|
static TimestampTz
|
|
|
|
|
date2timestamptz(DateADT dateVal)
|
|
|
|
|
{
|
|
|
|
|
return date2timestamptz_opt_overflow(dateVal, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* date2timestamp_no_overflow
|
|
|
|
|
*
|
|
|
|
|
* This is chartered to produce a double value that is numerically
|
|
|
|
|
* equivalent to the corresponding Timestamp value, if the date is in the
|
|
|
|
|
* valid range of Timestamps, but in any case not throw an overflow error.
|
|
|
|
|
* We can do this since the numerical range of double is greater than
|
|
|
|
|
* that of non-erroneous timestamps. The results are currently only
|
|
|
|
|
* used for statistical estimation purposes.
|
|
|
|
|
*/
|
|
|
|
|
double
|
|
|
|
|
date2timestamp_no_overflow(DateADT dateVal)
|
|
|
|
|
{
|
|
|
|
|
double result;
|
|
|
|
|
|
|
|
|
|
if (DATE_IS_NOBEGIN(dateVal))
|
|
|
|
|
result = -DBL_MAX;
|
|
|
|
|
else if (DATE_IS_NOEND(dateVal))
|
|
|
|
|
result = DBL_MAX;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* date is days since 2000, timestamp is microseconds since same... */
|
|
|
|
|
result = dateVal * (double) USECS_PER_DAY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Crosstype comparison functions for dates
|
|
|
|
|
*/
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
int32
|
|
|
|
|
date_cmp_timestamp_internal(DateADT dateVal, Timestamp dt2)
|
|
|
|
|
{
|
|
|
|
|
Timestamp dt1;
|
|
|
|
|
int overflow;
|
|
|
|
|
|
|
|
|
|
dt1 = date2timestamp_opt_overflow(dateVal, &overflow);
|
|
|
|
|
if (overflow > 0)
|
|
|
|
|
{
|
|
|
|
|
/* dt1 is larger than any finite timestamp, but less than infinity */
|
|
|
|
|
return TIMESTAMP_IS_NOEND(dt2) ? -1 : +1;
|
|
|
|
|
}
|
|
|
|
|
Assert(overflow == 0); /* -1 case cannot occur */
|
|
|
|
|
|
|
|
|
|
return timestamp_cmp_internal(dt1, dt2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_eq_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(0);
|
|
|
|
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_ne_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(0);
|
|
|
|
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) != 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_lt_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(0);
|
|
|
|
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) < 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_gt_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(0);
|
|
|
|
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) > 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_le_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(0);
|
|
|
|
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) <= 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_ge_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(0);
|
|
|
|
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) >= 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_cmp_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(0);
|
|
|
|
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_INT32(date_cmp_timestamp_internal(dateVal, dt2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32
|
|
|
|
|
date_cmp_timestamptz_internal(DateADT dateVal, TimestampTz dt2)
|
|
|
|
|
{
|
|
|
|
|
TimestampTz dt1;
|
|
|
|
|
int overflow;
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
dt1 = date2timestamptz_opt_overflow(dateVal, &overflow);
|
|
|
|
|
if (overflow > 0)
|
|
|
|
|
{
|
|
|
|
|
/* dt1 is larger than any finite timestamp, but less than infinity */
|
|
|
|
|
return TIMESTAMP_IS_NOEND(dt2) ? -1 : +1;
|
|
|
|
|
}
|
|
|
|
|
if (overflow < 0)
|
|
|
|
|
{
|
|
|
|
|
/* dt1 is less than any finite timestamp, but more than -infinity */
|
|
|
|
|
return TIMESTAMP_IS_NOBEGIN(dt2) ? +1 : -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return timestamptz_cmp_internal(dt1, dt2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_eq_timestamptz(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(0);
|
|
|
|
|
TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_ne_timestamptz(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(0);
|
|
|
|
|
TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) != 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_lt_timestamptz(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(0);
|
|
|
|
|
TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) < 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_gt_timestamptz(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(0);
|
|
|
|
|
TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) > 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_le_timestamptz(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(0);
|
|
|
|
|
TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) <= 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_ge_timestamptz(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(0);
|
|
|
|
|
TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) >= 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
date_cmp_timestamptz(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(0);
|
|
|
|
|
TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_INT32(date_cmp_timestamptz_internal(dateVal, dt2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timestamp_eq_date(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timestamp_ne_date(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) != 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timestamp_lt_date(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) > 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timestamp_gt_date(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) < 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timestamp_le_date(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) >= 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timestamp_ge_date(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) <= 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timestamp_cmp_date(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_INT32(-date_cmp_timestamp_internal(dateVal, dt1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timestamptz_eq_date(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timestamptz_ne_date(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) != 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timestamptz_lt_date(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) > 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timestamptz_gt_date(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) < 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timestamptz_le_date(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) >= 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timestamptz_ge_date(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) <= 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timestamptz_cmp_date(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(1);
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
PG_RETURN_INT32(-date_cmp_timestamptz_internal(dateVal, dt1));
|
|
|
|
|
}
|
|
|
|
|
|
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
8 years ago
|
|
|
/*
|
|
|
|
|
* in_range support function for date.
|
|
|
|
|
*
|
|
|
|
|
* We implement this by promoting the dates to timestamp (without time zone)
|
|
|
|
|
* and then using the timestamp-and-interval in_range function.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
in_range_date_interval(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT val = PG_GETARG_DATEADT(0);
|
|
|
|
|
DateADT base = PG_GETARG_DATEADT(1);
|
|
|
|
|
Interval *offset = PG_GETARG_INTERVAL_P(2);
|
|
|
|
|
bool sub = PG_GETARG_BOOL(3);
|
|
|
|
|
bool less = PG_GETARG_BOOL(4);
|
|
|
|
|
Timestamp valStamp;
|
|
|
|
|
Timestamp baseStamp;
|
|
|
|
|
|
Prevent internal overflows in date-vs-timestamp and related comparisons.
The date-vs-timestamp, date-vs-timestamptz, and timestamp-vs-timestamptz
comparators all worked by promoting the first type to the second and
then doing a simple same-type comparison. This works fine, except
when the conversion result is out of range, in which case we throw an
entirely avoidable error. The sources of such failures are
(a) type date can represent dates much farther in the future than
the timestamp types can;
(b) timezone rotation might cause a just-in-range timestamp value to
become a just-out-of-range timestamptz value.
Up to now we just ignored these corner-case issues, but now we have
an actual user complaint (bug #16657 from Huss EL-Sheikh), so let's
do something about it.
It turns out that commit 52ad1e659 already built all the necessary
infrastructure to support error-free comparisons, but neglected to
actually use it in the main-line code paths. Fix that, do a little
bit of code style review, and remove the now-duplicate logic in
jsonpath_exec.c.
Back-patch to v13 where 52ad1e659 came in. We could take this back
further by back-patching said infrastructure, but given the small
number of complaints so far, I don't feel a great need to.
Discussion: https://postgr.es/m/16657-cde2f876d8cc7971@postgresql.org
5 years ago
|
|
|
/* XXX we could support out-of-range cases here, perhaps */
|
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
8 years ago
|
|
|
valStamp = date2timestamp(val);
|
|
|
|
|
baseStamp = date2timestamp(base);
|
|
|
|
|
|
|
|
|
|
return DirectFunctionCall5(in_range_timestamp_interval,
|
|
|
|
|
TimestampGetDatum(valStamp),
|
|
|
|
|
TimestampGetDatum(baseStamp),
|
|
|
|
|
IntervalPGetDatum(offset),
|
|
|
|
|
BoolGetDatum(sub),
|
|
|
|
|
BoolGetDatum(less));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
/* extract_date()
|
|
|
|
|
* Extract specified field from date type.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
extract_date(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
text *units = PG_GETARG_TEXT_PP(0);
|
|
|
|
|
DateADT date = PG_GETARG_DATEADT(1);
|
|
|
|
|
int64 intresult;
|
|
|
|
|
int type,
|
|
|
|
|
val;
|
|
|
|
|
char *lowunits;
|
|
|
|
|
int year,
|
|
|
|
|
mon,
|
|
|
|
|
mday;
|
|
|
|
|
|
|
|
|
|
lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
|
|
|
|
|
VARSIZE_ANY_EXHDR(units),
|
|
|
|
|
false);
|
|
|
|
|
|
|
|
|
|
type = DecodeUnits(0, lowunits, &val);
|
|
|
|
|
if (type == UNKNOWN_FIELD)
|
|
|
|
|
type = DecodeSpecial(0, lowunits, &val);
|
|
|
|
|
|
|
|
|
|
if (DATE_NOT_FINITE(date) && (type == UNITS || type == RESERV))
|
|
|
|
|
{
|
|
|
|
|
switch (val)
|
|
|
|
|
{
|
|
|
|
|
/* Oscillating units */
|
|
|
|
|
case DTK_DAY:
|
|
|
|
|
case DTK_MONTH:
|
|
|
|
|
case DTK_QUARTER:
|
|
|
|
|
case DTK_WEEK:
|
|
|
|
|
case DTK_DOW:
|
|
|
|
|
case DTK_ISODOW:
|
|
|
|
|
case DTK_DOY:
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* 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 (DATE_IS_NOBEGIN(date))
|
|
|
|
|
PG_RETURN_NUMERIC(DatumGetNumeric(DirectFunctionCall3(numeric_in,
|
|
|
|
|
CStringGetDatum("-Infinity"),
|
|
|
|
|
ObjectIdGetDatum(InvalidOid),
|
|
|
|
|
Int32GetDatum(-1))));
|
|
|
|
|
else
|
|
|
|
|
PG_RETURN_NUMERIC(DatumGetNumeric(DirectFunctionCall3(numeric_in,
|
|
|
|
|
CStringGetDatum("Infinity"),
|
|
|
|
|
ObjectIdGetDatum(InvalidOid),
|
|
|
|
|
Int32GetDatum(-1))));
|
|
|
|
|
default:
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
|
errmsg("unit \"%s\" not supported for type %s",
|
|
|
|
|
lowunits, format_type_be(DATEOID))));
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (type == UNITS)
|
|
|
|
|
{
|
|
|
|
|
j2date(date + POSTGRES_EPOCH_JDATE, &year, &mon, &mday);
|
|
|
|
|
|
|
|
|
|
switch (val)
|
|
|
|
|
{
|
|
|
|
|
case DTK_DAY:
|
|
|
|
|
intresult = mday;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_MONTH:
|
|
|
|
|
intresult = mon;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_QUARTER:
|
|
|
|
|
intresult = (mon - 1) / 3 + 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_WEEK:
|
|
|
|
|
intresult = date2isoweek(year, mon, mday);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_YEAR:
|
|
|
|
|
if (year > 0)
|
|
|
|
|
intresult = year;
|
|
|
|
|
else
|
|
|
|
|
/* there is no year 0, just 1 BC and 1 AD */
|
|
|
|
|
intresult = year - 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_DECADE:
|
|
|
|
|
/* see comments in timestamp_part */
|
|
|
|
|
if (year >= 0)
|
|
|
|
|
intresult = year / 10;
|
|
|
|
|
else
|
|
|
|
|
intresult = -((8 - (year - 1)) / 10);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_CENTURY:
|
|
|
|
|
/* see comments in timestamp_part */
|
|
|
|
|
if (year > 0)
|
|
|
|
|
intresult = (year + 99) / 100;
|
|
|
|
|
else
|
|
|
|
|
intresult = -((99 - (year - 1)) / 100);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_MILLENNIUM:
|
|
|
|
|
/* see comments in timestamp_part */
|
|
|
|
|
if (year > 0)
|
|
|
|
|
intresult = (year + 999) / 1000;
|
|
|
|
|
else
|
|
|
|
|
intresult = -((999 - (year - 1)) / 1000);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_JULIAN:
|
|
|
|
|
intresult = date + POSTGRES_EPOCH_JDATE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_ISOYEAR:
|
|
|
|
|
intresult = date2isoyear(year, mon, mday);
|
|
|
|
|
/* Adjust BC years */
|
|
|
|
|
if (intresult <= 0)
|
|
|
|
|
intresult -= 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_DOW:
|
|
|
|
|
case DTK_ISODOW:
|
|
|
|
|
intresult = j2day(date + POSTGRES_EPOCH_JDATE);
|
|
|
|
|
if (val == DTK_ISODOW && intresult == 0)
|
|
|
|
|
intresult = 7;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_DOY:
|
|
|
|
|
intresult = date2j(year, mon, mday) - date2j(year, 1, 1) + 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
|
errmsg("unit \"%s\" not supported for type %s",
|
|
|
|
|
lowunits, format_type_be(DATEOID))));
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
intresult = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (type == RESERV)
|
|
|
|
|
{
|
|
|
|
|
switch (val)
|
|
|
|
|
{
|
|
|
|
|
case DTK_EPOCH:
|
|
|
|
|
intresult = ((int64) date + POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
|
errmsg("unit \"%s\" not supported for type %s",
|
|
|
|
|
lowunits, format_type_be(DATEOID))));
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
intresult = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
|
errmsg("unit \"%s\" not recognized for type %s",
|
|
|
|
|
lowunits, format_type_be(DATEOID))));
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
intresult = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PG_RETURN_NUMERIC(int64_to_numeric(intresult));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Add an interval to a date, giving a new date.
|
|
|
|
|
* Must handle both positive and negative intervals.
|
|
|
|
|
*
|
|
|
|
|
* We implement this by promoting the date to timestamp (without time zone)
|
|
|
|
|
* and then using the timestamp plus interval function.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
date_pl_interval(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(0);
|
|
|
|
|
Interval *span = PG_GETARG_INTERVAL_P(1);
|
|
|
|
|
Timestamp dateStamp;
|
|
|
|
|
|
|
|
|
|
dateStamp = date2timestamp(dateVal);
|
|
|
|
|
|
|
|
|
|
return DirectFunctionCall2(timestamp_pl_interval,
|
|
|
|
|
TimestampGetDatum(dateStamp),
|
|
|
|
|
PointerGetDatum(span));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Subtract an interval from a date, giving a new date.
|
|
|
|
|
* Must handle both positive and negative intervals.
|
|
|
|
|
*
|
|
|
|
|
* We implement this by promoting the date to timestamp (without time zone)
|
|
|
|
|
* and then using the timestamp minus interval function.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
date_mi_interval(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(0);
|
|
|
|
|
Interval *span = PG_GETARG_INTERVAL_P(1);
|
|
|
|
|
Timestamp dateStamp;
|
|
|
|
|
|
|
|
|
|
dateStamp = date2timestamp(dateVal);
|
|
|
|
|
|
|
|
|
|
return DirectFunctionCall2(timestamp_mi_interval,
|
|
|
|
|
TimestampGetDatum(dateStamp),
|
|
|
|
|
PointerGetDatum(span));
|
|
|
|
|
}
|
|
|
|
|
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
/* date_timestamp()
|
|
|
|
|
* Convert date to timestamp data type.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
date_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(0);
|
|
|
|
|
Timestamp result;
|
|
|
|
|
|
|
|
|
|
result = date2timestamp(dateVal);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMESTAMP(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* timestamp_date()
|
|
|
|
|
* Convert timestamp to date data type.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
timestamp_date(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
|
|
|
|
|
DateADT result;
|
|
|
|
|
struct pg_tm tt,
|
|
|
|
|
*tm = &tt;
|
|
|
|
|
fsec_t fsec;
|
|
|
|
|
|
|
|
|
|
if (TIMESTAMP_IS_NOBEGIN(timestamp))
|
|
|
|
|
DATE_NOBEGIN(result);
|
|
|
|
|
else if (TIMESTAMP_IS_NOEND(timestamp))
|
|
|
|
|
DATE_NOEND(result);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
|
|
|
|
|
result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PG_RETURN_DATEADT(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* date_timestamptz()
|
|
|
|
|
* Convert date to timestamp with time zone data type.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
date_timestamptz(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT dateVal = PG_GETARG_DATEADT(0);
|
|
|
|
|
TimestampTz result;
|
|
|
|
|
|
|
|
|
|
result = date2timestamptz(dateVal);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMESTAMP(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* timestamptz_date()
|
|
|
|
|
* Convert timestamp with time zone to date data type.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
timestamptz_date(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
DateADT result;
|
|
|
|
|
struct pg_tm tt,
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
*tm = &tt;
|
|
|
|
|
fsec_t fsec;
|
|
|
|
|
int tz;
|
|
|
|
|
|
|
|
|
|
if (TIMESTAMP_IS_NOBEGIN(timestamp))
|
|
|
|
|
DATE_NOBEGIN(result);
|
|
|
|
|
else if (TIMESTAMP_IS_NOEND(timestamp))
|
|
|
|
|
DATE_NOEND(result);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
|
|
|
|
|
result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PG_RETURN_DATEADT(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
/*****************************************************************************
|
|
|
|
|
* Time ADT
|
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
time_in(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
char *str = PG_GETARG_CSTRING(0);
|
|
|
|
|
#ifdef NOT_USED
|
|
|
|
|
Oid typelem = PG_GETARG_OID(1);
|
|
|
|
|
#endif
|
|
|
|
|
int32 typmod = PG_GETARG_INT32(2);
|
|
|
|
|
Node *escontext = fcinfo->context;
|
|
|
|
|
TimeADT result;
|
|
|
|
|
fsec_t fsec;
|
|
|
|
|
struct pg_tm tt,
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
*tm = &tt;
|
|
|
|
|
int tz;
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
int nf;
|
|
|
|
|
int dterr;
|
|
|
|
|
char workbuf[MAXDATELEN + 1];
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
char *field[MAXDATEFIELDS];
|
|
|
|
|
int dtype;
|
|
|
|
|
int ftype[MAXDATEFIELDS];
|
|
|
|
|
DateTimeErrorExtra extra;
|
|
|
|
|
|
|
|
|
|
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
|
|
|
|
field, ftype, MAXDATEFIELDS, &nf);
|
|
|
|
|
if (dterr == 0)
|
|
|
|
|
dterr = DecodeTimeOnly(field, ftype, nf,
|
|
|
|
|
&dtype, tm, &fsec, &tz, &extra);
|
|
|
|
|
if (dterr != 0)
|
|
|
|
|
{
|
|
|
|
|
DateTimeParseError(dterr, &extra, str, "time", escontext);
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tm2time(tm, fsec, &result);
|
|
|
|
|
AdjustTimeForTypmod(&result, typmod);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMEADT(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* tm2time()
|
|
|
|
|
* Convert a tm structure to a time data type.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
tm2time(struct pg_tm *tm, fsec_t fsec, TimeADT *result)
|
|
|
|
|
{
|
|
|
|
|
*result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec)
|
|
|
|
|
* USECS_PER_SEC) + fsec;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* time_overflows()
|
|
|
|
|
* Check to see if a broken-down time-of-day is out of range.
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
time_overflows(int hour, int min, int sec, fsec_t fsec)
|
|
|
|
|
{
|
|
|
|
|
/* Range-check the fields individually. */
|
|
|
|
|
if (hour < 0 || hour > HOURS_PER_DAY ||
|
|
|
|
|
min < 0 || min >= MINS_PER_HOUR ||
|
|
|
|
|
sec < 0 || sec > SECS_PER_MINUTE ||
|
|
|
|
|
fsec < 0 || fsec > USECS_PER_SEC)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Because we allow, eg, hour = 24 or sec = 60, we must check separately
|
|
|
|
|
* that the total time value doesn't exceed 24:00:00.
|
|
|
|
|
*/
|
|
|
|
|
if ((((((hour * MINS_PER_HOUR + min) * SECS_PER_MINUTE)
|
|
|
|
|
+ sec) * USECS_PER_SEC) + fsec) > USECS_PER_DAY)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* float_time_overflows()
|
|
|
|
|
* Same, when we have seconds + fractional seconds as one "double" value.
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
float_time_overflows(int hour, int min, double sec)
|
|
|
|
|
{
|
|
|
|
|
/* Range-check the fields individually. */
|
|
|
|
|
if (hour < 0 || hour > HOURS_PER_DAY ||
|
|
|
|
|
min < 0 || min >= MINS_PER_HOUR)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* "sec", being double, requires extra care. Cope with NaN, and round off
|
|
|
|
|
* before applying the range check to avoid unexpected errors due to
|
|
|
|
|
* imprecise input. (We assume rint() behaves sanely with infinities.)
|
|
|
|
|
*/
|
|
|
|
|
if (isnan(sec))
|
|
|
|
|
return true;
|
|
|
|
|
sec = rint(sec * USECS_PER_SEC);
|
|
|
|
|
if (sec < 0 || sec > SECS_PER_MINUTE * USECS_PER_SEC)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Because we allow, eg, hour = 24 or sec = 60, we must check separately
|
|
|
|
|
* that the total time value doesn't exceed 24:00:00. This must match the
|
|
|
|
|
* way that callers will convert the fields to a time.
|
|
|
|
|
*/
|
|
|
|
|
if (((((hour * MINS_PER_HOUR + min) * SECS_PER_MINUTE)
|
|
|
|
|
* USECS_PER_SEC) + (int64) sec) > USECS_PER_DAY)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* time2tm()
|
|
|
|
|
* Convert time data type to POSIX time structure.
|
|
|
|
|
*
|
|
|
|
|
* Note that only the hour/min/sec/fractional-sec fields are filled in.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
time2tm(TimeADT time, struct pg_tm *tm, fsec_t *fsec)
|
|
|
|
|
{
|
|
|
|
|
tm->tm_hour = time / USECS_PER_HOUR;
|
|
|
|
|
time -= tm->tm_hour * USECS_PER_HOUR;
|
|
|
|
|
tm->tm_min = time / USECS_PER_MINUTE;
|
|
|
|
|
time -= tm->tm_min * USECS_PER_MINUTE;
|
|
|
|
|
tm->tm_sec = time / USECS_PER_SEC;
|
|
|
|
|
time -= tm->tm_sec * USECS_PER_SEC;
|
|
|
|
|
*fsec = time;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
time_out(PG_FUNCTION_ARGS)
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
{
|
|
|
|
|
TimeADT time = PG_GETARG_TIMEADT(0);
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
char *result;
|
|
|
|
|
struct pg_tm tt,
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
*tm = &tt;
|
|
|
|
|
fsec_t fsec;
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
char buf[MAXDATELEN + 1];
|
|
|
|
|
|
|
|
|
|
time2tm(time, tm, &fsec);
|
|
|
|
|
EncodeTimeOnly(tm, fsec, false, 0, DateStyle, buf);
|
|
|
|
|
|
|
|
|
|
result = pstrdup(buf);
|
|
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* time_recv - converts external binary format to time
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
time_recv(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
|
|
|
|
|
|
|
|
|
#ifdef NOT_USED
|
|
|
|
|
Oid typelem = PG_GETARG_OID(1);
|
|
|
|
|
#endif
|
|
|
|
|
int32 typmod = PG_GETARG_INT32(2);
|
|
|
|
|
TimeADT result;
|
|
|
|
|
|
|
|
|
|
result = pq_getmsgint64(buf);
|
|
|
|
|
|
|
|
|
|
if (result < INT64CONST(0) || result > USECS_PER_DAY)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("time out of range")));
|
|
|
|
|
|
|
|
|
|
AdjustTimeForTypmod(&result, typmod);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMEADT(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* time_send - converts time to binary format
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
time_send(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeADT time = PG_GETARG_TIMEADT(0);
|
|
|
|
|
StringInfoData buf;
|
|
|
|
|
|
|
|
|
|
pq_begintypsend(&buf);
|
|
|
|
|
pq_sendint64(&buf, time);
|
|
|
|
|
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timetypmodin(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT32(anytime_typmodin(false, ta));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timetypmodout(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int32 typmod = PG_GETARG_INT32(0);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_CSTRING(anytime_typmodout(false, typmod));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* make_time - time constructor
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
make_time(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int tm_hour = PG_GETARG_INT32(0);
|
|
|
|
|
int tm_min = PG_GETARG_INT32(1);
|
|
|
|
|
double sec = PG_GETARG_FLOAT8(2);
|
|
|
|
|
TimeADT time;
|
|
|
|
|
|
|
|
|
|
/* Check for time overflow */
|
|
|
|
|
if (float_time_overflows(tm_hour, tm_min, sec))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
|
|
|
|
|
errmsg("time field value out of range: %d:%02d:%02g",
|
|
|
|
|
tm_hour, tm_min, sec)));
|
|
|
|
|
|
|
|
|
|
/* This should match tm2time */
|
|
|
|
|
time = (((tm_hour * MINS_PER_HOUR + tm_min) * SECS_PER_MINUTE)
|
|
|
|
|
* USECS_PER_SEC) + (int64) rint(sec * USECS_PER_SEC);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMEADT(time);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* time_support()
|
|
|
|
|
*
|
|
|
|
|
* Planner support function for the time_scale() and timetz_scale()
|
|
|
|
|
* length coercion functions (we need not distinguish them here).
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
time_support(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
Node *rawreq = (Node *) PG_GETARG_POINTER(0);
|
|
|
|
|
Node *ret = NULL;
|
|
|
|
|
|
|
|
|
|
if (IsA(rawreq, SupportRequestSimplify))
|
|
|
|
|
{
|
|
|
|
|
SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
|
|
|
|
|
|
|
|
|
|
ret = TemporalSimplify(MAX_TIME_PRECISION, (Node *) req->fcall);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(ret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* time_scale()
|
|
|
|
|
* Adjust time type for specified scale factor.
|
|
|
|
|
* Used by PostgreSQL type system to stuff columns.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
time_scale(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeADT time = PG_GETARG_TIMEADT(0);
|
|
|
|
|
int32 typmod = PG_GETARG_INT32(1);
|
|
|
|
|
TimeADT result;
|
|
|
|
|
|
|
|
|
|
result = time;
|
|
|
|
|
AdjustTimeForTypmod(&result, typmod);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMEADT(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* AdjustTimeForTypmod()
|
|
|
|
|
* Force the precision of the time value to a specified value.
|
|
|
|
|
* Uses *exactly* the same code as in AdjustTimestampForTypmod()
|
|
|
|
|
* but we make a separate copy because those types do not
|
|
|
|
|
* have a fundamental tie together but rather a coincidence of
|
|
|
|
|
* implementation. - thomas
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
AdjustTimeForTypmod(TimeADT *time, int32 typmod)
|
|
|
|
|
{
|
|
|
|
|
static const int64 TimeScales[MAX_TIME_PRECISION + 1] = {
|
|
|
|
|
INT64CONST(1000000),
|
|
|
|
|
INT64CONST(100000),
|
|
|
|
|
INT64CONST(10000),
|
|
|
|
|
INT64CONST(1000),
|
|
|
|
|
INT64CONST(100),
|
|
|
|
|
INT64CONST(10),
|
|
|
|
|
INT64CONST(1)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const int64 TimeOffsets[MAX_TIME_PRECISION + 1] = {
|
|
|
|
|
INT64CONST(500000),
|
|
|
|
|
INT64CONST(50000),
|
|
|
|
|
INT64CONST(5000),
|
|
|
|
|
INT64CONST(500),
|
|
|
|
|
INT64CONST(50),
|
|
|
|
|
INT64CONST(5),
|
|
|
|
|
INT64CONST(0)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (typmod >= 0 && typmod <= MAX_TIME_PRECISION)
|
|
|
|
|
{
|
|
|
|
|
if (*time >= INT64CONST(0))
|
|
|
|
|
*time = ((*time + TimeOffsets[typmod]) / TimeScales[typmod]) *
|
|
|
|
|
TimeScales[typmod];
|
|
|
|
|
else
|
|
|
|
|
*time = -((((-*time) + TimeOffsets[typmod]) / TimeScales[typmod]) *
|
|
|
|
|
TimeScales[typmod]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
time_eq(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeADT time1 = PG_GETARG_TIMEADT(0);
|
|
|
|
|
TimeADT time2 = PG_GETARG_TIMEADT(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(time1 == time2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
time_ne(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeADT time1 = PG_GETARG_TIMEADT(0);
|
|
|
|
|
TimeADT time2 = PG_GETARG_TIMEADT(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(time1 != time2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
time_lt(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeADT time1 = PG_GETARG_TIMEADT(0);
|
|
|
|
|
TimeADT time2 = PG_GETARG_TIMEADT(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(time1 < time2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
time_le(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeADT time1 = PG_GETARG_TIMEADT(0);
|
|
|
|
|
TimeADT time2 = PG_GETARG_TIMEADT(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(time1 <= time2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
time_gt(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeADT time1 = PG_GETARG_TIMEADT(0);
|
|
|
|
|
TimeADT time2 = PG_GETARG_TIMEADT(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(time1 > time2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
time_ge(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeADT time1 = PG_GETARG_TIMEADT(0);
|
|
|
|
|
TimeADT time2 = PG_GETARG_TIMEADT(1);
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(time1 >= time2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
time_cmp(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeADT time1 = PG_GETARG_TIMEADT(0);
|
|
|
|
|
TimeADT time2 = PG_GETARG_TIMEADT(1);
|
|
|
|
|
|
|
|
|
|
if (time1 < time2)
|
|
|
|
|
PG_RETURN_INT32(-1);
|
|
|
|
|
if (time1 > time2)
|
|
|
|
|
PG_RETURN_INT32(1);
|
|
|
|
|
PG_RETURN_INT32(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
time_hash(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
return hashint8(fcinfo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
time_hash_extended(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
return hashint8extended(fcinfo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
time_larger(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeADT time1 = PG_GETARG_TIMEADT(0);
|
|
|
|
|
TimeADT time2 = PG_GETARG_TIMEADT(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMEADT((time1 > time2) ? time1 : time2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
time_smaller(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeADT time1 = PG_GETARG_TIMEADT(0);
|
|
|
|
|
TimeADT time2 = PG_GETARG_TIMEADT(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMEADT((time1 < time2) ? time1 : time2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* overlaps_time() --- implements the SQL OVERLAPS operator.
|
|
|
|
|
*
|
|
|
|
|
* Algorithm is per SQL spec. This is much harder than you'd think
|
|
|
|
|
* because the spec requires us to deliver a non-null answer in some cases
|
|
|
|
|
* where some of the inputs are null.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
overlaps_time(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* The arguments are TimeADT, but we leave them as generic Datums to avoid
|
|
|
|
|
* dereferencing nulls (TimeADT is pass-by-reference!)
|
|
|
|
|
*/
|
|
|
|
|
Datum ts1 = PG_GETARG_DATUM(0);
|
|
|
|
|
Datum te1 = PG_GETARG_DATUM(1);
|
|
|
|
|
Datum ts2 = PG_GETARG_DATUM(2);
|
|
|
|
|
Datum te2 = PG_GETARG_DATUM(3);
|
|
|
|
|
bool ts1IsNull = PG_ARGISNULL(0);
|
|
|
|
|
bool te1IsNull = PG_ARGISNULL(1);
|
|
|
|
|
bool ts2IsNull = PG_ARGISNULL(2);
|
|
|
|
|
bool te2IsNull = PG_ARGISNULL(3);
|
|
|
|
|
|
|
|
|
|
#define TIMEADT_GT(t1,t2) \
|
|
|
|
|
(DatumGetTimeADT(t1) > DatumGetTimeADT(t2))
|
|
|
|
|
#define TIMEADT_LT(t1,t2) \
|
|
|
|
|
(DatumGetTimeADT(t1) < DatumGetTimeADT(t2))
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
if (ts1IsNull)
|
|
|
|
|
{
|
|
|
|
|
if (te1IsNull)
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
/* swap null for non-null */
|
|
|
|
|
ts1 = te1;
|
|
|
|
|
te1IsNull = true;
|
|
|
|
|
}
|
|
|
|
|
else if (!te1IsNull)
|
|
|
|
|
{
|
|
|
|
|
if (TIMEADT_GT(ts1, te1))
|
|
|
|
|
{
|
|
|
|
|
Datum tt = ts1;
|
|
|
|
|
|
|
|
|
|
ts1 = te1;
|
|
|
|
|
te1 = tt;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Likewise for interval 2. */
|
|
|
|
|
if (ts2IsNull)
|
|
|
|
|
{
|
|
|
|
|
if (te2IsNull)
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
/* swap null for non-null */
|
|
|
|
|
ts2 = te2;
|
|
|
|
|
te2IsNull = true;
|
|
|
|
|
}
|
|
|
|
|
else if (!te2IsNull)
|
|
|
|
|
{
|
|
|
|
|
if (TIMEADT_GT(ts2, te2))
|
|
|
|
|
{
|
|
|
|
|
Datum tt = ts2;
|
|
|
|
|
|
|
|
|
|
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 (TIMEADT_GT(ts1, ts2))
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* This case is ts1 < te2 OR te1 < te2, which may look redundant but
|
|
|
|
|
* in the presence of nulls it's not quite completely so.
|
|
|
|
|
*/
|
|
|
|
|
if (te2IsNull)
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
if (TIMEADT_LT(ts1, te2))
|
|
|
|
|
PG_RETURN_BOOL(true);
|
|
|
|
|
if (te1IsNull)
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If te1 is not null then we had ts1 <= te1 above, and we just found
|
|
|
|
|
* ts1 >= te2, hence te1 >= te2.
|
|
|
|
|
*/
|
|
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
|
}
|
|
|
|
|
else if (TIMEADT_LT(ts1, ts2))
|
|
|
|
|
{
|
|
|
|
|
/* This case is ts2 < te1 OR te2 < te1 */
|
|
|
|
|
if (te1IsNull)
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
if (TIMEADT_LT(ts2, te1))
|
|
|
|
|
PG_RETURN_BOOL(true);
|
|
|
|
|
if (te2IsNull)
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If te2 is not null then we had ts2 <= te2 above, and we just found
|
|
|
|
|
* ts2 >= te1, hence te2 >= te1.
|
|
|
|
|
*/
|
|
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
|
|
|
|
|
* rather silly way of saying "true if both are nonnull, else null".
|
|
|
|
|
*/
|
|
|
|
|
if (te1IsNull || te2IsNull)
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
PG_RETURN_BOOL(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef TIMEADT_GT
|
|
|
|
|
#undef TIMEADT_LT
|
|
|
|
|
}
|
|
|
|
|
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
/* timestamp_time()
|
|
|
|
|
* Convert timestamp to time data type.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
timestamp_time(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
|
|
|
|
|
TimeADT result;
|
|
|
|
|
struct pg_tm tt,
|
|
|
|
|
*tm = &tt;
|
|
|
|
|
fsec_t fsec;
|
|
|
|
|
|
|
|
|
|
if (TIMESTAMP_NOT_FINITE(timestamp))
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
|
|
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Could also do this with time = (timestamp / USECS_PER_DAY *
|
|
|
|
|
* USECS_PER_DAY) - timestamp;
|
|
|
|
|
*/
|
|
|
|
|
result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
|
|
|
|
|
USECS_PER_SEC) + fsec;
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMEADT(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* timestamptz_time()
|
|
|
|
|
* Convert timestamptz to time data type.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
timestamptz_time(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
|
|
|
|
|
TimeADT result;
|
|
|
|
|
struct pg_tm tt,
|
|
|
|
|
*tm = &tt;
|
|
|
|
|
int tz;
|
|
|
|
|
fsec_t fsec;
|
|
|
|
|
|
|
|
|
|
if (TIMESTAMP_NOT_FINITE(timestamp))
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
|
|
if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Could also do this with time = (timestamp / USECS_PER_DAY *
|
|
|
|
|
* USECS_PER_DAY) - timestamp;
|
|
|
|
|
*/
|
|
|
|
|
result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
|
|
|
|
|
USECS_PER_SEC) + fsec;
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMEADT(result);
|
|
|
|
|
}
|
|
|
|
|
|
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
26 years ago
|
|
|
/* datetime_timestamp()
|
|
|
|
|
* Convert date and time to timestamp data type.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
datetime_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT date = PG_GETARG_DATEADT(0);
|
|
|
|
|
TimeADT time = PG_GETARG_TIMEADT(1);
|
|
|
|
|
Timestamp result;
|
|
|
|
|
|
|
|
|
|
result = date2timestamp(date);
|
|
|
|
|
if (!TIMESTAMP_NOT_FINITE(result))
|
|
|
|
|
{
|
|
|
|
|
result += time;
|
|
|
|
|
if (!IS_VALID_TIMESTAMP(result))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMESTAMP(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* time_interval()
|
|
|
|
|
* Convert time to interval data type.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
time_interval(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeADT time = PG_GETARG_TIMEADT(0);
|
|
|
|
|
Interval *result;
|
|
|
|
|
|
|
|
|
|
result = (Interval *) palloc(sizeof(Interval));
|
|
|
|
|
|
|
|
|
|
result->time = time;
|
|
|
|
|
result->day = 0;
|
|
|
|
|
result->month = 0;
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INTERVAL_P(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* interval_time()
|
|
|
|
|
* Convert interval to time data type.
|
|
|
|
|
*
|
|
|
|
|
* This is defined as producing the fractional-day portion of the interval.
|
|
|
|
|
* Therefore, we can just ignore the months field. It is not real clear
|
|
|
|
|
* what to do with negative intervals, but we choose to subtract the floor,
|
|
|
|
|
* so that, say, '-2 hours' becomes '22:00:00'.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
interval_time(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
Interval *span = PG_GETARG_INTERVAL_P(0);
|
|
|
|
|
TimeADT result;
|
|
|
|
|
|
Support +/- infinity in the interval data type.
This adds support for infinity to the interval data type, using the
same input/output representation as the other date/time data types
that support infinity. This allows various arithmetic operations on
infinite dates, timestamps and intervals.
The new values are represented by setting all fields of the interval
to INT32/64_MIN for -infinity, and INT32/64_MAX for +infinity. This
ensures that they compare as less/greater than all other interval
values, without the need for any special-case comparison code.
Note that, since those 2 values were formerly accepted as legal finite
intervals, pg_upgrade and dump/restore from an old database will turn
them from finite to infinite intervals. That seems OK, since those
exact values should be extremely rare in practice, and they are
outside the documented range supported by the interval type, which
gives us a certain amount of leeway.
Bump catalog version.
Joseph Koshakow, Jian He, and Ashutosh Bapat, reviewed by me.
Discussion: https://postgr.es/m/CAAvxfHea4%2BsPybKK7agDYOMo9N-Z3J6ZXf3BOM79pFsFNcRjwA%40mail.gmail.com
2 years ago
|
|
|
if (INTERVAL_NOT_FINITE(span))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("cannot convert infinite interval to time")));
|
|
|
|
|
|
|
|
|
|
result = span->time % USECS_PER_DAY;
|
|
|
|
|
if (result < 0)
|
|
|
|
|
result += USECS_PER_DAY;
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMEADT(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* time_mi_time()
|
|
|
|
|
* Subtract two times to produce an interval.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
time_mi_time(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeADT time1 = PG_GETARG_TIMEADT(0);
|
|
|
|
|
TimeADT time2 = PG_GETARG_TIMEADT(1);
|
|
|
|
|
Interval *result;
|
|
|
|
|
|
|
|
|
|
result = (Interval *) palloc(sizeof(Interval));
|
|
|
|
|
|
|
|
|
|
result->month = 0;
|
|
|
|
|
result->day = 0;
|
|
|
|
|
result->time = time1 - time2;
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INTERVAL_P(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* time_pl_interval()
|
|
|
|
|
* Add interval to time.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
time_pl_interval(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeADT time = PG_GETARG_TIMEADT(0);
|
|
|
|
|
Interval *span = PG_GETARG_INTERVAL_P(1);
|
|
|
|
|
TimeADT result;
|
|
|
|
|
|
Support +/- infinity in the interval data type.
This adds support for infinity to the interval data type, using the
same input/output representation as the other date/time data types
that support infinity. This allows various arithmetic operations on
infinite dates, timestamps and intervals.
The new values are represented by setting all fields of the interval
to INT32/64_MIN for -infinity, and INT32/64_MAX for +infinity. This
ensures that they compare as less/greater than all other interval
values, without the need for any special-case comparison code.
Note that, since those 2 values were formerly accepted as legal finite
intervals, pg_upgrade and dump/restore from an old database will turn
them from finite to infinite intervals. That seems OK, since those
exact values should be extremely rare in practice, and they are
outside the documented range supported by the interval type, which
gives us a certain amount of leeway.
Bump catalog version.
Joseph Koshakow, Jian He, and Ashutosh Bapat, reviewed by me.
Discussion: https://postgr.es/m/CAAvxfHea4%2BsPybKK7agDYOMo9N-Z3J6ZXf3BOM79pFsFNcRjwA%40mail.gmail.com
2 years ago
|
|
|
if (INTERVAL_NOT_FINITE(span))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("cannot add infinite interval to time")));
|
|
|
|
|
|
|
|
|
|
result = time + span->time;
|
|
|
|
|
result -= result / USECS_PER_DAY * USECS_PER_DAY;
|
|
|
|
|
if (result < INT64CONST(0))
|
|
|
|
|
result += USECS_PER_DAY;
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMEADT(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* time_mi_interval()
|
|
|
|
|
* Subtract interval from time.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
time_mi_interval(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeADT time = PG_GETARG_TIMEADT(0);
|
|
|
|
|
Interval *span = PG_GETARG_INTERVAL_P(1);
|
|
|
|
|
TimeADT result;
|
|
|
|
|
|
Support +/- infinity in the interval data type.
This adds support for infinity to the interval data type, using the
same input/output representation as the other date/time data types
that support infinity. This allows various arithmetic operations on
infinite dates, timestamps and intervals.
The new values are represented by setting all fields of the interval
to INT32/64_MIN for -infinity, and INT32/64_MAX for +infinity. This
ensures that they compare as less/greater than all other interval
values, without the need for any special-case comparison code.
Note that, since those 2 values were formerly accepted as legal finite
intervals, pg_upgrade and dump/restore from an old database will turn
them from finite to infinite intervals. That seems OK, since those
exact values should be extremely rare in practice, and they are
outside the documented range supported by the interval type, which
gives us a certain amount of leeway.
Bump catalog version.
Joseph Koshakow, Jian He, and Ashutosh Bapat, reviewed by me.
Discussion: https://postgr.es/m/CAAvxfHea4%2BsPybKK7agDYOMo9N-Z3J6ZXf3BOM79pFsFNcRjwA%40mail.gmail.com
2 years ago
|
|
|
if (INTERVAL_NOT_FINITE(span))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("cannot subtract infinite interval from time")));
|
|
|
|
|
|
|
|
|
|
result = time - span->time;
|
|
|
|
|
result -= result / USECS_PER_DAY * USECS_PER_DAY;
|
|
|
|
|
if (result < INT64CONST(0))
|
|
|
|
|
result += USECS_PER_DAY;
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMEADT(result);
|
|
|
|
|
}
|
|
|
|
|
|
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
8 years ago
|
|
|
/*
|
|
|
|
|
* in_range support function for time.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
in_range_time_interval(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeADT val = PG_GETARG_TIMEADT(0);
|
|
|
|
|
TimeADT base = PG_GETARG_TIMEADT(1);
|
|
|
|
|
Interval *offset = PG_GETARG_INTERVAL_P(2);
|
|
|
|
|
bool sub = PG_GETARG_BOOL(3);
|
|
|
|
|
bool less = PG_GETARG_BOOL(4);
|
|
|
|
|
TimeADT sum;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Like time_pl_interval/time_mi_interval, we disregard the month and day
|
Support +/- infinity in the interval data type.
This adds support for infinity to the interval data type, using the
same input/output representation as the other date/time data types
that support infinity. This allows various arithmetic operations on
infinite dates, timestamps and intervals.
The new values are represented by setting all fields of the interval
to INT32/64_MIN for -infinity, and INT32/64_MAX for +infinity. This
ensures that they compare as less/greater than all other interval
values, without the need for any special-case comparison code.
Note that, since those 2 values were formerly accepted as legal finite
intervals, pg_upgrade and dump/restore from an old database will turn
them from finite to infinite intervals. That seems OK, since those
exact values should be extremely rare in practice, and they are
outside the documented range supported by the interval type, which
gives us a certain amount of leeway.
Bump catalog version.
Joseph Koshakow, Jian He, and Ashutosh Bapat, reviewed by me.
Discussion: https://postgr.es/m/CAAvxfHea4%2BsPybKK7agDYOMo9N-Z3J6ZXf3BOM79pFsFNcRjwA%40mail.gmail.com
2 years ago
|
|
|
* fields of the offset. So our test for negative should too. This also
|
|
|
|
|
* catches -infinity, so we only need worry about +infinity below.
|
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
8 years ago
|
|
|
*/
|
|
|
|
|
if (offset->time < 0)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(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
8 years ago
|
|
|
errmsg("invalid preceding or following size in window function")));
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We can't use time_pl_interval/time_mi_interval here, because their
|
|
|
|
|
* wraparound behavior would give wrong (or at least undesirable) answers.
|
Support +/- infinity in the interval data type.
This adds support for infinity to the interval data type, using the
same input/output representation as the other date/time data types
that support infinity. This allows various arithmetic operations on
infinite dates, timestamps and intervals.
The new values are represented by setting all fields of the interval
to INT32/64_MIN for -infinity, and INT32/64_MAX for +infinity. This
ensures that they compare as less/greater than all other interval
values, without the need for any special-case comparison code.
Note that, since those 2 values were formerly accepted as legal finite
intervals, pg_upgrade and dump/restore from an old database will turn
them from finite to infinite intervals. That seems OK, since those
exact values should be extremely rare in practice, and they are
outside the documented range supported by the interval type, which
gives us a certain amount of leeway.
Bump catalog version.
Joseph Koshakow, Jian He, and Ashutosh Bapat, reviewed by me.
Discussion: https://postgr.es/m/CAAvxfHea4%2BsPybKK7agDYOMo9N-Z3J6ZXf3BOM79pFsFNcRjwA%40mail.gmail.com
2 years ago
|
|
|
* Fortunately the equivalent non-wrapping behavior is trivial, except
|
|
|
|
|
* that adding an infinite (or very large) interval might cause integer
|
|
|
|
|
* overflow. Subtraction cannot overflow here.
|
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
8 years ago
|
|
|
*/
|
|
|
|
|
if (sub)
|
|
|
|
|
sum = base - offset->time;
|
Support +/- infinity in the interval data type.
This adds support for infinity to the interval data type, using the
same input/output representation as the other date/time data types
that support infinity. This allows various arithmetic operations on
infinite dates, timestamps and intervals.
The new values are represented by setting all fields of the interval
to INT32/64_MIN for -infinity, and INT32/64_MAX for +infinity. This
ensures that they compare as less/greater than all other interval
values, without the need for any special-case comparison code.
Note that, since those 2 values were formerly accepted as legal finite
intervals, pg_upgrade and dump/restore from an old database will turn
them from finite to infinite intervals. That seems OK, since those
exact values should be extremely rare in practice, and they are
outside the documented range supported by the interval type, which
gives us a certain amount of leeway.
Bump catalog version.
Joseph Koshakow, Jian He, and Ashutosh Bapat, reviewed by me.
Discussion: https://postgr.es/m/CAAvxfHea4%2BsPybKK7agDYOMo9N-Z3J6ZXf3BOM79pFsFNcRjwA%40mail.gmail.com
2 years ago
|
|
|
else if (pg_add_s64_overflow(base, offset->time, &sum))
|
|
|
|
|
PG_RETURN_BOOL(less);
|
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
8 years ago
|
|
|
|
|
|
|
|
if (less)
|
|
|
|
|
PG_RETURN_BOOL(val <= sum);
|
|
|
|
|
else
|
|
|
|
|
PG_RETURN_BOOL(val >= sum);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
/* time_part() and extract_time()
|
|
|
|
|
* Extract specified field from time type.
|
|
|
|
|
*/
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
static Datum
|
|
|
|
|
time_part_common(PG_FUNCTION_ARGS, bool retnumeric)
|
|
|
|
|
{
|
|
|
|
|
text *units = PG_GETARG_TEXT_PP(0);
|
|
|
|
|
TimeADT time = PG_GETARG_TIMEADT(1);
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
int64 intresult;
|
|
|
|
|
int type,
|
|
|
|
|
val;
|
|
|
|
|
char *lowunits;
|
|
|
|
|
|
|
|
|
|
lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
|
|
|
|
|
VARSIZE_ANY_EXHDR(units),
|
|
|
|
|
false);
|
|
|
|
|
|
|
|
|
|
type = DecodeUnits(0, lowunits, &val);
|
|
|
|
|
if (type == UNKNOWN_FIELD)
|
|
|
|
|
type = DecodeSpecial(0, lowunits, &val);
|
|
|
|
|
|
|
|
|
|
if (type == UNITS)
|
|
|
|
|
{
|
|
|
|
|
fsec_t fsec;
|
|
|
|
|
struct pg_tm tt,
|
|
|
|
|
*tm = &tt;
|
|
|
|
|
|
|
|
|
|
time2tm(time, tm, &fsec);
|
|
|
|
|
|
|
|
|
|
switch (val)
|
|
|
|
|
{
|
|
|
|
|
case DTK_MICROSEC:
|
|
|
|
|
intresult = tm->tm_sec * INT64CONST(1000000) + fsec;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_MILLISEC:
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
if (retnumeric)
|
|
|
|
|
/*---
|
|
|
|
|
* tm->tm_sec * 1000 + fsec / 1000
|
|
|
|
|
* = (tm->tm_sec * 1'000'000 + fsec) / 1000
|
|
|
|
|
*/
|
|
|
|
|
PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 3));
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
else
|
|
|
|
|
PG_RETURN_FLOAT8(tm->tm_sec * 1000.0 + fsec / 1000.0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_SECOND:
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
if (retnumeric)
|
|
|
|
|
/*---
|
|
|
|
|
* tm->tm_sec + fsec / 1'000'000
|
|
|
|
|
* = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
|
|
|
|
|
*/
|
|
|
|
|
PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 6));
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
else
|
|
|
|
|
PG_RETURN_FLOAT8(tm->tm_sec + fsec / 1000000.0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_MINUTE:
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
intresult = tm->tm_min;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_HOUR:
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
intresult = tm->tm_hour;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_TZ:
|
|
|
|
|
case DTK_TZ_MINUTE:
|
|
|
|
|
case DTK_TZ_HOUR:
|
|
|
|
|
case DTK_DAY:
|
|
|
|
|
case DTK_MONTH:
|
|
|
|
|
case DTK_QUARTER:
|
|
|
|
|
case DTK_YEAR:
|
|
|
|
|
case DTK_DECADE:
|
|
|
|
|
case DTK_CENTURY:
|
|
|
|
|
case DTK_MILLENNIUM:
|
|
|
|
|
case DTK_ISOYEAR:
|
|
|
|
|
default:
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
|
errmsg("unit \"%s\" not supported for type %s",
|
|
|
|
|
lowunits, format_type_be(TIMEOID))));
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
intresult = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (type == RESERV && val == DTK_EPOCH)
|
|
|
|
|
{
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
if (retnumeric)
|
|
|
|
|
PG_RETURN_NUMERIC(int64_div_fast_to_numeric(time, 6));
|
|
|
|
|
else
|
|
|
|
|
PG_RETURN_FLOAT8(time / 1000000.0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
|
errmsg("unit \"%s\" not recognized for type %s",
|
|
|
|
|
lowunits, format_type_be(TIMEOID))));
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
intresult = 0;
|
|
|
|
|
}
|
|
|
|
|
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
if (retnumeric)
|
|
|
|
|
PG_RETURN_NUMERIC(int64_to_numeric(intresult));
|
|
|
|
|
else
|
|
|
|
|
PG_RETURN_FLOAT8(intresult);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
time_part(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
return time_part_common(fcinfo, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
extract_time(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
return time_part_common(fcinfo, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
|
* Time With Time Zone ADT
|
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
/* tm2timetz()
|
|
|
|
|
* Convert a tm structure to a time data type.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
tm2timetz(struct pg_tm *tm, fsec_t fsec, int tz, TimeTzADT *result)
|
|
|
|
|
{
|
|
|
|
|
result->time = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
|
|
|
|
|
USECS_PER_SEC) + fsec;
|
|
|
|
|
result->zone = tz;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timetz_in(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
char *str = PG_GETARG_CSTRING(0);
|
|
|
|
|
#ifdef NOT_USED
|
|
|
|
|
Oid typelem = PG_GETARG_OID(1);
|
|
|
|
|
#endif
|
|
|
|
|
int32 typmod = PG_GETARG_INT32(2);
|
|
|
|
|
Node *escontext = fcinfo->context;
|
|
|
|
|
TimeTzADT *result;
|
|
|
|
|
fsec_t fsec;
|
|
|
|
|
struct pg_tm tt,
|
|
|
|
|
*tm = &tt;
|
|
|
|
|
int tz;
|
|
|
|
|
int nf;
|
|
|
|
|
int dterr;
|
|
|
|
|
char workbuf[MAXDATELEN + 1];
|
|
|
|
|
char *field[MAXDATEFIELDS];
|
|
|
|
|
int dtype;
|
|
|
|
|
int ftype[MAXDATEFIELDS];
|
|
|
|
|
DateTimeErrorExtra extra;
|
|
|
|
|
|
|
|
|
|
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
|
|
|
|
field, ftype, MAXDATEFIELDS, &nf);
|
|
|
|
|
if (dterr == 0)
|
|
|
|
|
dterr = DecodeTimeOnly(field, ftype, nf,
|
|
|
|
|
&dtype, tm, &fsec, &tz, &extra);
|
|
|
|
|
if (dterr != 0)
|
|
|
|
|
{
|
|
|
|
|
DateTimeParseError(dterr, &extra, str, "time with time zone",
|
|
|
|
|
escontext);
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
|
|
|
|
|
tm2timetz(tm, fsec, tz, result);
|
|
|
|
|
AdjustTimeForTypmod(&(result->time), typmod);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMETZADT_P(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timetz_out(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
|
|
|
|
|
char *result;
|
|
|
|
|
struct pg_tm tt,
|
|
|
|
|
*tm = &tt;
|
|
|
|
|
fsec_t fsec;
|
|
|
|
|
int tz;
|
|
|
|
|
char buf[MAXDATELEN + 1];
|
|
|
|
|
|
|
|
|
|
timetz2tm(time, tm, &fsec, &tz);
|
|
|
|
|
EncodeTimeOnly(tm, fsec, true, tz, DateStyle, buf);
|
|
|
|
|
|
|
|
|
|
result = pstrdup(buf);
|
|
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* timetz_recv - converts external binary format to timetz
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
timetz_recv(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
|
|
|
|
|
|
|
|
|
#ifdef NOT_USED
|
|
|
|
|
Oid typelem = PG_GETARG_OID(1);
|
|
|
|
|
#endif
|
|
|
|
|
int32 typmod = PG_GETARG_INT32(2);
|
|
|
|
|
TimeTzADT *result;
|
|
|
|
|
|
|
|
|
|
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
|
|
|
|
|
|
|
|
|
|
result->time = pq_getmsgint64(buf);
|
|
|
|
|
|
|
|
|
|
if (result->time < INT64CONST(0) || result->time > USECS_PER_DAY)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("time out of range")));
|
|
|
|
|
|
|
|
|
|
result->zone = pq_getmsgint(buf, sizeof(result->zone));
|
|
|
|
|
|
|
|
|
|
/* Check for sane GMT displacement; see notes in datatype/timestamp.h */
|
|
|
|
|
if (result->zone <= -TZDISP_LIMIT || result->zone >= TZDISP_LIMIT)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE),
|
|
|
|
|
errmsg("time zone displacement out of range")));
|
|
|
|
|
|
|
|
|
|
AdjustTimeForTypmod(&(result->time), typmod);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMETZADT_P(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* timetz_send - converts timetz to binary format
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
timetz_send(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
|
|
|
|
|
StringInfoData buf;
|
|
|
|
|
|
|
|
|
|
pq_begintypsend(&buf);
|
|
|
|
|
pq_sendint64(&buf, time->time);
|
|
|
|
|
pq_sendint32(&buf, time->zone);
|
|
|
|
|
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timetztypmodin(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT32(anytime_typmodin(true, ta));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timetztypmodout(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int32 typmod = PG_GETARG_INT32(0);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_CSTRING(anytime_typmodout(true, typmod));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* timetz2tm()
|
|
|
|
|
* Convert TIME WITH TIME ZONE data type to POSIX time structure.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
timetz2tm(TimeTzADT *time, struct pg_tm *tm, fsec_t *fsec, int *tzp)
|
|
|
|
|
{
|
|
|
|
|
TimeOffset trem = time->time;
|
|
|
|
|
|
|
|
|
|
tm->tm_hour = trem / USECS_PER_HOUR;
|
|
|
|
|
trem -= tm->tm_hour * USECS_PER_HOUR;
|
|
|
|
|
tm->tm_min = trem / USECS_PER_MINUTE;
|
|
|
|
|
trem -= tm->tm_min * USECS_PER_MINUTE;
|
|
|
|
|
tm->tm_sec = trem / USECS_PER_SEC;
|
|
|
|
|
*fsec = trem - tm->tm_sec * USECS_PER_SEC;
|
|
|
|
|
|
|
|
|
|
if (tzp != NULL)
|
|
|
|
|
*tzp = time->zone;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* timetz_scale()
|
|
|
|
|
* Adjust time type for specified scale factor.
|
|
|
|
|
* Used by PostgreSQL type system to stuff columns.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
timetz_scale(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
|
|
|
|
|
int32 typmod = PG_GETARG_INT32(1);
|
|
|
|
|
TimeTzADT *result;
|
|
|
|
|
|
|
|
|
|
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
|
|
|
|
|
|
|
|
|
|
result->time = time->time;
|
|
|
|
|
result->zone = time->zone;
|
|
|
|
|
|
|
|
|
|
AdjustTimeForTypmod(&(result->time), typmod);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMETZADT_P(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
timetz_cmp_internal(TimeTzADT *time1, TimeTzADT *time2)
|
|
|
|
|
{
|
|
|
|
|
TimeOffset t1,
|
|
|
|
|
t2;
|
|
|
|
|
|
|
|
|
|
/* Primary sort is by true (GMT-equivalent) time */
|
|
|
|
|
t1 = time1->time + (time1->zone * USECS_PER_SEC);
|
|
|
|
|
t2 = time2->time + (time2->zone * USECS_PER_SEC);
|
|
|
|
|
|
|
|
|
|
if (t1 > t2)
|
|
|
|
|
return 1;
|
|
|
|
|
if (t1 < t2)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If same GMT time, sort by timezone; we only want to say that two
|
|
|
|
|
* timetz's are equal if both the time and zone parts are equal.
|
|
|
|
|
*/
|
|
|
|
|
if (time1->zone > time2->zone)
|
|
|
|
|
return 1;
|
|
|
|
|
if (time1->zone < time2->zone)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timetz_eq(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
|
|
|
|
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timetz_ne(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
|
|
|
|
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) != 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timetz_lt(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
|
|
|
|
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) < 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timetz_le(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
|
|
|
|
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) <= 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timetz_gt(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
|
|
|
|
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) > 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timetz_ge(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
|
|
|
|
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) >= 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timetz_cmp(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
|
|
|
|
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT32(timetz_cmp_internal(time1, time2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timetz_hash(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeTzADT *key = PG_GETARG_TIMETZADT_P(0);
|
|
|
|
|
uint32 thash;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* To avoid any problems with padding bytes in the struct, we figure the
|
|
|
|
|
* field hashes separately and XOR them.
|
|
|
|
|
*/
|
|
|
|
|
thash = DatumGetUInt32(DirectFunctionCall1(hashint8,
|
|
|
|
|
Int64GetDatumFast(key->time)));
|
|
|
|
|
thash ^= DatumGetUInt32(hash_uint32(key->zone));
|
|
|
|
|
PG_RETURN_UINT32(thash);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timetz_hash_extended(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeTzADT *key = PG_GETARG_TIMETZADT_P(0);
|
|
|
|
|
Datum seed = PG_GETARG_DATUM(1);
|
|
|
|
|
uint64 thash;
|
|
|
|
|
|
|
|
|
|
/* Same approach as timetz_hash */
|
|
|
|
|
thash = DatumGetUInt64(DirectFunctionCall2(hashint8extended,
|
|
|
|
|
Int64GetDatumFast(key->time),
|
|
|
|
|
seed));
|
|
|
|
|
thash ^= DatumGetUInt64(hash_uint32_extended(key->zone,
|
|
|
|
|
DatumGetInt64(seed)));
|
|
|
|
|
PG_RETURN_UINT64(thash);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timetz_larger(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
|
|
|
|
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
|
|
|
|
|
TimeTzADT *result;
|
|
|
|
|
|
|
|
|
|
if (timetz_cmp_internal(time1, time2) > 0)
|
|
|
|
|
result = time1;
|
|
|
|
|
else
|
|
|
|
|
result = time2;
|
|
|
|
|
PG_RETURN_TIMETZADT_P(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timetz_smaller(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
|
|
|
|
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
|
|
|
|
|
TimeTzADT *result;
|
|
|
|
|
|
|
|
|
|
if (timetz_cmp_internal(time1, time2) < 0)
|
|
|
|
|
result = time1;
|
|
|
|
|
else
|
|
|
|
|
result = time2;
|
|
|
|
|
PG_RETURN_TIMETZADT_P(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* timetz_pl_interval()
|
|
|
|
|
* Add interval to timetz.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
timetz_pl_interval(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
|
|
|
|
|
Interval *span = PG_GETARG_INTERVAL_P(1);
|
|
|
|
|
TimeTzADT *result;
|
|
|
|
|
|
Support +/- infinity in the interval data type.
This adds support for infinity to the interval data type, using the
same input/output representation as the other date/time data types
that support infinity. This allows various arithmetic operations on
infinite dates, timestamps and intervals.
The new values are represented by setting all fields of the interval
to INT32/64_MIN for -infinity, and INT32/64_MAX for +infinity. This
ensures that they compare as less/greater than all other interval
values, without the need for any special-case comparison code.
Note that, since those 2 values were formerly accepted as legal finite
intervals, pg_upgrade and dump/restore from an old database will turn
them from finite to infinite intervals. That seems OK, since those
exact values should be extremely rare in practice, and they are
outside the documented range supported by the interval type, which
gives us a certain amount of leeway.
Bump catalog version.
Joseph Koshakow, Jian He, and Ashutosh Bapat, reviewed by me.
Discussion: https://postgr.es/m/CAAvxfHea4%2BsPybKK7agDYOMo9N-Z3J6ZXf3BOM79pFsFNcRjwA%40mail.gmail.com
2 years ago
|
|
|
if (INTERVAL_NOT_FINITE(span))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("cannot add infinite interval to time")));
|
|
|
|
|
|
|
|
|
|
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
|
|
|
|
|
|
|
|
|
|
result->time = time->time + span->time;
|
|
|
|
|
result->time -= result->time / USECS_PER_DAY * USECS_PER_DAY;
|
|
|
|
|
if (result->time < INT64CONST(0))
|
|
|
|
|
result->time += USECS_PER_DAY;
|
|
|
|
|
|
|
|
|
|
result->zone = time->zone;
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMETZADT_P(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* timetz_mi_interval()
|
|
|
|
|
* Subtract interval from timetz.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
timetz_mi_interval(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
|
|
|
|
|
Interval *span = PG_GETARG_INTERVAL_P(1);
|
|
|
|
|
TimeTzADT *result;
|
|
|
|
|
|
Support +/- infinity in the interval data type.
This adds support for infinity to the interval data type, using the
same input/output representation as the other date/time data types
that support infinity. This allows various arithmetic operations on
infinite dates, timestamps and intervals.
The new values are represented by setting all fields of the interval
to INT32/64_MIN for -infinity, and INT32/64_MAX for +infinity. This
ensures that they compare as less/greater than all other interval
values, without the need for any special-case comparison code.
Note that, since those 2 values were formerly accepted as legal finite
intervals, pg_upgrade and dump/restore from an old database will turn
them from finite to infinite intervals. That seems OK, since those
exact values should be extremely rare in practice, and they are
outside the documented range supported by the interval type, which
gives us a certain amount of leeway.
Bump catalog version.
Joseph Koshakow, Jian He, and Ashutosh Bapat, reviewed by me.
Discussion: https://postgr.es/m/CAAvxfHea4%2BsPybKK7agDYOMo9N-Z3J6ZXf3BOM79pFsFNcRjwA%40mail.gmail.com
2 years ago
|
|
|
if (INTERVAL_NOT_FINITE(span))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("cannot subtract infinite interval from time")));
|
|
|
|
|
|
|
|
|
|
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
|
|
|
|
|
|
|
|
|
|
result->time = time->time - span->time;
|
|
|
|
|
result->time -= result->time / USECS_PER_DAY * USECS_PER_DAY;
|
|
|
|
|
if (result->time < INT64CONST(0))
|
|
|
|
|
result->time += USECS_PER_DAY;
|
|
|
|
|
|
|
|
|
|
result->zone = time->zone;
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMETZADT_P(result);
|
|
|
|
|
}
|
|
|
|
|
|
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
8 years ago
|
|
|
/*
|
|
|
|
|
* in_range support function for timetz.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
in_range_timetz_interval(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeTzADT *val = PG_GETARG_TIMETZADT_P(0);
|
|
|
|
|
TimeTzADT *base = PG_GETARG_TIMETZADT_P(1);
|
|
|
|
|
Interval *offset = PG_GETARG_INTERVAL_P(2);
|
|
|
|
|
bool sub = PG_GETARG_BOOL(3);
|
|
|
|
|
bool less = PG_GETARG_BOOL(4);
|
|
|
|
|
TimeTzADT sum;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Like timetz_pl_interval/timetz_mi_interval, we disregard the month and
|
Support +/- infinity in the interval data type.
This adds support for infinity to the interval data type, using the
same input/output representation as the other date/time data types
that support infinity. This allows various arithmetic operations on
infinite dates, timestamps and intervals.
The new values are represented by setting all fields of the interval
to INT32/64_MIN for -infinity, and INT32/64_MAX for +infinity. This
ensures that they compare as less/greater than all other interval
values, without the need for any special-case comparison code.
Note that, since those 2 values were formerly accepted as legal finite
intervals, pg_upgrade and dump/restore from an old database will turn
them from finite to infinite intervals. That seems OK, since those
exact values should be extremely rare in practice, and they are
outside the documented range supported by the interval type, which
gives us a certain amount of leeway.
Bump catalog version.
Joseph Koshakow, Jian He, and Ashutosh Bapat, reviewed by me.
Discussion: https://postgr.es/m/CAAvxfHea4%2BsPybKK7agDYOMo9N-Z3J6ZXf3BOM79pFsFNcRjwA%40mail.gmail.com
2 years ago
|
|
|
* day fields of the offset. So our test for negative should too. This
|
|
|
|
|
* also catches -infinity, so we only need worry about +infinity below.
|
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
8 years ago
|
|
|
*/
|
|
|
|
|
if (offset->time < 0)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(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
8 years ago
|
|
|
errmsg("invalid preceding or following size in window function")));
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We can't use timetz_pl_interval/timetz_mi_interval here, because their
|
|
|
|
|
* wraparound behavior would give wrong (or at least undesirable) answers.
|
Support +/- infinity in the interval data type.
This adds support for infinity to the interval data type, using the
same input/output representation as the other date/time data types
that support infinity. This allows various arithmetic operations on
infinite dates, timestamps and intervals.
The new values are represented by setting all fields of the interval
to INT32/64_MIN for -infinity, and INT32/64_MAX for +infinity. This
ensures that they compare as less/greater than all other interval
values, without the need for any special-case comparison code.
Note that, since those 2 values were formerly accepted as legal finite
intervals, pg_upgrade and dump/restore from an old database will turn
them from finite to infinite intervals. That seems OK, since those
exact values should be extremely rare in practice, and they are
outside the documented range supported by the interval type, which
gives us a certain amount of leeway.
Bump catalog version.
Joseph Koshakow, Jian He, and Ashutosh Bapat, reviewed by me.
Discussion: https://postgr.es/m/CAAvxfHea4%2BsPybKK7agDYOMo9N-Z3J6ZXf3BOM79pFsFNcRjwA%40mail.gmail.com
2 years ago
|
|
|
* Fortunately the equivalent non-wrapping behavior is trivial, except
|
|
|
|
|
* that adding an infinite (or very large) interval might cause integer
|
|
|
|
|
* overflow. Subtraction cannot overflow here.
|
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
8 years ago
|
|
|
*/
|
|
|
|
|
if (sub)
|
|
|
|
|
sum.time = base->time - offset->time;
|
Support +/- infinity in the interval data type.
This adds support for infinity to the interval data type, using the
same input/output representation as the other date/time data types
that support infinity. This allows various arithmetic operations on
infinite dates, timestamps and intervals.
The new values are represented by setting all fields of the interval
to INT32/64_MIN for -infinity, and INT32/64_MAX for +infinity. This
ensures that they compare as less/greater than all other interval
values, without the need for any special-case comparison code.
Note that, since those 2 values were formerly accepted as legal finite
intervals, pg_upgrade and dump/restore from an old database will turn
them from finite to infinite intervals. That seems OK, since those
exact values should be extremely rare in practice, and they are
outside the documented range supported by the interval type, which
gives us a certain amount of leeway.
Bump catalog version.
Joseph Koshakow, Jian He, and Ashutosh Bapat, reviewed by me.
Discussion: https://postgr.es/m/CAAvxfHea4%2BsPybKK7agDYOMo9N-Z3J6ZXf3BOM79pFsFNcRjwA%40mail.gmail.com
2 years ago
|
|
|
else if (pg_add_s64_overflow(base->time, offset->time, &sum.time))
|
|
|
|
|
PG_RETURN_BOOL(less);
|
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
8 years ago
|
|
|
sum.zone = base->zone;
|
|
|
|
|
|
|
|
|
|
if (less)
|
|
|
|
|
PG_RETURN_BOOL(timetz_cmp_internal(val, &sum) <= 0);
|
|
|
|
|
else
|
|
|
|
|
PG_RETURN_BOOL(timetz_cmp_internal(val, &sum) >= 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* overlaps_timetz() --- implements the SQL OVERLAPS operator.
|
|
|
|
|
*
|
|
|
|
|
* Algorithm is per SQL spec. This is much harder than you'd think
|
|
|
|
|
* because the spec requires us to deliver a non-null answer in some cases
|
|
|
|
|
* where some of the inputs are null.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
overlaps_timetz(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* The arguments are TimeTzADT *, but we leave them as generic Datums for
|
|
|
|
|
* convenience of notation --- and to avoid dereferencing nulls.
|
|
|
|
|
*/
|
|
|
|
|
Datum ts1 = PG_GETARG_DATUM(0);
|
|
|
|
|
Datum te1 = PG_GETARG_DATUM(1);
|
|
|
|
|
Datum ts2 = PG_GETARG_DATUM(2);
|
|
|
|
|
Datum te2 = PG_GETARG_DATUM(3);
|
|
|
|
|
bool ts1IsNull = PG_ARGISNULL(0);
|
|
|
|
|
bool te1IsNull = PG_ARGISNULL(1);
|
|
|
|
|
bool ts2IsNull = PG_ARGISNULL(2);
|
|
|
|
|
bool te2IsNull = PG_ARGISNULL(3);
|
|
|
|
|
|
|
|
|
|
#define TIMETZ_GT(t1,t2) \
|
|
|
|
|
DatumGetBool(DirectFunctionCall2(timetz_gt,t1,t2))
|
|
|
|
|
#define TIMETZ_LT(t1,t2) \
|
|
|
|
|
DatumGetBool(DirectFunctionCall2(timetz_lt,t1,t2))
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
if (ts1IsNull)
|
|
|
|
|
{
|
|
|
|
|
if (te1IsNull)
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
/* swap null for non-null */
|
|
|
|
|
ts1 = te1;
|
|
|
|
|
te1IsNull = true;
|
|
|
|
|
}
|
|
|
|
|
else if (!te1IsNull)
|
|
|
|
|
{
|
|
|
|
|
if (TIMETZ_GT(ts1, te1))
|
|
|
|
|
{
|
|
|
|
|
Datum tt = ts1;
|
|
|
|
|
|
|
|
|
|
ts1 = te1;
|
|
|
|
|
te1 = tt;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Likewise for interval 2. */
|
|
|
|
|
if (ts2IsNull)
|
|
|
|
|
{
|
|
|
|
|
if (te2IsNull)
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
/* swap null for non-null */
|
|
|
|
|
ts2 = te2;
|
|
|
|
|
te2IsNull = true;
|
|
|
|
|
}
|
|
|
|
|
else if (!te2IsNull)
|
|
|
|
|
{
|
|
|
|
|
if (TIMETZ_GT(ts2, te2))
|
|
|
|
|
{
|
|
|
|
|
Datum tt = ts2;
|
|
|
|
|
|
|
|
|
|
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 (TIMETZ_GT(ts1, ts2))
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* This case is ts1 < te2 OR te1 < te2, which may look redundant but
|
|
|
|
|
* in the presence of nulls it's not quite completely so.
|
|
|
|
|
*/
|
|
|
|
|
if (te2IsNull)
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
if (TIMETZ_LT(ts1, te2))
|
|
|
|
|
PG_RETURN_BOOL(true);
|
|
|
|
|
if (te1IsNull)
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If te1 is not null then we had ts1 <= te1 above, and we just found
|
|
|
|
|
* ts1 >= te2, hence te1 >= te2.
|
|
|
|
|
*/
|
|
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
|
}
|
|
|
|
|
else if (TIMETZ_LT(ts1, ts2))
|
|
|
|
|
{
|
|
|
|
|
/* This case is ts2 < te1 OR te2 < te1 */
|
|
|
|
|
if (te1IsNull)
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
if (TIMETZ_LT(ts2, te1))
|
|
|
|
|
PG_RETURN_BOOL(true);
|
|
|
|
|
if (te2IsNull)
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If te2 is not null then we had ts2 <= te2 above, and we just found
|
|
|
|
|
* ts2 >= te1, hence te2 >= te1.
|
|
|
|
|
*/
|
|
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
|
|
|
|
|
* rather silly way of saying "true if both are nonnull, else null".
|
|
|
|
|
*/
|
|
|
|
|
if (te1IsNull || te2IsNull)
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
PG_RETURN_BOOL(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef TIMETZ_GT
|
|
|
|
|
#undef TIMETZ_LT
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timetz_time(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeTzADT *timetz = PG_GETARG_TIMETZADT_P(0);
|
|
|
|
|
TimeADT result;
|
|
|
|
|
|
|
|
|
|
/* swallow the time zone and just return the time */
|
|
|
|
|
result = timetz->time;
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMEADT(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
time_timetz(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimeADT time = PG_GETARG_TIMEADT(0);
|
|
|
|
|
TimeTzADT *result;
|
|
|
|
|
struct pg_tm tt,
|
|
|
|
|
*tm = &tt;
|
|
|
|
|
fsec_t fsec;
|
|
|
|
|
int tz;
|
|
|
|
|
|
|
|
|
|
GetCurrentDateTime(tm);
|
|
|
|
|
time2tm(time, tm, &fsec);
|
|
|
|
|
tz = DetermineTimeZoneOffset(tm, session_timezone);
|
|
|
|
|
|
|
|
|
|
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
|
|
|
|
|
|
|
|
|
|
result->time = time;
|
|
|
|
|
result->zone = tz;
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMETZADT_P(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* timestamptz_timetz()
|
|
|
|
|
* Convert timestamp to timetz data type.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
timestamptz_timetz(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
|
|
|
|
|
TimeTzADT *result;
|
|
|
|
|
struct pg_tm tt,
|
|
|
|
|
*tm = &tt;
|
|
|
|
|
int tz;
|
|
|
|
|
fsec_t fsec;
|
|
|
|
|
|
|
|
|
|
if (TIMESTAMP_NOT_FINITE(timestamp))
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
|
|
if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
|
|
|
|
|
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
|
|
|
|
|
|
|
|
|
|
tm2timetz(tm, fsec, tz, result);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMETZADT_P(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* datetimetz_timestamptz()
|
|
|
|
|
* Convert date and timetz to timestamp with time zone data type.
|
|
|
|
|
* Timestamp is stored in GMT, so add the time zone
|
|
|
|
|
* stored with the timetz to the result.
|
|
|
|
|
* - thomas 2000-03-10
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
datetimetz_timestamptz(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
DateADT date = PG_GETARG_DATEADT(0);
|
|
|
|
|
TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
|
|
|
|
|
TimestampTz result;
|
|
|
|
|
|
|
|
|
|
if (DATE_IS_NOBEGIN(date))
|
|
|
|
|
TIMESTAMP_NOBEGIN(result);
|
|
|
|
|
else if (DATE_IS_NOEND(date))
|
|
|
|
|
TIMESTAMP_NOEND(result);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Date's range is wider than timestamp's, so check for boundaries.
|
|
|
|
|
* Since dates have the same minimum values as timestamps, only upper
|
|
|
|
|
* boundary need be checked for overflow.
|
|
|
|
|
*/
|
|
|
|
|
if (date >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("date out of range for timestamp")));
|
|
|
|
|
result = date * USECS_PER_DAY + time->time + time->zone * USECS_PER_SEC;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Since it is possible to go beyond allowed timestamptz range because
|
|
|
|
|
* of time zone, check for allowed timestamp range after adding tz.
|
|
|
|
|
*/
|
|
|
|
|
if (!IS_VALID_TIMESTAMP(result))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("date out of range for timestamp")));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMESTAMP(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
/* timetz_part() and extract_timetz()
|
|
|
|
|
* Extract specified field from time type.
|
|
|
|
|
*/
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
static Datum
|
|
|
|
|
timetz_part_common(PG_FUNCTION_ARGS, bool retnumeric)
|
|
|
|
|
{
|
|
|
|
|
text *units = PG_GETARG_TEXT_PP(0);
|
|
|
|
|
TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
int64 intresult;
|
|
|
|
|
int type,
|
|
|
|
|
val;
|
|
|
|
|
char *lowunits;
|
|
|
|
|
|
|
|
|
|
lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
|
|
|
|
|
VARSIZE_ANY_EXHDR(units),
|
|
|
|
|
false);
|
|
|
|
|
|
|
|
|
|
type = DecodeUnits(0, lowunits, &val);
|
|
|
|
|
if (type == UNKNOWN_FIELD)
|
|
|
|
|
type = DecodeSpecial(0, lowunits, &val);
|
|
|
|
|
|
|
|
|
|
if (type == UNITS)
|
|
|
|
|
{
|
|
|
|
|
int tz;
|
|
|
|
|
fsec_t fsec;
|
|
|
|
|
struct pg_tm tt,
|
|
|
|
|
*tm = &tt;
|
|
|
|
|
|
|
|
|
|
timetz2tm(time, tm, &fsec, &tz);
|
|
|
|
|
|
|
|
|
|
switch (val)
|
|
|
|
|
{
|
|
|
|
|
case DTK_TZ:
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
intresult = -tz;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_TZ_MINUTE:
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
intresult = (-tz / SECS_PER_MINUTE) % MINS_PER_HOUR;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_TZ_HOUR:
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
intresult = -tz / SECS_PER_HOUR;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_MICROSEC:
|
|
|
|
|
intresult = tm->tm_sec * INT64CONST(1000000) + fsec;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_MILLISEC:
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
if (retnumeric)
|
|
|
|
|
/*---
|
|
|
|
|
* tm->tm_sec * 1000 + fsec / 1000
|
|
|
|
|
* = (tm->tm_sec * 1'000'000 + fsec) / 1000
|
|
|
|
|
*/
|
|
|
|
|
PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 3));
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
else
|
|
|
|
|
PG_RETURN_FLOAT8(tm->tm_sec * 1000.0 + fsec / 1000.0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_SECOND:
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
if (retnumeric)
|
|
|
|
|
/*---
|
|
|
|
|
* tm->tm_sec + fsec / 1'000'000
|
|
|
|
|
* = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
|
|
|
|
|
*/
|
|
|
|
|
PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 6));
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
else
|
|
|
|
|
PG_RETURN_FLOAT8(tm->tm_sec + fsec / 1000000.0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_MINUTE:
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
intresult = tm->tm_min;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_HOUR:
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
intresult = tm->tm_hour;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DTK_DAY:
|
|
|
|
|
case DTK_MONTH:
|
|
|
|
|
case DTK_QUARTER:
|
|
|
|
|
case DTK_YEAR:
|
|
|
|
|
case DTK_DECADE:
|
|
|
|
|
case DTK_CENTURY:
|
|
|
|
|
case DTK_MILLENNIUM:
|
|
|
|
|
default:
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
|
errmsg("unit \"%s\" not supported for type %s",
|
|
|
|
|
lowunits, format_type_be(TIMETZOID))));
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
intresult = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (type == RESERV && val == DTK_EPOCH)
|
|
|
|
|
{
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
if (retnumeric)
|
|
|
|
|
/*---
|
|
|
|
|
* time->time / 1'000'000 + time->zone
|
|
|
|
|
* = (time->time + time->zone * 1'000'000) / 1'000'000
|
|
|
|
|
*/
|
|
|
|
|
PG_RETURN_NUMERIC(int64_div_fast_to_numeric(time->time + time->zone * INT64CONST(1000000), 6));
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
else
|
|
|
|
|
PG_RETURN_FLOAT8(time->time / 1000000.0 + time->zone);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
|
errmsg("unit \"%s\" not recognized for type %s",
|
|
|
|
|
lowunits, format_type_be(TIMETZOID))));
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
intresult = 0;
|
|
|
|
|
}
|
|
|
|
|
|
Change return type of EXTRACT to numeric
The previous implementation of EXTRACT mapped internally to
date_part(), which returned type double precision (since it was
implemented long before the numeric type existed). This can lead to
imprecise output in some cases, so returning numeric would be
preferrable. Changing the return type of an existing function is a
bit risky, so instead we do the following: We implement a new set of
functions, which are now called "extract", in parallel to the existing
date_part functions. They work the same way internally but use
numeric instead of float8. The EXTRACT construct is now mapped by the
parser to these new extract functions. That way, dumps of views
etc. from old versions (which would use date_part) continue to work
unchanged, but new uses will map to the new extract functions.
Additionally, the reverse compilation of EXTRACT now reproduces the
original syntax, using the new mechanism introduced in
40c24bfef92530bd846e111c1742c2a54441c62c.
The following minor changes of behavior result from the new
implementation:
- The column name from an isolated EXTRACT call is now "extract"
instead of "date_part".
- Extract from date now rejects inappropriate field names such as
HOUR. It was previously mapped internally to extract from
timestamp, so it would silently accept everything appropriate for
timestamp.
- Return values when extracting fields with possibly fractional
values, such as second and epoch, now have the full scale that the
value has internally (so, for example, '1.000000' instead of just
'1').
Reported-by: Petr Fedorov <petr.fedorov@phystech.edu>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
5 years ago
|
|
|
if (retnumeric)
|
|
|
|
|
PG_RETURN_NUMERIC(int64_to_numeric(intresult));
|
|
|
|
|
else
|
|
|
|
|
PG_RETURN_FLOAT8(intresult);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
timetz_part(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
return timetz_part_common(fcinfo, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
extract_timetz(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
return timetz_part_common(fcinfo, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* timetz_zone()
|
|
|
|
|
* Encode time with time zone type with specified time zone.
|
|
|
|
|
* Applies DST rules as of the transaction start time.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
timetz_zone(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
text *zone = PG_GETARG_TEXT_PP(0);
|
|
|
|
|
TimeTzADT *t = PG_GETARG_TIMETZADT_P(1);
|
|
|
|
|
TimeTzADT *result;
|
|
|
|
|
int tz;
|
|
|
|
|
char tzname[TZ_STRLEN_MAX + 1];
|
|
|
|
|
int type,
|
|
|
|
|
val;
|
|
|
|
|
pg_tz *tzp;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Look up the requested timezone.
|
|
|
|
|
*/
|
|
|
|
|
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.
11 years ago
|
|
|
|
|
|
|
|
type = DecodeTimezoneName(tzname, &val, &tzp);
|
|
|
|
|
|
|
|
|
|
if (type == TZNAME_FIXED_OFFSET)
|
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.
11 years ago
|
|
|
{
|
|
|
|
|
/* fixed-offset abbreviation */
|
|
|
|
|
tz = -val;
|
|
|
|
|
}
|
|
|
|
|
else if (type == TZNAME_DYNTZ)
|
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.
11 years ago
|
|
|
{
|
|
|
|
|
/* dynamic-offset abbreviation, resolve using transaction start time */
|
|
|
|
|
TimestampTz now = GetCurrentTransactionStartTimestamp();
|
|
|
|
|
int isdst;
|
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.
11 years ago
|
|
|
|
|
|
|
|
tz = DetermineTimeZoneAbbrevOffsetTS(now, tzname, tzp, &isdst);
|
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.
11 years ago
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Get the offset-from-GMT that is valid now for the zone name */
|
|
|
|
|
TimestampTz now = GetCurrentTransactionStartTimestamp();
|
|
|
|
|
struct pg_tm tm;
|
|
|
|
|
fsec_t fsec;
|
|
|
|
|
|
|
|
|
|
if (timestamp2tm(now, &tz, &tm, &fsec, NULL, tzp) != 0)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
|
|
|
|
|
|
|
|
|
|
result->time = t->time + (t->zone - tz) * USECS_PER_SEC;
|
|
|
|
|
/* C99 modulo has the wrong sign convention for negative input */
|
|
|
|
|
while (result->time < INT64CONST(0))
|
|
|
|
|
result->time += USECS_PER_DAY;
|
|
|
|
|
if (result->time >= USECS_PER_DAY)
|
|
|
|
|
result->time %= USECS_PER_DAY;
|
|
|
|
|
|
|
|
|
|
result->zone = tz;
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMETZADT_P(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* timetz_izone()
|
|
|
|
|
* Encode time with time zone type with specified time interval as time zone.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
timetz_izone(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
Interval *zone = PG_GETARG_INTERVAL_P(0);
|
|
|
|
|
TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
|
|
|
|
|
TimeTzADT *result;
|
|
|
|
|
int tz;
|
|
|
|
|
|
Support +/- infinity in the interval data type.
This adds support for infinity to the interval data type, using the
same input/output representation as the other date/time data types
that support infinity. This allows various arithmetic operations on
infinite dates, timestamps and intervals.
The new values are represented by setting all fields of the interval
to INT32/64_MIN for -infinity, and INT32/64_MAX for +infinity. This
ensures that they compare as less/greater than all other interval
values, without the need for any special-case comparison code.
Note that, since those 2 values were formerly accepted as legal finite
intervals, pg_upgrade and dump/restore from an old database will turn
them from finite to infinite intervals. That seems OK, since those
exact values should be extremely rare in practice, and they are
outside the documented range supported by the interval type, which
gives us a certain amount of leeway.
Bump catalog version.
Joseph Koshakow, Jian He, and Ashutosh Bapat, reviewed by me.
Discussion: https://postgr.es/m/CAAvxfHea4%2BsPybKK7agDYOMo9N-Z3J6ZXf3BOM79pFsFNcRjwA%40mail.gmail.com
2 years ago
|
|
|
if (INTERVAL_NOT_FINITE(zone))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
|
errmsg("interval time zone \"%s\" must be finite",
|
|
|
|
|
DatumGetCString(DirectFunctionCall1(interval_out,
|
|
|
|
|
PointerGetDatum(zone))))));
|
|
|
|
|
|
|
|
|
|
if (zone->month != 0 || zone->day != 0)
|
|
|
|
|
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
9 years ago
|
|
|
errmsg("interval time zone \"%s\" must not include months or days",
|
|
|
|
|
DatumGetCString(DirectFunctionCall1(interval_out,
|
|
|
|
|
PointerGetDatum(zone))))));
|
|
|
|
|
|
|
|
|
|
tz = -(zone->time / USECS_PER_SEC);
|
|
|
|
|
|
|
|
|
|
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
|
|
|
|
|
|
|
|
|
|
result->time = time->time + (time->zone - tz) * USECS_PER_SEC;
|
|
|
|
|
/* C99 modulo has the wrong sign convention for negative input */
|
|
|
|
|
while (result->time < INT64CONST(0))
|
|
|
|
|
result->time += USECS_PER_DAY;
|
|
|
|
|
if (result->time >= USECS_PER_DAY)
|
|
|
|
|
result->time %= USECS_PER_DAY;
|
|
|
|
|
|
|
|
|
|
result->zone = tz;
|
|
|
|
|
|
|
|
|
|
PG_RETURN_TIMETZADT_P(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* timetz_at_local()
|
|
|
|
|
*
|
|
|
|
|
* Unlike for timestamp[tz]_at_local, the type for timetz does not flip between
|
|
|
|
|
* time with/without time zone, so we cannot just call the conversion function.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
timetz_at_local(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
Datum time = PG_GETARG_DATUM(0);
|
|
|
|
|
const char *tzn = pg_get_timezone_name(session_timezone);
|
|
|
|
|
Datum zone = PointerGetDatum(cstring_to_text(tzn));
|
|
|
|
|
|
|
|
|
|
return DirectFunctionCall2(timetz_zone, zone, time);
|
|
|
|
|
}
|