📄 timestamp.c
字号:
#else double span1, span2;#endif span1 = interval1->time; span2 = interval2->time;#ifdef HAVE_INT64_TIMESTAMP span1 += interval1->month * INT64CONST(30) * USECS_PER_DAY; span1 += interval1->day * INT64CONST(24) * USECS_PER_HOUR; span2 += interval2->month * INT64CONST(30) * USECS_PER_DAY; span2 += interval2->day * INT64CONST(24) * USECS_PER_HOUR;#else span1 += interval1->month * ((double) DAYS_PER_MONTH * SECS_PER_DAY); span1 += interval1->day * ((double) HOURS_PER_DAY * SECS_PER_HOUR); span2 += interval2->month * ((double) DAYS_PER_MONTH * SECS_PER_DAY); span2 += interval2->day * ((double) HOURS_PER_DAY * SECS_PER_HOUR);#endif return ((span1 < span2) ? -1 : (span1 > span2) ? 1 : 0);}Datuminterval_eq(PG_FUNCTION_ARGS){ Interval *interval1 = PG_GETARG_INTERVAL_P(0); Interval *interval2 = PG_GETARG_INTERVAL_P(1); PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) == 0);}Datuminterval_ne(PG_FUNCTION_ARGS){ Interval *interval1 = PG_GETARG_INTERVAL_P(0); Interval *interval2 = PG_GETARG_INTERVAL_P(1); PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) != 0);}Datuminterval_lt(PG_FUNCTION_ARGS){ Interval *interval1 = PG_GETARG_INTERVAL_P(0); Interval *interval2 = PG_GETARG_INTERVAL_P(1); PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) < 0);}Datuminterval_gt(PG_FUNCTION_ARGS){ Interval *interval1 = PG_GETARG_INTERVAL_P(0); Interval *interval2 = PG_GETARG_INTERVAL_P(1); PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) > 0);}Datuminterval_le(PG_FUNCTION_ARGS){ Interval *interval1 = PG_GETARG_INTERVAL_P(0); Interval *interval2 = PG_GETARG_INTERVAL_P(1); PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) <= 0);}Datuminterval_ge(PG_FUNCTION_ARGS){ Interval *interval1 = PG_GETARG_INTERVAL_P(0); Interval *interval2 = PG_GETARG_INTERVAL_P(1); PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) >= 0);}Datuminterval_cmp(PG_FUNCTION_ARGS){ Interval *interval1 = PG_GETARG_INTERVAL_P(0); Interval *interval2 = PG_GETARG_INTERVAL_P(1); PG_RETURN_INT32(interval_cmp_internal(interval1, interval2));}/* * interval, being an unusual size, needs a specialized hash function. */Datuminterval_hash(PG_FUNCTION_ARGS){ Interval *key = PG_GETARG_INTERVAL_P(0); /* * Specify hash length as sizeof(double) + sizeof(int4), not as * sizeof(Interval), so that any garbage pad bytes in the structure won't * be included in the hash! */ return hash_any((unsigned char *) key, sizeof(key->time) + sizeof(key->day) + sizeof(key->month));}/* overlaps_timestamp() --- implements the SQL92 OVERLAPS operator. * * Algorithm is per SQL92 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. */Datumoverlaps_timestamp(PG_FUNCTION_ARGS){ /* * The arguments are Timestamps, but we leave them as generic Datums to * avoid unnecessary conversions between value and reference forms --- not * to mention possible dereferences of null pointers. */ 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 TIMESTAMP_GT(t1,t2) \ DatumGetBool(DirectFunctionCall2(timestamp_gt,t1,t2))#define TIMESTAMP_LT(t1,t2) \ DatumGetBool(DirectFunctionCall2(timestamp_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 (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; } else if (!te2IsNull) { if (TIMESTAMP_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 (TIMESTAMP_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 (TIMESTAMP_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 (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(); /* * 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 TIMESTAMP_GT#undef TIMESTAMP_LT}/*---------------------------------------------------------- * "Arithmetic" operators on date/times. *---------------------------------------------------------*/Datumtimestamp_smaller(PG_FUNCTION_ARGS){ Timestamp dt1 = PG_GETARG_TIMESTAMP(0); Timestamp dt2 = PG_GETARG_TIMESTAMP(1); Timestamp result; /* 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);}Datumtimestamp_larger(PG_FUNCTION_ARGS){ Timestamp dt1 = PG_GETARG_TIMESTAMP(0); Timestamp dt2 = PG_GETARG_TIMESTAMP(1); Timestamp result; if (timestamp_cmp_internal(dt1, dt2) > 0) result = dt1; else result = dt2; PG_RETURN_TIMESTAMP(result);}Datumtimestamp_mi(PG_FUNCTION_ARGS){ Timestamp dt1 = PG_GETARG_TIMESTAMP(0); Timestamp dt2 = PG_GETARG_TIMESTAMP(1); Interval *result; result = (Interval *) palloc(sizeof(Interval)); if (TIMESTAMP_NOT_FINITE(dt1) || TIMESTAMP_NOT_FINITE(dt2)) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("cannot subtract infinite timestamps"))); result->time = dt1 - dt2; result->month = 0; result->day = 0; /* * This is wrong, but removing it breaks a lot of regression tests. For * example: * * test=> SET timezone = 'EST5EDT'; test=> SELECT test-> ('2005-10-30 * 13:22:00-05'::timestamptz - test(> '2005-10-29 * 13:22:00-04'::timestamptz); ?column? ---------------- 1 day 01:00:00 (1 * row) * * so adding that to the first timestamp gets: * * test=> SELECT test-> ('2005-10-29 13:22:00-04'::timestamptz + test(> * ('2005-10-30 13:22:00-05'::timestamptz - test(> '2005-10-29 * 13:22:00-04'::timestamptz)) at time zone 'EST'; timezone * -------------------- 2005-10-30 14:22:00 (1 row) */ result = DatumGetIntervalP(DirectFunctionCall1(interval_justify_hours, IntervalPGetDatum(result))); PG_RETURN_INTERVAL_P(result);}/* * interval_justify_hours() * * Adjust interval so 'time' contains less than a whole day, adding * the excess to 'day'. This is useful for * situations (such as non-TZ) where '1 day' = '24 hours' is valid, * e.g. interval subtraction and division. */Datuminterval_justify_hours(PG_FUNCTION_ARGS){ Interval *span = PG_GETARG_INTERVAL_P(0); Interval *result;#ifdef HAVE_INT64_TIMESTAMP int64 wholeday;#else double wholeday;#endif result = (Interval *) palloc(sizeof(Interval)); result->month = span->month; result->day = span->day; result->time = span->time;#ifdef HAVE_INT64_TIMESTAMP TMODULO(result->time, wholeday, USECS_PER_DAY);#else TMODULO(result->time, wholeday, (double) SECS_PER_DAY);#endif result->day += wholeday; /* could overflow... */ PG_RETURN_INTERVAL_P(result);}/* * interval_justify_days() * * Adjust interval so 'day' contains less than 30 days, adding * the excess to 'month'. */Datuminterval_justify_days(PG_FUNCTION_ARGS){ Interval *span = PG_GETARG_INTERVAL_P(0); Interval *result; int32 wholemonth; result = (Interval *) palloc(sizeof(Interval)); result->month = span->month; result->day = span->day; result->time = span->time; wholemonth = result->day / DAYS_PER_MONTH; result->day -= wholemonth * DAYS_PER_MONTH; result->month += wholemonth; PG_RETURN_INTERVAL_P(result);}/* timestamp_pl_interval() * Add a interval to a timestamp data type. * Note that interval has provisions for qualitative year/month and day * units, so try to do the right thing with them. * To add a month, increment the month, and use the same day of month. * Then, if the next month has fewer days, set the day of month * to the last day of month. * To add a day, increment the mday, and use the same time of day. * Lastly, add in the "quantitative time". */Datumtimestamp_pl_interval(PG_FUNCTION_ARGS){ Timestamp timestamp = PG_GETARG_TIMESTAMP(0); Interval *span = PG_GETARG_INTERVAL_P(1); Timestamp result; if (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"))); tm->tm_mon += span->month; if (tm->tm_mon > MONTHS_PER_YEAR) { tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR; tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1; } else if (tm->tm_mon < 1) { tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1; tm->tm_mon = tm->tm_mon % MONTHS_PER_YEAR + MONTHS_PER_YEAR; } /* 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"))); /* Add days by converting to and from julian */ julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + span->day; 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"))); } timestamp += span->time; result = timestamp; } PG_RETURN_TIMESTAMP(result);}Datumtimestamp_mi_interval(PG_FUNCTION_ARGS){ Timestamp timestamp = PG_GETARG_TIMESTAMP(0); Interval *span = PG_GETARG_INTERVAL_P(1); Interval tspan; tspan.month = -span->month; tspan.day = -span->day; tspan.time = -span->time; return DirectFunctionCall2(timestamp_pl_interval, TimestampGetDatum(timestamp), PointerGetDatum(&tspan));}/* timestamptz_pl_interval() * Add a interval to a timestamp with time zone data type. * Note that interval has provisions for qualitative year/month * units, so try to do the right thing with them. * To add a month, increment the month, and use the same day of month. * Then, if the next month has fewer days, set the day of month * to the last day of month. * Lastly, add in the "quantitative time". */Datumtimestamptz_pl_interval(PG_FUNCTION_ARGS){ TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0); Interval *span = PG_GETARG_INTERVAL_P(1); TimestampTz result; int tz; char *tzn; if (TIMESTAMP_NOT_FINITE(timestamp)) result = timestamp; else { if (span->month != 0) { struct pg_tm tt, *tm = &tt; fsec_t fsec; if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); tm->tm_mon += span->month; if (tm->tm_mon > MONTHS_PER_YEAR) { tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR; tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1; } else if (tm->tm_mon < 1) { tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1; tm->tm_mon = tm->tm_mon % MONTHS_PER_YEAR + MONTHS_PER_YEAR; } /* 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, global_timezone); 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, &tzn, NULL) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); /* Add days by converting to and from julian */ julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + span->day; j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); tz = DetermineTimeZoneOffset(tm, global_timezone); if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); } timestamp += span->time; result = timestamp; } PG_RETURN_TIMESTAMP(result);}Datum
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -