📄 timestamp.c
字号:
timestamptz_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->time; PG_RETURN_INTERVAL_P(result);}Datuminterval_mul(PG_FUNCTION_ARGS){ Interval *span = PG_GETARG_INTERVAL_P(0); float8 factor = PG_GETARG_FLOAT8(1); double month_remainder, day_remainder, month_remainder_days; Interval *result; result = (Interval *) palloc(sizeof(Interval)); month_remainder = span->month * factor; day_remainder = span->day * factor; result->month = (int32) month_remainder; result->day = (int32) day_remainder; month_remainder -= result->month; day_remainder -= result->day; /* * The above correctly handles the whole-number part of the month and day * products, but we have to do something with any fractional part * resulting when the factor is nonintegral. We cascade the fractions * down to lower units using the conversion factors DAYS_PER_MONTH and * SECS_PER_DAY. Note we do NOT cascade up, since we are not forced to do * so by the representation. The user can choose to cascade up later, * using justify_hours and/or justify_days. */ /* fractional months full days into days */ month_remainder_days = month_remainder * DAYS_PER_MONTH; result->day += (int32) month_remainder_days; /* fractional months partial days into time */ day_remainder += month_remainder_days - (int32) month_remainder_days;#ifdef HAVE_INT64_TIMESTAMP result->time = rint(span->time * factor + day_remainder * USECS_PER_DAY);#else result->time = span->time * factor + day_remainder * SECS_PER_DAY;#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 span = PG_GETARG_DATUM(1); return DirectFunctionCall2(interval_mul, span, factor);}Datuminterval_div(PG_FUNCTION_ARGS){ Interval *span = PG_GETARG_INTERVAL_P(0); float8 factor = PG_GETARG_FLOAT8(1); double month_remainder, day_remainder, month_remainder_days; Interval *result; result = (Interval *) palloc(sizeof(Interval)); if (factor == 0.0) ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg("division by zero"))); month_remainder = span->month / factor; day_remainder = span->day / factor; result->month = (int32) month_remainder; result->day = (int32) day_remainder; month_remainder -= result->month; day_remainder -= result->day; /* * Handle any fractional parts the same way as in interval_mul. */ /* fractional months full days into days */ month_remainder_days = month_remainder * DAYS_PER_MONTH; result->day += (int32) month_remainder_days; /* fractional months partial days into time */ day_remainder += month_remainder_days - (int32) month_remainder_days;#ifdef HAVE_INT64_TIMESTAMP result->time = rint(span->time / factor + day_remainder * USECS_PER_DAY);#else result->time = span->time / factor + day_remainder * SECS_PER_DAY;#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; deconstruct_array(transarray, INTERVALOID, sizeof(Interval), 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, sizeof(Interval), 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; deconstruct_array(transarray, INTERVALOID, sizeof(Interval), 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 pg_tm tt, *tm = &tt; struct pg_tm tt1, *tm1 = &tt1; struct pg_tm tt2, *tm2 = &tt2; result = (Interval *) palloc(sizeof(Interval)); if (timestamp2tm(dt1, NULL, tm1, &fsec1, NULL, NULL) == 0 && timestamp2tm(dt2, NULL, tm2, &fsec2, NULL, 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; } while (tm->tm_sec < 0) { tm->tm_sec += SECS_PER_MINUTE; tm->tm_min--; } while (tm->tm_min < 0) { tm->tm_min += MINS_PER_HOUR; tm->tm_hour--; } while (tm->tm_hour < 0) { tm->tm_hour += HOURS_PER_DAY; tm->tm_mday--; } while (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--; } } while (tm->tm_mon < 0) { tm->tm_mon += MONTHS_PER_YEAR; 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 pg_tm tt, *tm = &tt; struct pg_tm tt1, *tm1 = &tt1; struct pg_tm tt2, *tm2 = &tt2; int tz1; int tz2; char *tzn; result = (Interval *) palloc(sizeof(Interval)); if (timestamp2tm(dt1, &tz1, tm1, &fsec1, &tzn, NULL) == 0 && timestamp2tm(dt2, &tz2, tm2, &fsec2, &tzn, 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; } while (tm->tm_sec < 0) { tm->tm_sec += SECS_PER_MINUTE; tm->tm_min--; } while (tm->tm_min < 0) { tm->tm_min += MINS_PER_HOUR; tm->tm_hour--; } while (tm->tm_hour < 0) { tm->tm_hour += HOURS_PER_DAY; tm->tm_mday--; } while (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--; } } while (tm->tm_mon < 0) { tm->tm_mon += MONTHS_PER_YEAR; tm->tm_year--; } /* * Note: we deliberately ignore any difference between tz1 and tz2. */ /* 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);}/*---------------------------------------------------------- * Conversion operators. *---------------------------------------------------------*//* timestamp_text() * Convert timestamp to text data type. */Datumtimestamp_text(PG_FUNCTION_ARGS){ /* Input is a Timestamp, but may as well leave it in Datum form */ Datum timestamp = PG_GETARG_DATUM(0); text *result; char *str; int len; str = DatumGetCString(DirectFunctionCall1(timestamp_out, timestamp)); len = (strlen(str) + VARHDRSZ); result = palloc(len); VARATT_SIZEP(result) = len; memmove(VARDATA(result), str, len - VARHDRSZ); pfree(str); PG_RETURN_TEXT_P(result);}/* text_timestamp() * Convert text string to timestamp. * Text type is not null terminated, so use temporary string * then call the standard input routine. */Datumtext_timestamp(PG_FUNCTION_ARGS){ text *str = PG_GETARG_TEXT_P(0); int i; char *sp, *dp
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -