📄 timestamp.c
字号:
PG_RETURN_INTERVAL_P(result);}/* timestamp_pl_span() * Add a interval to a timestamp 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". */Datumtimestamp_pl_span(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 tm tt, *tm = &tt; fsec_t fsec; if (timestamp2tm(timestamp, NULL, tm, &fsec, 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 > 12) { tm->tm_year += ((tm->tm_mon - 1) / 12); tm->tm_mon = (((tm->tm_mon - 1) % 12) + 1); } else if (tm->tm_mon < 1) { tm->tm_year += ((tm->tm_mon / 12) - 1); tm->tm_mon = ((tm->tm_mon % 12) + 12); } /* 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"))); } timestamp += span->time; result = timestamp; } PG_RETURN_TIMESTAMP(result);}Datumtimestamp_mi_span(PG_FUNCTION_ARGS){ Timestamp timestamp = PG_GETARG_TIMESTAMP(0); Interval *span = PG_GETARG_INTERVAL_P(1); Interval tspan; tspan.month = -span->month; tspan.time = -span->time; return DirectFunctionCall2(timestamp_pl_span, TimestampGetDatum(timestamp), PointerGetDatum(&tspan));}/* timestamptz_pl_span() * 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_span(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 tm tt, *tm = &tt; fsec_t fsec; if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); tm->tm_mon += span->month; if (tm->tm_mon > 12) { tm->tm_year += ((tm->tm_mon - 1) / 12); tm->tm_mon = (((tm->tm_mon - 1) % 12) + 1); } else if (tm->tm_mon < 1) { tm->tm_year += ((tm->tm_mon / 12) - 1); tm->tm_mon = ((tm->tm_mon % 12) + 12); } /* 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 = DetermineLocalTimeZone(tm); 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_span(PG_FUNCTION_ARGS){ TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0); Interval *span = PG_GETARG_INTERVAL_P(1); Interval tspan; tspan.month = -span->month; tspan.time = -span->time; return DirectFunctionCall2(timestamptz_pl_span, 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->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);#ifdef HAVE_INT64_TIMESTAMP result->time = (span1->time + span2->time);#else result->time = JROUND(span1->time + span2->time);#endif 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);#ifdef HAVE_INT64_TIMESTAMP result->time = (span1->time - span2->time);#else result->time = JROUND(span1->time - span2->time);#endif PG_RETURN_INTERVAL_P(result);}Datuminterval_mul(PG_FUNCTION_ARGS){ Interval *span1 = PG_GETARG_INTERVAL_P(0); float8 factor = PG_GETARG_FLOAT8(1); Interval *result;#ifdef HAVE_INT64_TIMESTAMP int64 months;#else double months;#endif result = (Interval *) palloc(sizeof(Interval)); months = (span1->month * factor);#ifdef HAVE_INT64_TIMESTAMP result->month = months; result->time = (span1->time * factor); result->time += ((months - result->month) * INT64CONST(30) * INT64CONST(86400000000));#else result->month = rint(months); result->time = JROUND(span1->time * factor); /* evaluate fractional months as 30 days */ result->time += JROUND((months - result->month) * 30 * 86400);#endif PG_RETURN_INTERVAL_P(result);}Datummul_d_interval(PG_FUNCTION_ARGS){ /* Args are float8 and Interval *, but leave them as generic Datum */ Datum factor = PG_GETARG_DATUM(0); Datum span1 = PG_GETARG_DATUM(1); return DirectFunctionCall2(interval_mul, span1, factor);}Datuminterval_div(PG_FUNCTION_ARGS){ Interval *span = PG_GETARG_INTERVAL_P(0); float8 factor = PG_GETARG_FLOAT8(1); Interval *result;#ifndef HAVE_INT64_TIMESTAMP double months;#endif result = (Interval *) palloc(sizeof(Interval)); if (factor == 0.0) ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg("division by zero")));#ifdef HAVE_INT64_TIMESTAMP result->month = (span->month / factor); result->time = (span->time / factor); /* evaluate fractional months as 30 days */ result->time += (((span->month - (result->month * factor)) * INT64CONST(30) * INT64CONST(86400000000)) / factor);#else months = (span->month / factor); result->month = rint(months); result->time = JROUND(span->time / factor); /* evaluate fractional months as 30 days */ result->time += JROUND((months - result->month) * 30 * 86400);#endif PG_RETURN_INTERVAL_P(result);}/* * interval_accum and interval_avg implement the AVG(interval) aggregate. * * The transition datatype for this aggregate is a 2-element array of * intervals, where the first is the running sum and the second contains * the number of values so far in its 'time' field. This is a bit ugly * but it beats inventing a specialized datatype for the purpose. */Datuminterval_accum(PG_FUNCTION_ARGS){ ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); Interval *newval = PG_GETARG_INTERVAL_P(1); Datum *transdatums; int ndatums; Interval sumX, N; Interval *newsum; ArrayType *result; /* We assume the input is array of interval */ deconstruct_array(transarray, INTERVALOID, 12, false, 'd', &transdatums, &ndatums); if (ndatums != 2) elog(ERROR, "expected 2-element interval array"); /* * XXX memcpy, instead of just extracting a pointer, to work around * buggy array code: it won't ensure proper alignment of Interval * objects on machines where double requires 8-byte alignment. That * should be fixed, but in the meantime... * * Note: must use DatumGetPointer here, not DatumGetIntervalP, else some * compilers optimize into double-aligned load/store anyway. */ memcpy((void *) &sumX, DatumGetPointer(transdatums[0]), sizeof(Interval)); memcpy((void *) &N, DatumGetPointer(transdatums[1]), sizeof(Interval)); newsum = DatumGetIntervalP(DirectFunctionCall2(interval_pl, IntervalPGetDatum(&sumX), IntervalPGetDatum(newval))); N.time += 1; transdatums[0] = IntervalPGetDatum(newsum); transdatums[1] = IntervalPGetDatum(&N); result = construct_array(transdatums, 2, INTERVALOID, 12, false, 'd'); PG_RETURN_ARRAYTYPE_P(result);}Datuminterval_avg(PG_FUNCTION_ARGS){ ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); Datum *transdatums; int ndatums; Interval sumX, N; /* We assume the input is array of interval */ deconstruct_array(transarray, INTERVALOID, 12, false, 'd', &transdatums, &ndatums); if (ndatums != 2) elog(ERROR, "expected 2-element interval array"); /* * XXX memcpy, instead of just extracting a pointer, to work around * buggy array code: it won't ensure proper alignment of Interval * objects on machines where double requires 8-byte alignment. That * should be fixed, but in the meantime... * * Note: must use DatumGetPointer here, not DatumGetIntervalP, else some * compilers optimize into double-aligned load/store anyway. */ memcpy((void *) &sumX, DatumGetPointer(transdatums[0]), sizeof(Interval)); memcpy((void *) &N, DatumGetPointer(transdatums[1]), sizeof(Interval)); /* SQL92 defines AVG of no values to be NULL */ if (N.time == 0) PG_RETURN_NULL(); return DirectFunctionCall2(interval_div, IntervalPGetDatum(&sumX), Float8GetDatum(N.time));}/* timestamp_age() * Calculate time difference while retaining year/month fields. * Note that this does not result in an accurate absolute time span * since year and month are out of context once the arithmetic * is done. */Datumtimestamp_age(PG_FUNCTION_ARGS){ Timestamp dt1 = PG_GETARG_TIMESTAMP(0); Timestamp dt2 = PG_GETARG_TIMESTAMP(1); Interval *result; fsec_t fsec, fsec1, fsec2; struct tm tt, *tm = &tt; struct tm tt1, *tm1 = &tt1; struct tm tt2, *tm2 = &tt2; result = (Interval *) palloc(sizeof(Interval)); if ((timestamp2tm(dt1, NULL, tm1, &fsec1, NULL) == 0) && (timestamp2tm(dt2, NULL, tm2, &fsec2, NULL) == 0)) { fsec = (fsec1 - fsec2); tm->tm_sec = (tm1->tm_sec - tm2->tm_sec); tm->tm_min = (tm1->tm_min - tm2->tm_min); tm->tm_hour = (tm1->tm_hour - tm2->tm_hour); tm->tm_mday = (tm1->tm_mday - tm2->tm_mday); tm->tm_mon = (tm1->tm_mon - tm2->tm_mon); tm->tm_year = (tm1->tm_year - tm2->tm_year); /* flip sign if necessary... */ if (dt1 < dt2) { fsec = -fsec; tm->tm_sec = -tm->tm_sec; tm->tm_min = -tm->tm_min; tm->tm_hour = -tm->tm_hour; tm->tm_mday = -tm->tm_mday; tm->tm_mon = -tm->tm_mon; tm->tm_year = -tm->tm_year; } if (tm->tm_sec < 0) { tm->tm_sec += 60; tm->tm_min--; } if (tm->tm_min < 0) { tm->tm_min += 60; tm->tm_hour--; } if (tm->tm_hour < 0) { tm->tm_hour += 24; tm->tm_mday--; } if (tm->tm_mday < 0) { if (dt1 < dt2) { tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1]; tm->tm_mon--; } else { tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1]; tm->tm_mon--; } } if (tm->tm_mon < 0) { tm->tm_mon += 12; tm->tm_year--; } /* recover sign if necessary... */ if (dt1 < dt2) { fsec = -fsec; tm->tm_sec = -tm->tm_sec; tm->tm_min = -tm->tm_min; tm->tm_hour = -tm->tm_hour; tm->tm_mday = -tm->tm_mday; tm->tm_mon = -tm->tm_mon; tm->tm_year = -tm->tm_year; } if (tm2interval(tm, fsec, result) != 0) 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"))); PG_RETURN_INTERVAL_P(result);}/* timestamptz_age() * Calculate time difference while retaining year/month fields. * Note that this does not result in an accurate absolute time span * since year and month are out of context once the arithmetic * is done. */Datumtimestamptz_age(PG_FUNCTION_ARGS){ TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0); TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1); Interval *result; fsec_t fsec, fsec1, fsec2; struct tm tt, *tm = &tt; struct tm tt1, *tm1 = &tt1; struct tm tt2, *tm2 = &tt2; result = (Interval *) palloc(sizeof(Interval)); if ((timestamp2tm(dt1, NULL, tm1, &fsec1, NULL) == 0) && (timestamp2tm(dt2, NULL, tm2, &fsec2, NULL) == 0)) { fsec = (fsec1 - fsec2); tm->tm_sec = (tm1->tm_sec - tm2->tm_sec); tm->tm_min = (tm1->tm_min - tm2->tm_min); tm->tm_hour = (tm1->tm_hour - tm2->tm_hour); tm->tm_mday = (tm1->tm_mday - tm2->tm_mday); tm->tm_mon = (tm1->tm_mon - tm2->tm_mon); tm->tm_year = (tm1->tm_year - tm2->tm_year); /* flip sign if necessary... */ if (dt1 < dt2) { fsec = -fsec; tm->tm_sec = -tm->tm_sec; tm->tm_min = -tm->tm_min; tm->tm_hour = -tm->tm_hour; tm->tm_mday = -tm->tm_mday; tm->tm_mon = -tm->tm_mon; tm->tm_year = -tm->tm_year;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -