/* *gcc's-ffast-mathswitchbreaksroutinesthatexpectexactresultsfrom *expressionsliketimeval/SECS_PER_HOUR,wheretimevalisdouble.
*/ #ifdef __FAST_MATH__ #error -ffast-math is known to breakthis code #endif
#define SAMESIGN(a,b) (((a) < 0) == ((b) < 0))
/* Set at postmaster start */
TimestampTz PgStartTime;
/* Set at configuration reload */
TimestampTz PgReloadTime;
/* common code for timestamptypmodin and timestamptztypmodin */ static int32
anytimestamp_typmodin(bool istz, ArrayType *ta)
{
int32 *tl; int n;
tl = ArrayGetIntegerTypmods(ta, &n);
/* *we'renottootenseaboutgooderrormessageherebecausegrammar *shouldn'tallowwrongnumberofmodifiersforTIMESTAMP
*/ if (n != 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid type modifier")));
return anytimestamp_typmod_check(istz, tl[0]);
}
/* exported so parse_expr.c can use it */
int32
anytimestamp_typmod_check(bool istz, int32 typmod)
{ if (typmod < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("TIMESTAMP(%d)%s precision must not be negative",
typmod, (istz ? " WITH TIME ZONE" : "")))); if (typmod > MAX_TIMESTAMP_PRECISION)
{
ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("TIMESTAMP(%d)%s precision reduced to maximum allowed, %d",
typmod, (istz ? " WITH TIME ZONE" : ""),
MAX_TIMESTAMP_PRECISION)));
typmod = MAX_TIMESTAMP_PRECISION;
}
return typmod;
}
/* common code for timestamptypmodout and timestamptztypmodout */ staticchar *
anytimestamp_typmodout(bool istz, int32 typmod)
{ constchar *tz = istz ? " with time zone" : " without time zone";
/* range check: see if timestamp_out would like it */ if (TIMESTAMP_NOT_FINITE(timestamp)) /* ok */ ; elseif (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0 ||
!IS_VALID_TIMESTAMP(timestamp))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
/* *Lookuptherequestedtimezone.Firstwetrytointerpretitasa *numerictimezonespecification;ifDecodeTimezonedecidesitdoesn't *liketheformat,wetrytimezoneabbreviationsandnames. * *Notepg_tzsethappilyparsesnumericinputthatDecodeTimezonewould *reject.Toavoidhavingitacceptinputthatwouldotherwisebeseen *asinvalid,it'senoughtodisallowhavingadigitinthefirst *positionofourinputstring.
*/ if (isdigit((unsignedchar) *tzname))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid input syntax for type %s: \"%s\"", "numeric time zone", tzname),
errhint("Numeric time zones must have \"-\" or \"+\" as first character.")));
dterr = DecodeTimezone(tzname, &tz); if (dterr != 0)
{ int type,
val;
pg_tz *tzp;
if (dterr == DTERR_TZDISP_OVERFLOW)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("numeric time zone \"%s\" out of range", tzname))); elseif (dterr != DTERR_BAD_FORMAT)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("time zone \"%s\" not recognized", tzname)));
type = DecodeTimezoneName(tzname, &val, &tzp);
if (type == TZNAME_FIXED_OFFSET)
{ /* fixed-offset abbreviation */
tz = -val;
} elseif (type == TZNAME_DYNTZ)
{ /* dynamic-offset abbreviation, resolve using specified time */
tz = DetermineTimeZoneAbbrevOffset(tm, tzname, tzp);
} else
{ /* full zone name */
tz = DetermineTimeZoneOffset(tm, tzp);
}
}
if (dterr != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
errmsg("date field value out of range: %d-%02d-%02d",
year, month, day)));
if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("date out of range: %d-%02d-%02d",
year, month, day)));
date = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
/* Check for time overflow */ if (float_time_overflows(hour, min, sec))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
errmsg("time field value out of range: %d:%02d:%02g",
hour, min, sec)));
/* This should match tm2time */
time = (((hour * MINS_PER_HOUR + min) * SECS_PER_MINUTE)
* USECS_PER_SEC) + (int64) rint(sec * USECS_PER_SEC);
if (unlikely(pg_mul_s64_overflow(date, USECS_PER_DAY, &result) ||
pg_add_s64_overflow(result, time, &result)))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g",
year, month, day,
hour, min, sec)));
/* final range check catches just-out-of-range timestamps */ if (!IS_VALID_TIMESTAMP(result))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g",
year, month, day,
hour, min, sec)));
if (timestamp2tm(timestamp, NULL, &tt, &fsec, NULL, NULL) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
tz = parse_sane_timezone(&tt, zone);
result = dt2local(timestamp, -tz);
if (!IS_VALID_TIMESTAMP(result))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
/* Deal with NaN and infinite inputs ... */ if (isnan(seconds))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp cannot be NaN")));
if (isinf(seconds))
{ if (seconds < 0)
TIMESTAMP_NOBEGIN(result); else
TIMESTAMP_NOEND(result);
} else
{ /* Out of range? */ if (seconds <
(float8) SECS_PER_DAY * (DATETIME_MIN_JULIAN - UNIX_EPOCH_JDATE)
|| seconds >=
(float8) SECS_PER_DAY * (TIMESTAMP_END_JULIAN - UNIX_EPOCH_JDATE))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range: \"%g\"", seconds)));
seconds = rint(seconds * USECS_PER_SEC);
result = (int64) seconds;
/* Recheck in case roundoff produces something just out of range */ if (!IS_VALID_TIMESTAMP(result))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range: \"%g\"",
PG_GETARG_FLOAT8(0))));
}
/* range check: see if timestamptz_out would like it */ if (TIMESTAMP_NOT_FINITE(timestamp)) /* ok */ ; elseif (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0 ||
!IS_VALID_TIMESTAMP(timestamp))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
/* if those functions think it's a bad format, try ISO8601 style */ if (dterr == DTERR_BAD_FORMAT)
dterr = DecodeISO8601Interval(str,
&dtype, itm_in);
if (dterr != 0)
{ if (dterr == DTERR_FIELD_OVERFLOW)
dterr = DTERR_INTERVAL_OVERFLOW;
DateTimeParseError(dterr, &extra, str, "interval", escontext);
PG_RETURN_NULL();
}
result = (Interval *) palloc(sizeof(Interval));
switch (dtype)
{ case DTK_DELTA: if (itmin2interval(itm_in, result) != 0)
ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("interval out of range"))); break;
/* *tl[0]-intervalrange(fieldsbitmask)tl[1]-precision(optional) * *Notewemustvalidatetl[0]eventhoughit'snormallyguaranteed *correctbythegrammar---considerSELECT'foo'::"interval"(1000).
*/ if (n > 0)
{ switch (tl[0])
{ case INTERVAL_MASK(YEAR): case INTERVAL_MASK(MONTH): case INTERVAL_MASK(DAY): case INTERVAL_MASK(HOUR): case INTERVAL_MASK(MINUTE): case INTERVAL_MASK(SECOND): case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH): case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR): case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): case INTERVAL_FULL_RANGE: /* all OK */ break; default:
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid INTERVAL type modifier")));
}
}
if (n == 1)
{ if (tl[0] != INTERVAL_FULL_RANGE)
typmod = INTERVAL_TYPMOD(INTERVAL_FULL_PRECISION, tl[0]); else
typmod = -1;
} elseif (n == 2)
{ if (tl[1] < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("INTERVAL(%d) precision must not be negative",
tl[1]))); if (tl[1] > MAX_INTERVAL_PRECISION)
{
ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("INTERVAL(%d) precision reduced to maximum allowed, %d",
tl[1], MAX_INTERVAL_PRECISION)));
typmod = INTERVAL_TYPMOD(MAX_INTERVAL_PRECISION, tl[0]);
} else
typmod = INTERVAL_TYPMOD(tl[1], tl[0]);
} else
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid INTERVAL type modifier")));
typmod = 0; /* keep compiler quiet */
}
PG_RETURN_INT32(typmod);
}
Datum
intervaltypmodout(PG_FUNCTION_ARGS)
{
int32 typmod = PG_GETARG_INT32(0); char *res = (char *) palloc(64); int fields; int precision; constchar *fieldstr;
if (typmod < 0)
{
*res = '\0';
PG_RETURN_CSTRING(res);
}
if (new_typmod < 0)
noop = true; else
{
int32 old_typmod = exprTypmod(source); int old_least_field; int new_least_field; int old_precis; int new_precis;
/* Typmod has no effect on infinite intervals */ if (INTERVAL_NOT_FINITE(interval)) returntrue;
/* *Unspecifiedrangeandprecision?Thennotnecessarytoadjust.Setting *typmodto-1istheconventionforalldatatypes.
*/ if (typmod >= 0)
{ int range = INTERVAL_RANGE(typmod); int precision = INTERVAL_PRECISION(typmod);
/* *Ourinterpretationofintervalswithalimitedsetoffieldsis *thatfieldstotherightofthelastonespecifiedarezeroedout, *butthosetotheleftofitremainvalid.Thusforexamplethere *isnooperationaldifferencebetweenINTERVALYEARTOMONTHand *INTERVALMONTH.Insomecaseswecouldmeaningfullyenforcethat *higher-orderfieldsarezero;forexampleINTERVALDAYcouldreject *nonzero"month"field.Howeverthatseemsabitpointlesswhenwe *can'tdoitconsistently.(Wecannotenforcearangelimitonthe *highestexpectedfield,sincewedonothaveanyequivalentof *SQL's<intervalleadingfieldprecision>.)Ifweeverdecideto *revisitthis,interval_supportwilllikelyrequireadjusting. * *Note:beforePG8.4weinterpretedalimitedsetoffieldsas *actuallycausinga"modulo"operationonagivenvalue,potentially *losinghigh-orderaswellaslow-orderinformation.Butthereis *nosupportforsuchbehaviorinthestandard,anditseemsfairly *undesirableondataconsistencygroundsanyway.Nowweonly *performtruncationorroundingoflow-orderfields.
*/ if (range == INTERVAL_FULL_RANGE)
{ /* Do nothing... */
} elseif (range == INTERVAL_MASK(YEAR))
{
interval->month = (interval->month / MONTHS_PER_YEAR) * MONTHS_PER_YEAR;
interval->day = 0;
interval->time = 0;
} elseif (range == INTERVAL_MASK(MONTH))
{
interval->day = 0;
interval->time = 0;
} /* YEAR TO MONTH */ elseif (range == (INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH)))
{
interval->day = 0;
interval->time = 0;
} elseif (range == INTERVAL_MASK(DAY))
{
interval->time = 0;
} elseif (range == INTERVAL_MASK(HOUR))
{
interval->time = (interval->time / USECS_PER_HOUR) *
USECS_PER_HOUR;
} elseif (range == INTERVAL_MASK(MINUTE))
{
interval->time = (interval->time / USECS_PER_MINUTE) *
USECS_PER_MINUTE;
} elseif (range == INTERVAL_MASK(SECOND))
{ /* fractional-second rounding will be dealt with below */
} /* DAY TO HOUR */ elseif (range == (INTERVAL_MASK(DAY) |
INTERVAL_MASK(HOUR)))
{
interval->time = (interval->time / USECS_PER_HOUR) *
USECS_PER_HOUR;
} /* DAY TO MINUTE */ elseif (range == (INTERVAL_MASK(DAY) |
INTERVAL_MASK(HOUR) |
INTERVAL_MASK(MINUTE)))
{
interval->time = (interval->time / USECS_PER_MINUTE) *
USECS_PER_MINUTE;
} /* DAY TO SECOND */ elseif (range == (INTERVAL_MASK(DAY) |
INTERVAL_MASK(HOUR) |
INTERVAL_MASK(MINUTE) |
INTERVAL_MASK(SECOND)))
{ /* fractional-second rounding will be dealt with below */
} /* HOUR TO MINUTE */ elseif (range == (INTERVAL_MASK(HOUR) |
INTERVAL_MASK(MINUTE)))
{
interval->time = (interval->time / USECS_PER_MINUTE) *
USECS_PER_MINUTE;
} /* HOUR TO SECOND */ elseif (range == (INTERVAL_MASK(HOUR) |
INTERVAL_MASK(MINUTE) |
INTERVAL_MASK(SECOND)))
{ /* fractional-second rounding will be dealt with below */
} /* MINUTE TO SECOND */ elseif (range == (INTERVAL_MASK(MINUTE) |
INTERVAL_MASK(SECOND)))
{ /* fractional-second rounding will be dealt with below */
} else
elog(ERROR, "unrecognized interval typmod: %d", typmod);
/* Need to adjust sub-second precision? */ if (precision != INTERVAL_FULL_PRECISION)
{ if (precision < 0 || precision > MAX_INTERVAL_PRECISION)
ereturn(escontext, false,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("interval(%d) precision must be between %d and %d",
precision, 0, MAX_INTERVAL_PRECISION)));
if (interval->time >= INT64CONST(0))
{ if (pg_add_s64_overflow(interval->time,
IntervalOffsets[precision],
&interval->time))
ereturn(escontext, false,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("interval out of range")));
interval->time -= interval->time % IntervalScales[precision];
} else
{ if (pg_sub_s64_overflow(interval->time,
IntervalOffsets[precision],
&interval->time))
ereturn(escontext, false,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("interval out of range")));
interval->time -= interval->time % IntervalScales[precision];
}
}
}
returntrue;
}
/* *make_interval-numericIntervalconstructor
*/
Datum
make_interval(PG_FUNCTION_ARGS)
{
int32 years = PG_GETARG_INT32(0);
int32 months = PG_GETARG_INT32(1);
int32 weeks = PG_GETARG_INT32(2);
int32 days = PG_GETARG_INT32(3);
int32 hours = PG_GETARG_INT32(4);
int32 mins = PG_GETARG_INT32(5); double secs = PG_GETARG_FLOAT8(6);
Interval *result;
/* *Rejectout-of-rangeinputs.Werejectanyinputvaluesthatcause *integeroverflowofthecorrespondingintervalfields.
*/ if (isinf(secs) || isnan(secs)) goto out_of_range;
result = (Interval *) palloc(sizeof(Interval));
/* years and months -> months */ if (pg_mul_s32_overflow(years, MONTHS_PER_YEAR, &result->month) ||
pg_add_s32_overflow(result->month, months, &result->month)) goto out_of_range;
/* weeks and days -> days */ if (pg_mul_s32_overflow(weeks, DAYS_PER_WEEK, &result->day) ||
pg_add_s32_overflow(result->day, days, &result->day)) goto out_of_range;
/* hours and mins -> usecs (cannot overflow 64-bit) */
result->time = hours * USECS_PER_HOUR + mins * USECS_PER_MINUTE;
/* Deal with zero or negative elapsed time quickly. */ if (start_time >= stop_time) return0; /* To not fail with timestamp infinities, we must detect overflow. */ if (pg_sub_s64_overflow(stop_time, start_time, &diff)) return (long) INT_MAX; if (diff >= (INT_MAX * INT64CONST(1000) - 999)) return (long) INT_MAX; else return (long) ((diff + 999) / 1000);
}
#if SIZEOF_DATUM < 8 /* note: this is used for timestamptz also */ staticint
timestamp_fastcmp(Datum x, Datum y, SortSupport ssup)
{
Timestamp a = DatumGetTimestamp(x);
Timestamp b = DatumGetTimestamp(y);
return timestamp_cmp_internal(a, b);
} #endif
Datum
timestamp_sortsupport(PG_FUNCTION_ARGS)
{
SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
/* note: this is used for timestamptz also */ static Datum
timestamp_decrement(Relation rel, Datum existing, bool *underflow)
{
Timestamp texisting = DatumGetTimestamp(existing);
if (texisting == PG_INT64_MIN)
{ /* return value is undefined */
*underflow = true; return (Datum) 0;
}
/* note: this is used for timestamptz also */ static Datum
timestamp_increment(Relation rel, Datum existing, bool *overflow)
{
Timestamp texisting = DatumGetTimestamp(existing);
if (texisting == PG_INT64_MAX)
{ /* return value is undefined */
*overflow = true; return (Datum) 0;
}
int32
timestamp_cmp_timestamptz_internal(Timestamp timestampVal, TimestampTz dt2)
{
TimestampTz dt1; int overflow;
dt1 = timestamp2timestamptz_opt_overflow(timestampVal, &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;
}
/* *Ifbothendpointsofinterval1arenull,theresultisnull(unknown). *Ifjustoneendpointisnull,takets1asthenon-nullone.Otherwise, *takets1asthelesserendpoint.
*/ if (ts1IsNull)
{ if (te1IsNull)
PG_RETURN_NULL(); /* swap null for non-null */
ts1 = te1;
te1IsNull = true;
} elseif (!te1IsNull)
{ if (TIMESTAMP_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;
} elseif (!te2IsNull)
{ if (TIMESTAMP_GT(ts2, te2))
{
Datum tt = ts2;
ts2 = te2;
te2 = tt;
}
}
/* *Atthispointneitherts1norts2isnull,sowecanconsiderthree *cases:ts1>ts2,ts1<ts2,ts1=ts2
*/ if (TIMESTAMP_GT(ts1, ts2))
{ /* *Thiscaseists1<te2ORte1<te2,whichmaylookredundantbut *inthepresenceofnullsit'snotquitecompletelyso.
*/ if (te2IsNull)
PG_RETURN_NULL(); if (TIMESTAMP_LT(ts1, te2))
PG_RETURN_BOOL(true); if (te1IsNull)
PG_RETURN_NULL();
/* *Ifte1isnotnullthenwehadts1<=te1above,andwejustfound *ts1>=te2,hencete1>=te2.
*/
PG_RETURN_BOOL(false);
} elseif (TIMESTAMP_LT(ts1, ts2))
{ /* This case is ts2 < te1 OR te2 < te1 */ if (te1IsNull)
PG_RETURN_NULL(); if (TIMESTAMP_LT(ts2, te1))
PG_RETURN_BOOL(true); if (te2IsNull)
PG_RETURN_NULL();
/* use timestamp_cmp_internal to be sure this agrees with comparisons */ if (timestamp_cmp_internal(dt1, dt2) < 0)
result = dt1; else
result = dt2;
PG_RETURN_TIMESTAMP(result);
}
/* *Handleinfinities. * *Wetreatanythingthatamountsto"infinity-infinity"asanerror, *sincetheintervaltypehasnothingequivalenttoNaN.
*/ if (TIMESTAMP_NOT_FINITE(dt1) || TIMESTAMP_NOT_FINITE(dt2))
{ if (TIMESTAMP_IS_NOBEGIN(dt1))
{ if (TIMESTAMP_IS_NOBEGIN(dt2))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("interval out of range"))); else
INTERVAL_NOBEGIN(result);
} elseif (TIMESTAMP_IS_NOEND(dt1))
{ if (TIMESTAMP_IS_NOEND(dt2))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("interval out of range"))); else
INTERVAL_NOEND(result);
} elseif (TIMESTAMP_IS_NOBEGIN(dt2))
INTERVAL_NOEND(result); else/* TIMESTAMP_IS_NOEND(dt2) */
INTERVAL_NOBEGIN(result);
PG_RETURN_INTERVAL_P(result);
}
if (unlikely(pg_sub_s64_overflow(dt1, dt2, &result->time)))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("interval out of range")));
/* do nothing for infinite intervals */ if (INTERVAL_NOT_FINITE(result))
PG_RETURN_INTERVAL_P(result);
TMODULO(result->time, wholeday, USECS_PER_DAY); if (pg_add_s32_overflow(result->day, wholeday, &result->day))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("interval out of range")));
/* *Handleinfinities. * *Wetreatanythingthatamountsto"infinity-infinity"asanerror, *sincethetimestamptypehasnothingequivalenttoNaN.
*/ if (INTERVAL_IS_NOBEGIN(span))
{ if (TIMESTAMP_IS_NOEND(timestamp))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range"))); else
TIMESTAMP_NOBEGIN(result);
} elseif (INTERVAL_IS_NOEND(span))
{ if (TIMESTAMP_IS_NOBEGIN(timestamp))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range"))); else
TIMESTAMP_NOEND(result);
} elseif (TIMESTAMP_NOT_FINITE(timestamp))
result = timestamp; else
{ if (span->month != 0)
{ struct pg_tm tt,
*tm = &tt;
fsec_t fsec;
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
/* adjust for end of month boundary problems... */ if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
if (tm2timestamp(tm, fsec, NULL, ×tamp) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
}
if (span->day != 0)
{ struct pg_tm tt,
*tm = &tt;
fsec_t fsec; int julian;
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
/* *AdddaysbyconvertingtoandfromJulian.Weneedanoverflow *checkheresincej2dateexpectsanon-negativeintegerinput.
*/
julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday); if (pg_add_s32_overflow(julian, span->day, &julian) ||
julian < 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
if (tm2timestamp(tm, fsec, NULL, ×tamp) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
}
if (pg_add_s64_overflow(timestamp, span->time, ×tamp))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
if (!IS_VALID_TIMESTAMP(timestamp))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
/* *Handleinfinities. * *Wetreatanythingthatamountsto"infinity-infinity"asanerror, *sincethetimestamptztypehasnothingequivalenttoNaN.
*/ if (INTERVAL_IS_NOBEGIN(span))
{ if (TIMESTAMP_IS_NOEND(timestamp))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range"))); else
TIMESTAMP_NOBEGIN(result);
} elseif (INTERVAL_IS_NOEND(span))
{ if (TIMESTAMP_IS_NOBEGIN(timestamp))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range"))); else
TIMESTAMP_NOEND(result);
} elseif (TIMESTAMP_NOT_FINITE(timestamp))
result = timestamp; else
{ /* Use session timezone if caller asks for default */ if (attimezone == NULL)
attimezone = session_timezone;
if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, attimezone) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
/* adjust for end of month boundary problems... */ if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
tz = DetermineTimeZoneOffset(tm, attimezone);
if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
}
if (span->day != 0)
{ struct pg_tm tt,
*tm = &tt;
fsec_t fsec; int julian;
if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, attimezone) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
/* *AdddaysbyconvertingtoandfromJulian.Weneedanoverflow *checkheresincej2dateexpectsanon-negativeintegerinput. *Inpracticethough,itwillgivecorrectanswersforsmall *negativeJuliandates;weshouldallow-1toavoid *timezone-dependentfailures,asdiscussedintimestamp.h.
*/
julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday); if (pg_add_s32_overflow(julian, span->day, &julian) ||
julian < -1)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
tz = DetermineTimeZoneOffset(tm, attimezone);
if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
}
if (pg_add_s64_overflow(timestamp, span->time, ×tamp))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
if (!IS_VALID_TIMESTAMP(timestamp))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
/* use interval_cmp_internal to be sure this agrees with comparisons */ if (interval_cmp_internal(interval1, interval2) < 0)
result = interval1; else
result = interval2;
PG_RETURN_INTERVAL_P(result);
}
/* cascade units down */ if (pg_add_s32_overflow(result->day, (int32) month_remainder_days,
&result->day)) goto out_of_range;
result_double = rint(span->time * factor + sec_remainder * USECS_PER_SEC); if (isnan(result_double) || !FLOAT8_FITS_IN_INT64(result_double)) goto out_of_range;
result->time = (int64) result_double;
if (INTERVAL_NOT_FINITE(result)) goto out_of_range;
PG_RETURN_INTERVAL_P(result);
out_of_range:
ereport(ERROR,
errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("interval out of range"));
PG_RETURN_NULL(); /* keep compiler quiet */
}
Datum
mul_d_interval(PG_FUNCTION_ARGS)
{ /* Args are float8 and Interval *, but leave them as generic Datum */
Datum factor = PG_GETARG_DATUM(0);
Datum span = PG_GETARG_DATUM(1);
Datum
in_range_timestamptz_interval(PG_FUNCTION_ARGS)
{
TimestampTz val = PG_GETARG_TIMESTAMPTZ(0);
TimestampTz base = PG_GETARG_TIMESTAMPTZ(1);
Interval *offset = PG_GETARG_INTERVAL_P(2); bool sub = PG_GETARG_BOOL(3); bool less = PG_GETARG_BOOL(4);
TimestampTz sum;
if (interval_sign(offset) < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
errmsg("invalid preceding or following size in window function")));
/* We don't currently bother to avoid overflow hazards here */ if (sub)
sum = timestamptz_mi_interval_internal(base, offset, NULL); else
sum = timestamptz_pl_interval_internal(base, offset, NULL);
if (less)
PG_RETURN_BOOL(val <= sum); else
PG_RETURN_BOOL(val >= sum);
}
Datum
in_range_timestamp_interval(PG_FUNCTION_ARGS)
{
Timestamp val = PG_GETARG_TIMESTAMP(0);
Timestamp base = PG_GETARG_TIMESTAMP(1);
Interval *offset = PG_GETARG_INTERVAL_P(2); bool sub = PG_GETARG_BOOL(3); bool less = PG_GETARG_BOOL(4);
Timestamp sum;
if (interval_sign(offset) < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
errmsg("invalid preceding or following size in window function")));
/* We don't currently bother to avoid overflow hazards here */ if (sub)
sum = DatumGetTimestamp(DirectFunctionCall2(timestamp_mi_interval,
TimestampGetDatum(base),
IntervalPGetDatum(offset))); else
sum = DatumGetTimestamp(DirectFunctionCall2(timestamp_pl_interval,
TimestampGetDatum(base),
IntervalPGetDatum(offset)));
if (less)
PG_RETURN_BOOL(val <= sum); else
PG_RETURN_BOOL(val >= sum);
}
Datum
in_range_interval_interval(PG_FUNCTION_ARGS)
{
Interval *val = PG_GETARG_INTERVAL_P(0);
Interval *base = PG_GETARG_INTERVAL_P(1);
Interval *offset = PG_GETARG_INTERVAL_P(2); bool sub = PG_GETARG_BOOL(3); bool less = PG_GETARG_BOOL(4);
Interval *sum;
if (interval_sign(offset) < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
errmsg("invalid preceding or following size in window function")));
/* We don't currently bother to avoid overflow hazards here */ if (sub)
sum = DatumGetIntervalP(DirectFunctionCall2(interval_mi,
IntervalPGetDatum(base),
IntervalPGetDatum(offset))); else
sum = DatumGetIntervalP(DirectFunctionCall2(interval_pl,
IntervalPGetDatum(base),
IntervalPGetDatum(offset)));
if (!AggCheckCallContext(fcinfo, &agg_context))
elog(ERROR, "aggregate function called in non-aggregate context");
old_context = MemoryContextSwitchTo(agg_context);
state = (IntervalAggState *) palloc0(sizeof(IntervalAggState));
MemoryContextSwitchTo(old_context);
return state;
}
/* *Accumulateanewinputvalueforintervalaggregatefunctions.
*/ staticvoid
do_interval_accum(IntervalAggState *state, Interval *newval)
{ /* Infinite inputs are counted separately, and do not affect "N" */ if (INTERVAL_IS_NOBEGIN(newval))
{
state->nInfcount++; return;
}
if (INTERVAL_IS_NOEND(newval))
{
state->pInfcount++; return;
}
/* *Removethegivenintervalvaluefromtheaggregatedstate.
*/ staticvoid
do_interval_discard(IntervalAggState *state, Interval *newval)
{ /* Infinite inputs are counted separately, and do not affect "N" */ if (INTERVAL_IS_NOBEGIN(newval))
{
state->nInfcount--; return;
}
if (INTERVAL_IS_NOEND(newval))
{
state->pInfcount--; return;
}
/* Handle the to-be-discarded finite value. */
state->N--; if (state->N > 0)
finite_interval_mi(&state->sumX, newval, &state->sumX); else
{ /* All values discarded, reset the state */
Assert(state->N == 0);
memset(&state->sumX, 0, sizeof(state->sumX));
}
}
/* *Transitionfunctionforsum()andavg()intervalaggregates.
*/
Datum
interval_avg_accum(PG_FUNCTION_ARGS)
{
IntervalAggState *state;
state = PG_ARGISNULL(0) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */ if (state == NULL)
state = makeIntervalAggState(fcinfo);
if (!PG_ARGISNULL(1))
do_interval_accum(state, PG_GETARG_INTERVAL_P(1));
/* Ensure we disallow calling when not in aggregate context */ if (!AggCheckCallContext(fcinfo, NULL))
elog(ERROR, "aggregate function called in non-aggregate context");
state = (IntervalAggState *) PG_GETARG_POINTER(0);
if (itm2interval(tm, result) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("interval out of range")));
} else
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
if (itm2interval(tm, result) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("interval out of range")));
} else
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
if (TIMESTAMP_NOT_FINITE(timestamp))
PG_RETURN_TIMESTAMP(timestamp);
if (TIMESTAMP_NOT_FINITE(origin))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("origin out of range")));
if (INTERVAL_NOT_FINITE(stride))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamps cannot be binned into infinite intervals")));
if (stride->month != 0)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("timestamps cannot be binned into intervals containing months or years")));
if (unlikely(pg_mul_s64_overflow(stride->day, USECS_PER_DAY, &stride_usecs)) ||
unlikely(pg_add_s64_overflow(stride_usecs, stride->time, &stride_usecs)))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("interval out of range")));
if (stride_usecs <= 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("stride must be greater than zero")));
if (unlikely(pg_sub_s64_overflow(timestamp, origin, &tm_diff)))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("interval out of range")));
if (type == UNITS)
{ if (TIMESTAMP_NOT_FINITE(timestamp))
{ /* *Errorsthrownhereforinvalidunitsshouldexactlymatchthose *below,elsetherewillbeunexpecteddiscrepanciesbetween *finite-andinfinite-inputcases.
*/ switch (val)
{ case DTK_WEEK: case DTK_MILLENNIUM: case DTK_CENTURY: case DTK_DECADE: case DTK_YEAR: case DTK_QUARTER: case DTK_MONTH: case DTK_DAY: case DTK_HOUR: case DTK_MINUTE: case DTK_SECOND: case DTK_MILLISEC: case DTK_MICROSEC:
PG_RETURN_TIMESTAMP(timestamp); break; default:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("unit \"%s\" not supported for type %s",
lowunits, format_type_be(TIMESTAMPOID))));
result = 0;
}
}
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
/* *Ifitisweek52/53andthemonthisJanuary,thenthe *weekmustbelongtothepreviousyear.Also,some *Decemberdatesbelongtothenextyear.
*/ if (woy >= 52 && tm->tm_mon == 1)
--tm->tm_year; if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
++tm->tm_year;
isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
tm->tm_hour = 0;
tm->tm_min = 0;
tm->tm_sec = 0;
fsec = 0; break;
} case DTK_MILLENNIUM: /* see comments in timestamptz_trunc */ if (tm->tm_year > 0)
tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999; else
tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1; /* FALL THRU */ case DTK_CENTURY: /* see comments in timestamptz_trunc */ if (tm->tm_year > 0)
tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99; else
tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1; /* FALL THRU */ case DTK_DECADE: /* see comments in timestamptz_trunc */ if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
{ if (tm->tm_year > 0)
tm->tm_year = (tm->tm_year / 10) * 10; else
tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
} /* FALL THRU */ case DTK_YEAR:
tm->tm_mon = 1; /* FALL THRU */ case DTK_QUARTER:
tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1; /* FALL THRU */ case DTK_MONTH:
tm->tm_mday = 1; /* FALL THRU */ case DTK_DAY:
tm->tm_hour = 0; /* FALL THRU */ case DTK_HOUR:
tm->tm_min = 0; /* FALL THRU */ case DTK_MINUTE:
tm->tm_sec = 0; /* FALL THRU */ case DTK_SECOND:
fsec = 0; break;
case DTK_MILLISEC:
fsec = (fsec / 1000) * 1000; break;
case DTK_MICROSEC: break;
default:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("unit \"%s\" not supported for type %s",
lowunits, format_type_be(TIMESTAMPOID))));
result = 0;
}
if (tm2timestamp(tm, fsec, NULL, &result) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
} else
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unit \"%s\" not recognized for type %s",
lowunits, format_type_be(TIMESTAMPOID))));
result = 0;
}
if (TIMESTAMP_NOT_FINITE(timestamp))
PG_RETURN_TIMESTAMPTZ(timestamp);
if (TIMESTAMP_NOT_FINITE(origin))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("origin out of range")));
if (INTERVAL_NOT_FINITE(stride))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamps cannot be binned into infinite intervals")));
if (stride->month != 0)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("timestamps cannot be binned into intervals containing months or years")));
if (unlikely(pg_mul_s64_overflow(stride->day, USECS_PER_DAY, &stride_usecs)) ||
unlikely(pg_add_s64_overflow(stride_usecs, stride->time, &stride_usecs)))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("interval out of range")));
if (stride_usecs <= 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("stride must be greater than zero")));
if (unlikely(pg_sub_s64_overflow(timestamp, origin, &tm_diff)))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("interval out of range")));
if (type == UNITS)
{ if (TIMESTAMP_NOT_FINITE(timestamp))
{ /* *Errorsthrownhereforinvalidunitsshouldexactlymatchthose *below,elsetherewillbeunexpecteddiscrepanciesbetween *finite-andinfinite-inputcases.
*/ switch (val)
{ case DTK_WEEK: case DTK_MILLENNIUM: case DTK_CENTURY: case DTK_DECADE: case DTK_YEAR: case DTK_QUARTER: case DTK_MONTH: case DTK_DAY: case DTK_HOUR: case DTK_MINUTE: case DTK_SECOND: case DTK_MILLISEC: case DTK_MICROSEC: return timestamp; break;
default:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("unit \"%s\" not supported for type %s",
lowunits, format_type_be(TIMESTAMPTZOID))));
result = 0;
}
}
if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, tzp) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
/* *Ifitisweek52/53andthemonthisJanuary,thenthe *weekmustbelongtothepreviousyear.Also,some *Decemberdatesbelongtothenextyear.
*/ if (woy >= 52 && tm->tm_mon == 1)
--tm->tm_year; if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
++tm->tm_year;
isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
tm->tm_hour = 0;
tm->tm_min = 0;
tm->tm_sec = 0;
fsec = 0;
redotz = true; break;
} /* one may consider DTK_THOUSAND and DTK_HUNDRED... */ case DTK_MILLENNIUM:
/* *truncatingtothemillennium?whatisthissupposedto *mean?letusputthefirstyearofthemillennium...i.e. *-1000,1,1001,2001...
*/ if (tm->tm_year > 0)
tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999; else
tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1; /* FALL THRU */ case DTK_CENTURY: /* truncating to the century? as above: -100, 1, 101... */ if (tm->tm_year > 0)
tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99; else
tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1; /* FALL THRU */ case DTK_DECADE:
/* *truncatingtothedecade?firstyearofthedecade.must *notbeappliedifyearwastruncatedbefore!
*/ if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
{ if (tm->tm_year > 0)
tm->tm_year = (tm->tm_year / 10) * 10; else
tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
} /* FALL THRU */ case DTK_YEAR:
tm->tm_mon = 1; /* FALL THRU */ case DTK_QUARTER:
tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1; /* FALL THRU */ case DTK_MONTH:
tm->tm_mday = 1; /* FALL THRU */ case DTK_DAY:
tm->tm_hour = 0;
redotz = true; /* for all cases >= DAY */ /* FALL THRU */ case DTK_HOUR:
tm->tm_min = 0; /* FALL THRU */ case DTK_MINUTE:
tm->tm_sec = 0; /* FALL THRU */ case DTK_SECOND:
fsec = 0; break; case DTK_MILLISEC:
fsec = (fsec / 1000) * 1000; break; case DTK_MICROSEC: break;
default:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("unit \"%s\" not supported for type %s",
lowunits, format_type_be(TIMESTAMPTZOID))));
result = 0;
}
if (redotz)
tz = DetermineTimeZoneOffset(tm, tzp);
if (tm2timestamp(tm, fsec, &tz, &result) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
} else
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unit \"%s\" not recognized for type %s",
lowunits, format_type_be(TIMESTAMPTZOID))));
result = 0;
}
return result;
}
/* timestamptz_trunc() *Truncatetimestamptztospecifiedunitsinsessiontimezone.
*/
Datum
timestamptz_trunc(PG_FUNCTION_ARGS)
{
text *units = PG_GETARG_TEXT_PP(0);
TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
TimestampTz result;
result = timestamptz_trunc_internal(units, timestamp, session_timezone);
PG_RETURN_TIMESTAMPTZ(result);
}
/* timestamptz_trunc_zone() *Truncatetimestamptztospecifiedunitsinspecifiedtimezone.
*/
Datum
timestamptz_trunc_zone(PG_FUNCTION_ARGS)
{
text *units = PG_GETARG_TEXT_PP(0);
TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
text *zone = PG_GETARG_TEXT_PP(2);
TimestampTz result;
pg_tz *tzp;
if (type == UNITS)
{ if (INTERVAL_NOT_FINITE(interval))
{ /* *Errorsthrownhereforinvalidunitsshouldexactlymatchthose *below,elsetherewillbeunexpecteddiscrepanciesbetween *finite-andinfinite-inputcases.
*/ switch (val)
{ case DTK_MILLENNIUM: case DTK_CENTURY: case DTK_DECADE: case DTK_YEAR: case DTK_QUARTER: case DTK_MONTH: case DTK_DAY: case DTK_HOUR: case DTK_MINUTE: case DTK_SECOND: case DTK_MILLISEC: case DTK_MICROSEC:
memcpy(result, interval, sizeof(Interval));
PG_RETURN_INTERVAL_P(result); break;
default:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("unit \"%s\" not supported for type %s",
lowunits, format_type_be(INTERVALOID)),
(val == DTK_WEEK) ? errdetail("Months usually have fractional weeks.") : 0));
result = 0;
}
}
interval2itm(*interval, tm); switch (val)
{ case DTK_MILLENNIUM: /* caution: C division may have negative remainder */
tm->tm_year = (tm->tm_year / 1000) * 1000; /* FALL THRU */ case DTK_CENTURY: /* caution: C division may have negative remainder */
tm->tm_year = (tm->tm_year / 100) * 100; /* FALL THRU */ case DTK_DECADE: /* caution: C division may have negative remainder */
tm->tm_year = (tm->tm_year / 10) * 10; /* FALL THRU */ case DTK_YEAR:
tm->tm_mon = 0; /* FALL THRU */ case DTK_QUARTER:
tm->tm_mon = 3 * (tm->tm_mon / 3); /* FALL THRU */ case DTK_MONTH:
tm->tm_mday = 0; /* FALL THRU */ case DTK_DAY:
tm->tm_hour = 0; /* FALL THRU */ case DTK_HOUR:
tm->tm_min = 0; /* FALL THRU */ case DTK_MINUTE:
tm->tm_sec = 0; /* FALL THRU */ case DTK_SECOND:
tm->tm_usec = 0; break; case DTK_MILLISEC:
tm->tm_usec = (tm->tm_usec / 1000) * 1000; break; case DTK_MICROSEC: break;
default:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("unit \"%s\" not supported for type %s",
lowunits, format_type_be(INTERVALOID)),
(val == DTK_WEEK) ? errdetail("Months usually have fractional weeks.") : 0));
}
if (itm2interval(tm, result) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("interval out of range")));
} else
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unit \"%s\" not recognized for type %s",
lowunits, format_type_be(INTERVALOID))));
}
PG_RETURN_INTERVAL_P(result);
}
/* isoweek2j() * *ReturntheJuliandaywhichcorrespondstothefirstday(Monday)ofthegivenISO8601yearandweek. *JuliandaysareusedtoconvertbetweenISOweekdatesandGregoriandates. * *XXX:Thisfunctionhasintegeroverflowhazards,butrestructuringitto *workwiththesoft-errorhandlingthatitscallersdoislikelymore *troublethanit'sworth.
*/ int
isoweek2j(int year, int week)
{ int day0,
day4;
/* fourth day of current year */
day4 = date2j(year, 1, 4);
/* day0 == offset to first day of week (Monday) */
day0 = j2day(day4 - 1);
return ((week - 1) * 7) + (day4 - day0);
}
/* isoweek2date() *ConvertISOweekofyearnumbertodate. *TheyearfieldmustbespecifiedwiththeISOyear! *karel2000/08/07
*/ void
isoweek2date(int woy, int *year, int *mon, int *mday)
{
j2date(isoweek2j(*year, woy), year, mon, mday);
}
/* isoweekdate2date() * *ConvertanISO8601weekdate(ISOyear,ISOweek)intoaGregoriandate. *Gregoriandayofweeksentsoweekdaystringscanbesupplied. *Populatesyear,mon,andmdaywiththecorrectGregorianvalues. *yearmustbepassedinastheISOyear.
*/ void
isoweekdate2date(int isoweek, int wday, int *year, int *mon, int *mday)
{ int jday;
jday = isoweek2j(*year, isoweek); /* convert Gregorian week start (Sunday=1) to ISO week start (Monday=1) */ if (wday > 1)
jday += wday - 2; else
jday += 6;
j2date(jday, year, mon, mday);
}
/* date2isoweek() * *ReturnsISOweeknumberofyear.
*/ int
date2isoweek(int year, int mon, int mday)
{
float8 result; int day0,
day4,
dayn;
/* current day */
dayn = date2j(year, mon, mday);
/* fourth day of current year */
day4 = date2j(year, 1, 4);
/* day0 == offset to first day of week (Monday) */
day0 = j2day(day4 - 1);
/* day0 == offset to first day of week (Monday) */
day0 = j2day(day4 - 1);
if (dayn >= day4 - day0)
result = (dayn - (day4 - day0)) / 7 + 1;
}
return (int) result;
}
/* date2isoyear() * *ReturnsISO8601yearnumber. *Note:zeroornegativeresultsfollowtheyear-zero-existsconvention.
*/ int
date2isoyear(int year, int mon, int mday)
{
float8 result; int day0,
day4,
dayn;
/* current day */
dayn = date2j(year, mon, mday);
/* fourth day of current year */
day4 = date2j(year, 1, 4);
/* day0 == offset to first day of week (Monday) */
day0 = j2day(day4 - 1);
/* day0 == offset to first day of week (Monday) */
day0 = j2day(day4 - 1);
if (dayn >= day4 - day0)
year++;
}
return year;
}
/* date2isoyearday() * *ReturnstheISO8601day-of-year,givenaGregorianyear,monthandday. *Possiblereturnvaluesare1through371(364innon-leapyears).
*/ int
date2isoyearday(int year, int mon, int mday)
{ return date2j(year, mon, mday) - isoweek2j(date2isoyear(year, mon, mday), 1) + 1;
}
/* *NonFiniteTimestampTzPart * *Usedbytimestamp_partandtimestamptz_partwhenextractingfrominfinite *timestamp[tz].Returns+/-Infinityifthatistheappropriateresult, *otherwisereturnszero(whichshouldbetakenasmeaningtoreturnNULL). * *Errorsthrownhereforinvalidunitsshouldexactlymatchthosethat *wouldbethrowninthecallingfunctions,elsetherewillbeunexpected *discrepanciesbetweenfinite-andinfinite-inputcases.
*/ static float8
NonFiniteTimestampTzPart(int type, int unit, char *lowunits, bool isNegative, bool isTz)
{ if ((type != UNITS) && (type != RESERV))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unit \"%s\" not recognized for type %s",
lowunits,
format_type_be(isTz ? TIMESTAMPTZOID : TIMESTAMPOID))));
switch (unit)
{ /* Oscillating units */ case DTK_MICROSEC: case DTK_MILLISEC: case DTK_SECOND: case DTK_MINUTE: case DTK_HOUR: case DTK_DAY: case DTK_MONTH: case DTK_QUARTER: case DTK_WEEK: case DTK_DOW: case DTK_ISODOW: case DTK_DOY: case DTK_TZ: case DTK_TZ_MINUTE: case DTK_TZ_HOUR: return0.0;
/* Monotonically-increasing units */ case DTK_YEAR: case DTK_DECADE: case DTK_CENTURY: case DTK_MILLENNIUM: case DTK_JULIAN: case DTK_ISOYEAR: case DTK_EPOCH: if (isNegative) return -get_float8_infinity(); else return get_float8_infinity();
default:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("unit \"%s\" not supported for type %s",
lowunits,
format_type_be(isTz ? TIMESTAMPTZOID : TIMESTAMPOID)))); return0.0; /* keep compiler quiet */
}
}
/* timestamp_part() and extract_timestamp() *Extractspecifiedfieldfromtimestamp.
*/ static Datum
timestamp_part_common(PG_FUNCTION_ARGS, bool retnumeric)
{
text *units = PG_GETARG_TEXT_PP(0);
Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
int64 intresult;
Timestamp epoch; int type,
val; char *lowunits;
fsec_t fsec; struct pg_tm tt,
*tm = &tt;
if (type == UNITS)
{ if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
if (type == UNITS)
{ if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
switch (val)
{ case DTK_TZ:
intresult = -tz; break;
case DTK_TZ_MINUTE:
intresult = (-tz / SECS_PER_MINUTE) % MINS_PER_HOUR; break;
case DTK_TZ_HOUR:
intresult = -tz / SECS_PER_HOUR; break;
case DTK_MICROSEC:
intresult = tm->tm_sec * INT64CONST(1000000) + fsec; break;
default:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("unit \"%s\" not supported for type %s",
lowunits, format_type_be(TIMESTAMPTZOID))));
intresult = 0;
}
} elseif (type == RESERV)
{ switch (val)
{ case DTK_EPOCH:
epoch = SetEpochTimestamp(); /* (timestamp - epoch) / 1000000 */ if (retnumeric)
{
Numeric result;
if (timestamp < (PG_INT64_MAX + epoch))
result = int64_div_fast_to_numeric(timestamp - epoch, 6); else
{
result = numeric_div_opt_error(numeric_sub_opt_error(int64_to_numeric(timestamp),
int64_to_numeric(epoch),
NULL),
int64_to_numeric(1000000),
NULL);
result = DatumGetNumeric(DirectFunctionCall2(numeric_round,
NumericGetDatum(result),
Int32GetDatum(6)));
}
PG_RETURN_NUMERIC(result);
} else
{
float8 result;
/* try to avoid precision loss in subtraction */ if (timestamp < (PG_INT64_MAX + epoch))
result = (timestamp - epoch) / 1000000.0; else
result = ((float8) timestamp - epoch) / 1000000.0;
PG_RETURN_FLOAT8(result);
} break;
default:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("unit \"%s\" not supported for type %s",
lowunits, format_type_be(TIMESTAMPTZOID))));
intresult = 0;
}
} else
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unit \"%s\" not recognized for type %s",
lowunits, format_type_be(TIMESTAMPTZOID))));
intresult = 0;
}
if (retnumeric)
PG_RETURN_NUMERIC(int64_to_numeric(intresult)); else
PG_RETURN_FLOAT8(intresult);
}
Datum
timestamptz_part(PG_FUNCTION_ARGS)
{ return timestamptz_part_common(fcinfo, false);
}
Datum
extract_timestamptz(PG_FUNCTION_ARGS)
{ return timestamptz_part_common(fcinfo, true);
}
/* *NonFiniteIntervalPart * *Usedbyinterval_partwhenextractingfrominfiniteinterval.Returns *+/-Infinityifthatistheappropriateresult,otherwisereturnszero *(whichshouldbetakenasmeaningtoreturnNULL). * *Errorsthrownhereforinvalidunitsshouldexactlymatchthosethat *wouldbethrowninthecallingfunctions,elsetherewillbeunexpected *discrepanciesbetweenfinite-andinfinite-inputcases.
*/ static float8
NonFiniteIntervalPart(int type, int unit, char *lowunits, bool isNegative)
{ if ((type != UNITS) && (type != RESERV))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unit \"%s\" not recognized for type %s",
lowunits, format_type_be(INTERVALOID))));
switch (unit)
{ /* Oscillating units */ case DTK_MICROSEC: case DTK_MILLISEC: case DTK_SECOND: case DTK_MINUTE: case DTK_WEEK: case DTK_MONTH: case DTK_QUARTER: return0.0;
/* Monotonically-increasing units */ case DTK_HOUR: case DTK_DAY: case DTK_YEAR: case DTK_DECADE: case DTK_CENTURY: case DTK_MILLENNIUM: case DTK_EPOCH: if (isNegative) return -get_float8_infinity(); else return get_float8_infinity();
default:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("unit \"%s\" not supported for type %s",
lowunits, format_type_be(INTERVALOID)))); return0.0; /* keep compiler quiet */
}
}
/* interval_part() and extract_interval() *Extractspecifiedfieldfrominterval.
*/ static Datum
interval_part_common(PG_FUNCTION_ARGS, bool retnumeric)
{
text *units = PG_GETARG_TEXT_PP(0);
Interval *interval = PG_GETARG_INTERVAL_P(1);
int64 intresult; int type,
val; char *lowunits; struct pg_itm tt,
*tm = &tt;
if (type == TZNAME_FIXED_OFFSET)
{ /* fixed-offset abbreviation */
tz = val;
result = dt2local(timestamp, tz);
} elseif (type == TZNAME_DYNTZ)
{ /* dynamic-offset abbreviation, resolve using specified time */ if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
tz = -DetermineTimeZoneAbbrevOffset(&tm, tzname, tzp);
result = dt2local(timestamp, tz);
} else
{ /* full zone name, rotate to that zone */ if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
tz = DetermineTimeZoneOffset(&tm, tzp); if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
}
if (!IS_VALID_TIMESTAMP(result))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
PG_RETURN_TIMESTAMPTZ(result);
}
/* timestamp_izone() *Encodetimestamptypewithspecifiedtimeintervalastimezone.
*/
Datum
timestamp_izone(PG_FUNCTION_ARGS)
{
Interval *zone = PG_GETARG_INTERVAL_P(0);
Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
TimestampTz result; int tz;
if (TIMESTAMP_NOT_FINITE(timestamp))
PG_RETURN_TIMESTAMPTZ(timestamp);
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),
errmsg("interval time zone \"%s\" must not include months or days",
DatumGetCString(DirectFunctionCall1(interval_out,
PointerGetDatum(zone))))));
tz = zone->time / USECS_PER_SEC;
result = dt2local(timestamp, tz);
if (!IS_VALID_TIMESTAMP(result))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
if (TIMESTAMP_NOT_FINITE(timestamp)) return timestamp;
/* We don't expect this to fail, but check it pro forma */ if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
{
tz = DetermineTimeZoneOffset(tm, session_timezone);
if (TIMESTAMP_NOT_FINITE(timestamp))
result = timestamp; else
{ if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range"))); if (tm2timestamp(tm, fsec, NULL, &result) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
} return result;
}
/* timestamptz_zone() *Evaluatetimestampwithtimezonetypeatthespecifiedtimezone. *Returnsatimestampwithouttimezone.
*/
Datum
timestamptz_zone(PG_FUNCTION_ARGS)
{
text *zone = PG_GETARG_TEXT_PP(0);
TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
Timestamp result; int tz; char tzname[TZ_STRLEN_MAX + 1]; int type,
val;
pg_tz *tzp;
if (TIMESTAMP_NOT_FINITE(timestamp))
PG_RETURN_TIMESTAMP(timestamp);
if (type == TZNAME_FIXED_OFFSET)
{ /* fixed-offset abbreviation */
tz = -val;
result = dt2local(timestamp, tz);
} elseif (type == TZNAME_DYNTZ)
{ /* dynamic-offset abbreviation, resolve using specified time */ int isdst;
tz = DetermineTimeZoneAbbrevOffsetTS(timestamp, tzname, tzp, &isdst);
result = dt2local(timestamp, tz);
} else
{ /* full zone name, rotate from that zone */ struct pg_tm tm;
fsec_t fsec;
if (timestamp2tm(timestamp, &tz, &tm, &fsec, NULL, tzp) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range"))); if (tm2timestamp(&tm, fsec, NULL, &result) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
}
if (!IS_VALID_TIMESTAMP(result))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
PG_RETURN_TIMESTAMP(result);
}
/* timestamptz_izone() *Encodetimestampwithtimezonetypewithspecifiedtimeintervalastimezone. *Returnsatimestampwithouttimezone.
*/
Datum
timestamptz_izone(PG_FUNCTION_ARGS)
{
Interval *zone = PG_GETARG_INTERVAL_P(0);
TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
Timestamp result; int tz;
if (TIMESTAMP_NOT_FINITE(timestamp))
PG_RETURN_TIMESTAMP(timestamp);
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),
errmsg("interval time zone \"%s\" must not include months or days",
DatumGetCString(DirectFunctionCall1(interval_out,
PointerGetDatum(zone))))));
tz = -(zone->time / USECS_PER_SEC);
result = dt2local(timestamp, tz);
if (!IS_VALID_TIMESTAMP(result))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
/* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL())
{
Timestamp start = PG_GETARG_TIMESTAMP(0);
Timestamp finish = PG_GETARG_TIMESTAMP(1);
Interval *step = PG_GETARG_INTERVAL_P(2);
MemoryContext oldcontext;
/* create a function context for cross-call persistence */
funcctx = SRF_FIRSTCALL_INIT();
/* stuff done on every call of the function */
funcctx = SRF_PERCALL_SETUP();
/* *getthesavedstateandusecurrentastheresultforthisiteration
*/
fctx = funcctx->user_fctx;
result = fctx->current;
if (fctx->step_sign > 0 ?
timestamp_cmp_internal(result, fctx->finish) <= 0 :
timestamp_cmp_internal(result, fctx->finish) >= 0)
{ /* increment current in preparation for next iteration */
fctx->current = DatumGetTimestamp(DirectFunctionCall2(timestamp_pl_interval,
TimestampGetDatum(fctx->current),
PointerGetDatum(&fctx->step)));
/* do when there is more left to send */
SRF_RETURN_NEXT(funcctx, TimestampGetDatum(result));
} else
{ /* do when there is no more left */
SRF_RETURN_DONE(funcctx);
}
}
/* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL())
{
TimestampTz start = PG_GETARG_TIMESTAMPTZ(0);
TimestampTz finish = PG_GETARG_TIMESTAMPTZ(1);
Interval *step = PG_GETARG_INTERVAL_P(2);
text *zone = (PG_NARGS() == 4) ? PG_GETARG_TEXT_PP(3) : NULL;
MemoryContext oldcontext;
/* create a function context for cross-call persistence */
funcctx = SRF_FIRSTCALL_INIT();
/* stuff done on every call of the function */
funcctx = SRF_PERCALL_SETUP();
/* *getthesavedstateandusecurrentastheresultforthisiteration
*/
fctx = funcctx->user_fctx;
result = fctx->current;
if (fctx->step_sign > 0 ?
timestamp_cmp_internal(result, fctx->finish) <= 0 :
timestamp_cmp_internal(result, fctx->finish) >= 0)
{ /* increment current in preparation for next iteration */
fctx->current = timestamptz_pl_interval_internal(fctx->current,
&fctx->step,
fctx->attimezone);
/* do when there is more left to send */
SRF_RETURN_NEXT(funcctx, TimestampTzGetDatum(result));
} else
{ /* do when there is no more left */
SRF_RETURN_DONE(funcctx);
}
}
Datum
generate_series_timestamptz(PG_FUNCTION_ARGS)
{ return generate_series_timestamptz_internal(fcinfo);
}
Datum
generate_series_timestamptz_at_zone(PG_FUNCTION_ARGS)
{ return generate_series_timestamptz_internal(fcinfo);
}
/* This equation works for either sign of step */ if (dstep != 0.0)
{
Interval *idiff = DatumGetIntervalP(diff); double ddiff = INTERVAL_TO_MICROSECONDS(idiff);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.