📄 timestamp.c
字号:
/* 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_interval() * * Adjust interval so 'month', 'day', and 'time' portions are within * customary bounds. Specifically: * * 0 <= abs(time) < 24 hours * 0 <= abs(day) < 30 days * * Also, the sign bit on all three fields is made equal, so either * all three fields are negative or all are positive. */Datuminterval_justify_interval(PG_FUNCTION_ARGS){ Interval *span = PG_GETARG_INTERVAL_P(0); Interval *result;#ifdef HAVE_INT64_TIMESTAMP int64 wholeday;#else double wholeday;#endif int32 wholemonth; 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... */ wholemonth = result->day / DAYS_PER_MONTH; result->day -= wholemonth * DAYS_PER_MONTH; result->month += wholemonth; if (result->month > 0 && (result->day < 0 || (result->day == 0 && result->time < 0))) { result->day += DAYS_PER_MONTH; result->month--; } else if (result->month < 0 && (result->day > 0 || (result->day == 0 && result->time > 0))) { result->day -= DAYS_PER_MONTH; result->month++; } if (result->day > 0 && result->time < 0) {#ifdef HAVE_INT64_TIMESTAMP result->time += USECS_PER_DAY;#else result->time += (double) SECS_PER_DAY;#endif result->day--; } else if (result->day < 0 && result->time > 0) {#ifdef HAVE_INT64_TIMESTAMP result->time -= USECS_PER_DAY;#else result->time -= (double) SECS_PER_DAY;#endif result->day++; } 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... */ if (result->day > 0 && result->time < 0) {#ifdef HAVE_INT64_TIMESTAMP result->time += USECS_PER_DAY;#else result->time += (double) SECS_PER_DAY;#endif result->day--; } else if (result->day < 0 && result->time > 0) {#ifdef HAVE_INT64_TIMESTAMP result->time -= USECS_PER_DAY;#else result->time -= (double) SECS_PER_DAY;#endif result->day++; } 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; if (result->month > 0 && result->day < 0) { result->day += DAYS_PER_MONTH; result->month--; } else if (result->month < 0 && result->day > 0) { result->day -= DAYS_PER_MONTH; result->month++; } 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, session_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, session_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);}Datumtimestamptz_mi_interval(PG_FUNCTION_ARGS){ TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0); Interval *span = PG_GETARG_INTERVAL_P(1); Interval tspan; tspan.month = -span->month; tspan.day = -span->day; tspan.time = -span->time; return DirectFunctionCall2(timestamptz_pl_interval, TimestampGetDatum(timestamp), PointerGetDatum(&tspan));}Datuminterval_um(PG_FUNCTION_ARGS){ Interval *interval = PG_GETARG_INTERVAL_P(0); Interval *result; result = (Interval *) palloc(sizeof(Interval)); result->time = -interval->time; result->day = -interval->day; result->month = -interval->month; PG_RETURN_INTERVAL_P(result);}Datuminterval_smaller(PG_FUNCTION_ARGS){ Interval *interval1 = PG_GETARG_INTERVAL_P(0); Interval *interval2 = PG_GETARG_INTERVAL_P(1); Interval *result; /* 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);}Datuminterval_larger(PG_FUNCTION_ARGS){ Interval *interval1 = PG_GETARG_INTERVAL_P(0); Interval *interval2 = PG_GETARG_INTERVAL_P(1); Interval *result; if (interval_cmp_internal(interval1, interval2) > 0) result = interval1; else result = interval2; PG_RETURN_INTERVAL_P(result);}Datuminterval_pl(PG_FUNCTION_ARGS){ Interval *span1 = PG_GETARG_INTERVAL_P(0); Interval *span2 = PG_GETARG_INTERVAL_P(1); Interval *result; result = (Interval *) palloc(sizeof(Interval)); result->month = span1->month + span2->month; result->day = span1->day + span2->day; result->time = span1->time + span2->time; PG_RETURN_INTERVAL_P(result);}Datuminterval_mi(PG_FUNCTION_ARGS){ Interval *span1 = PG_GETARG_INTERVAL_P(0); Interval *span2 = PG_GETARG_INTERVAL_P(1); Interval *result; result = (Interval *) palloc(sizeof(Interval)); result->month = span1->month - span2->month; result->day = span1->day - span2->day; result->time = span1->time - span2->ti
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -