00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "postgres.h"
00017
00018 #include <ctype.h>
00019 #include <math.h>
00020 #include <float.h>
00021 #include <limits.h>
00022 #include <sys/time.h>
00023
00024 #include "access/hash.h"
00025 #include "access/xact.h"
00026 #include "catalog/pg_type.h"
00027 #include "funcapi.h"
00028 #include "libpq/pqformat.h"
00029 #include "miscadmin.h"
00030 #include "nodes/nodeFuncs.h"
00031 #include "parser/scansup.h"
00032 #include "utils/array.h"
00033 #include "utils/builtins.h"
00034 #include "utils/datetime.h"
00035
00036
00037
00038
00039
00040 #ifdef __FAST_MATH__
00041 #error -ffast-math is known to break this code
00042 #endif
00043
00044
00045
00046 TimestampTz PgStartTime;
00047
00048
00049 TimestampTz PgReloadTime;
00050
00051 typedef struct
00052 {
00053 Timestamp current;
00054 Timestamp finish;
00055 Interval step;
00056 int step_sign;
00057 } generate_series_timestamp_fctx;
00058
00059 typedef struct
00060 {
00061 TimestampTz current;
00062 TimestampTz finish;
00063 Interval step;
00064 int step_sign;
00065 } generate_series_timestamptz_fctx;
00066
00067
00068 static TimeOffset time2t(const int hour, const int min, const int sec, const fsec_t fsec);
00069 static void EncodeSpecialTimestamp(Timestamp dt, char *str);
00070 static Timestamp dt2local(Timestamp dt, int timezone);
00071 static void AdjustTimestampForTypmod(Timestamp *time, int32 typmod);
00072 static void AdjustIntervalForTypmod(Interval *interval, int32 typmod);
00073 static TimestampTz timestamp2timestamptz(Timestamp timestamp);
00074
00075
00076
00077 static int32
00078 anytimestamp_typmodin(bool istz, ArrayType *ta)
00079 {
00080 int32 typmod;
00081 int32 *tl;
00082 int n;
00083
00084 tl = ArrayGetIntegerTypmods(ta, &n);
00085
00086
00087
00088
00089
00090 if (n != 1)
00091 ereport(ERROR,
00092 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00093 errmsg("invalid type modifier")));
00094
00095 if (*tl < 0)
00096 ereport(ERROR,
00097 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00098 errmsg("TIMESTAMP(%d)%s precision must not be negative",
00099 *tl, (istz ? " WITH TIME ZONE" : ""))));
00100 if (*tl > MAX_TIMESTAMP_PRECISION)
00101 {
00102 ereport(WARNING,
00103 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00104 errmsg("TIMESTAMP(%d)%s precision reduced to maximum allowed, %d",
00105 *tl, (istz ? " WITH TIME ZONE" : ""),
00106 MAX_TIMESTAMP_PRECISION)));
00107 typmod = MAX_TIMESTAMP_PRECISION;
00108 }
00109 else
00110 typmod = *tl;
00111
00112 return typmod;
00113 }
00114
00115
00116 static char *
00117 anytimestamp_typmodout(bool istz, int32 typmod)
00118 {
00119 char *res = (char *) palloc(64);
00120 const char *tz = istz ? " with time zone" : " without time zone";
00121
00122 if (typmod >= 0)
00123 snprintf(res, 64, "(%d)%s", (int) typmod, tz);
00124 else
00125 snprintf(res, 64, "%s", tz);
00126
00127 return res;
00128 }
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138 Datum
00139 timestamp_in(PG_FUNCTION_ARGS)
00140 {
00141 char *str = PG_GETARG_CSTRING(0);
00142
00143 #ifdef NOT_USED
00144 Oid typelem = PG_GETARG_OID(1);
00145 #endif
00146 int32 typmod = PG_GETARG_INT32(2);
00147 Timestamp result;
00148 fsec_t fsec;
00149 struct pg_tm tt,
00150 *tm = &tt;
00151 int tz;
00152 int dtype;
00153 int nf;
00154 int dterr;
00155 char *field[MAXDATEFIELDS];
00156 int ftype[MAXDATEFIELDS];
00157 char workbuf[MAXDATELEN + MAXDATEFIELDS];
00158
00159 dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
00160 field, ftype, MAXDATEFIELDS, &nf);
00161 if (dterr == 0)
00162 dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
00163 if (dterr != 0)
00164 DateTimeParseError(dterr, str, "timestamp");
00165
00166 switch (dtype)
00167 {
00168 case DTK_DATE:
00169 if (tm2timestamp(tm, fsec, NULL, &result) != 0)
00170 ereport(ERROR,
00171 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
00172 errmsg("timestamp out of range: \"%s\"", str)));
00173 break;
00174
00175 case DTK_EPOCH:
00176 result = SetEpochTimestamp();
00177 break;
00178
00179 case DTK_LATE:
00180 TIMESTAMP_NOEND(result);
00181 break;
00182
00183 case DTK_EARLY:
00184 TIMESTAMP_NOBEGIN(result);
00185 break;
00186
00187 case DTK_INVALID:
00188 ereport(ERROR,
00189 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00190 errmsg("date/time value \"%s\" is no longer supported", str)));
00191
00192 TIMESTAMP_NOEND(result);
00193 break;
00194
00195 default:
00196 elog(ERROR, "unexpected dtype %d while parsing timestamp \"%s\"",
00197 dtype, str);
00198 TIMESTAMP_NOEND(result);
00199 }
00200
00201 AdjustTimestampForTypmod(&result, typmod);
00202
00203 PG_RETURN_TIMESTAMP(result);
00204 }
00205
00206
00207
00208
00209 Datum
00210 timestamp_out(PG_FUNCTION_ARGS)
00211 {
00212 Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
00213 char *result;
00214 struct pg_tm tt,
00215 *tm = &tt;
00216 fsec_t fsec;
00217 char buf[MAXDATELEN + 1];
00218
00219 if (TIMESTAMP_NOT_FINITE(timestamp))
00220 EncodeSpecialTimestamp(timestamp, buf);
00221 else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
00222 EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf);
00223 else
00224 ereport(ERROR,
00225 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
00226 errmsg("timestamp out of range")));
00227
00228 result = pstrdup(buf);
00229 PG_RETURN_CSTRING(result);
00230 }
00231
00232
00233
00234
00235
00236
00237
00238 Datum
00239 timestamp_recv(PG_FUNCTION_ARGS)
00240 {
00241 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
00242
00243 #ifdef NOT_USED
00244 Oid typelem = PG_GETARG_OID(1);
00245 #endif
00246 int32 typmod = PG_GETARG_INT32(2);
00247 Timestamp timestamp;
00248 struct pg_tm tt,
00249 *tm = &tt;
00250 fsec_t fsec;
00251
00252 #ifdef HAVE_INT64_TIMESTAMP
00253 timestamp = (Timestamp) pq_getmsgint64(buf);
00254 #else
00255 timestamp = (Timestamp) pq_getmsgfloat8(buf);
00256
00257 if (isnan(timestamp))
00258 ereport(ERROR,
00259 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
00260 errmsg("timestamp cannot be NaN")));
00261 #endif
00262
00263
00264 if (TIMESTAMP_NOT_FINITE(timestamp))
00265 ;
00266 else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
00267 ereport(ERROR,
00268 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
00269 errmsg("timestamp out of range")));
00270
00271 AdjustTimestampForTypmod(×tamp, typmod);
00272
00273 PG_RETURN_TIMESTAMP(timestamp);
00274 }
00275
00276
00277
00278
00279 Datum
00280 timestamp_send(PG_FUNCTION_ARGS)
00281 {
00282 Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
00283 StringInfoData buf;
00284
00285 pq_begintypsend(&buf);
00286 #ifdef HAVE_INT64_TIMESTAMP
00287 pq_sendint64(&buf, timestamp);
00288 #else
00289 pq_sendfloat8(&buf, timestamp);
00290 #endif
00291 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
00292 }
00293
00294 Datum
00295 timestamptypmodin(PG_FUNCTION_ARGS)
00296 {
00297 ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
00298
00299 PG_RETURN_INT32(anytimestamp_typmodin(false, ta));
00300 }
00301
00302 Datum
00303 timestamptypmodout(PG_FUNCTION_ARGS)
00304 {
00305 int32 typmod = PG_GETARG_INT32(0);
00306
00307 PG_RETURN_CSTRING(anytimestamp_typmodout(false, typmod));
00308 }
00309
00310
00311
00312
00313
00314
00315 Datum
00316 timestamp_transform(PG_FUNCTION_ARGS)
00317 {
00318 PG_RETURN_POINTER(TemporalTransform(MAX_TIMESTAMP_PRECISION,
00319 (Node *) PG_GETARG_POINTER(0)));
00320 }
00321
00322
00323
00324
00325
00326 Datum
00327 timestamp_scale(PG_FUNCTION_ARGS)
00328 {
00329 Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
00330 int32 typmod = PG_GETARG_INT32(1);
00331 Timestamp result;
00332
00333 result = timestamp;
00334
00335 AdjustTimestampForTypmod(&result, typmod);
00336
00337 PG_RETURN_TIMESTAMP(result);
00338 }
00339
00340 static void
00341 AdjustTimestampForTypmod(Timestamp *time, int32 typmod)
00342 {
00343 #ifdef HAVE_INT64_TIMESTAMP
00344 static const int64 TimestampScales[MAX_TIMESTAMP_PRECISION + 1] = {
00345 INT64CONST(1000000),
00346 INT64CONST(100000),
00347 INT64CONST(10000),
00348 INT64CONST(1000),
00349 INT64CONST(100),
00350 INT64CONST(10),
00351 INT64CONST(1)
00352 };
00353
00354 static const int64 TimestampOffsets[MAX_TIMESTAMP_PRECISION + 1] = {
00355 INT64CONST(500000),
00356 INT64CONST(50000),
00357 INT64CONST(5000),
00358 INT64CONST(500),
00359 INT64CONST(50),
00360 INT64CONST(5),
00361 INT64CONST(0)
00362 };
00363 #else
00364 static const double TimestampScales[MAX_TIMESTAMP_PRECISION + 1] = {
00365 1,
00366 10,
00367 100,
00368 1000,
00369 10000,
00370 100000,
00371 1000000
00372 };
00373 #endif
00374
00375 if (!TIMESTAMP_NOT_FINITE(*time)
00376 && (typmod != -1) && (typmod != MAX_TIMESTAMP_PRECISION))
00377 {
00378 if (typmod < 0 || typmod > MAX_TIMESTAMP_PRECISION)
00379 ereport(ERROR,
00380 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00381 errmsg("timestamp(%d) precision must be between %d and %d",
00382 typmod, 0, MAX_TIMESTAMP_PRECISION)));
00383
00384
00385
00386
00387
00388
00389
00390
00391 #ifdef HAVE_INT64_TIMESTAMP
00392 if (*time >= INT64CONST(0))
00393 {
00394 *time = ((*time + TimestampOffsets[typmod]) / TimestampScales[typmod]) *
00395 TimestampScales[typmod];
00396 }
00397 else
00398 {
00399 *time = -((((-*time) + TimestampOffsets[typmod]) / TimestampScales[typmod])
00400 * TimestampScales[typmod]);
00401 }
00402 #else
00403 *time = rint((double) *time * TimestampScales[typmod]) / TimestampScales[typmod];
00404 #endif
00405 }
00406 }
00407
00408
00409
00410
00411
00412 Datum
00413 timestamptz_in(PG_FUNCTION_ARGS)
00414 {
00415 char *str = PG_GETARG_CSTRING(0);
00416
00417 #ifdef NOT_USED
00418 Oid typelem = PG_GETARG_OID(1);
00419 #endif
00420 int32 typmod = PG_GETARG_INT32(2);
00421 TimestampTz result;
00422 fsec_t fsec;
00423 struct pg_tm tt,
00424 *tm = &tt;
00425 int tz;
00426 int dtype;
00427 int nf;
00428 int dterr;
00429 char *field[MAXDATEFIELDS];
00430 int ftype[MAXDATEFIELDS];
00431 char workbuf[MAXDATELEN + MAXDATEFIELDS];
00432
00433 dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
00434 field, ftype, MAXDATEFIELDS, &nf);
00435 if (dterr == 0)
00436 dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
00437 if (dterr != 0)
00438 DateTimeParseError(dterr, str, "timestamp with time zone");
00439
00440 switch (dtype)
00441 {
00442 case DTK_DATE:
00443 if (tm2timestamp(tm, fsec, &tz, &result) != 0)
00444 ereport(ERROR,
00445 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
00446 errmsg("timestamp out of range: \"%s\"", str)));
00447 break;
00448
00449 case DTK_EPOCH:
00450 result = SetEpochTimestamp();
00451 break;
00452
00453 case DTK_LATE:
00454 TIMESTAMP_NOEND(result);
00455 break;
00456
00457 case DTK_EARLY:
00458 TIMESTAMP_NOBEGIN(result);
00459 break;
00460
00461 case DTK_INVALID:
00462 ereport(ERROR,
00463 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00464 errmsg("date/time value \"%s\" is no longer supported", str)));
00465
00466 TIMESTAMP_NOEND(result);
00467 break;
00468
00469 default:
00470 elog(ERROR, "unexpected dtype %d while parsing timestamptz \"%s\"",
00471 dtype, str);
00472 TIMESTAMP_NOEND(result);
00473 }
00474
00475 AdjustTimestampForTypmod(&result, typmod);
00476
00477 PG_RETURN_TIMESTAMPTZ(result);
00478 }
00479
00480
00481
00482
00483 Datum
00484 timestamptz_out(PG_FUNCTION_ARGS)
00485 {
00486 TimestampTz dt = PG_GETARG_TIMESTAMPTZ(0);
00487 char *result;
00488 int tz;
00489 struct pg_tm tt,
00490 *tm = &tt;
00491 fsec_t fsec;
00492 const char *tzn;
00493 char buf[MAXDATELEN + 1];
00494
00495 if (TIMESTAMP_NOT_FINITE(dt))
00496 EncodeSpecialTimestamp(dt, buf);
00497 else if (timestamp2tm(dt, &tz, tm, &fsec, &tzn, NULL) == 0)
00498 EncodeDateTime(tm, fsec, true, tz, tzn, DateStyle, buf);
00499 else
00500 ereport(ERROR,
00501 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
00502 errmsg("timestamp out of range")));
00503
00504 result = pstrdup(buf);
00505 PG_RETURN_CSTRING(result);
00506 }
00507
00508
00509
00510
00511
00512
00513
00514 Datum
00515 timestamptz_recv(PG_FUNCTION_ARGS)
00516 {
00517 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
00518
00519 #ifdef NOT_USED
00520 Oid typelem = PG_GETARG_OID(1);
00521 #endif
00522 int32 typmod = PG_GETARG_INT32(2);
00523 TimestampTz timestamp;
00524 int tz;
00525 struct pg_tm tt,
00526 *tm = &tt;
00527 fsec_t fsec;
00528
00529 #ifdef HAVE_INT64_TIMESTAMP
00530 timestamp = (TimestampTz) pq_getmsgint64(buf);
00531 #else
00532 timestamp = (TimestampTz) pq_getmsgfloat8(buf);
00533 #endif
00534
00535
00536 if (TIMESTAMP_NOT_FINITE(timestamp))
00537 ;
00538 else if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
00539 ereport(ERROR,
00540 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
00541 errmsg("timestamp out of range")));
00542
00543 AdjustTimestampForTypmod(×tamp, typmod);
00544
00545 PG_RETURN_TIMESTAMPTZ(timestamp);
00546 }
00547
00548
00549
00550
00551 Datum
00552 timestamptz_send(PG_FUNCTION_ARGS)
00553 {
00554 TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
00555 StringInfoData buf;
00556
00557 pq_begintypsend(&buf);
00558 #ifdef HAVE_INT64_TIMESTAMP
00559 pq_sendint64(&buf, timestamp);
00560 #else
00561 pq_sendfloat8(&buf, timestamp);
00562 #endif
00563 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
00564 }
00565
00566 Datum
00567 timestamptztypmodin(PG_FUNCTION_ARGS)
00568 {
00569 ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
00570
00571 PG_RETURN_INT32(anytimestamp_typmodin(true, ta));
00572 }
00573
00574 Datum
00575 timestamptztypmodout(PG_FUNCTION_ARGS)
00576 {
00577 int32 typmod = PG_GETARG_INT32(0);
00578
00579 PG_RETURN_CSTRING(anytimestamp_typmodout(true, typmod));
00580 }
00581
00582
00583
00584
00585
00586
00587 Datum
00588 timestamptz_scale(PG_FUNCTION_ARGS)
00589 {
00590 TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
00591 int32 typmod = PG_GETARG_INT32(1);
00592 TimestampTz result;
00593
00594 result = timestamp;
00595
00596 AdjustTimestampForTypmod(&result, typmod);
00597
00598 PG_RETURN_TIMESTAMPTZ(result);
00599 }
00600
00601
00602
00603
00604
00605
00606
00607
00608 Datum
00609 interval_in(PG_FUNCTION_ARGS)
00610 {
00611 char *str = PG_GETARG_CSTRING(0);
00612
00613 #ifdef NOT_USED
00614 Oid typelem = PG_GETARG_OID(1);
00615 #endif
00616 int32 typmod = PG_GETARG_INT32(2);
00617 Interval *result;
00618 fsec_t fsec;
00619 struct pg_tm tt,
00620 *tm = &tt;
00621 int dtype;
00622 int nf;
00623 int range;
00624 int dterr;
00625 char *field[MAXDATEFIELDS];
00626 int ftype[MAXDATEFIELDS];
00627 char workbuf[256];
00628
00629 tm->tm_year = 0;
00630 tm->tm_mon = 0;
00631 tm->tm_mday = 0;
00632 tm->tm_hour = 0;
00633 tm->tm_min = 0;
00634 tm->tm_sec = 0;
00635 fsec = 0;
00636
00637 if (typmod >= 0)
00638 range = INTERVAL_RANGE(typmod);
00639 else
00640 range = INTERVAL_FULL_RANGE;
00641
00642 dterr = ParseDateTime(str, workbuf, sizeof(workbuf), field,
00643 ftype, MAXDATEFIELDS, &nf);
00644 if (dterr == 0)
00645 dterr = DecodeInterval(field, ftype, nf, range,
00646 &dtype, tm, &fsec);
00647
00648
00649 if (dterr == DTERR_BAD_FORMAT)
00650 dterr = DecodeISO8601Interval(str,
00651 &dtype, tm, &fsec);
00652
00653 if (dterr != 0)
00654 {
00655 if (dterr == DTERR_FIELD_OVERFLOW)
00656 dterr = DTERR_INTERVAL_OVERFLOW;
00657 DateTimeParseError(dterr, str, "interval");
00658 }
00659
00660 result = (Interval *) palloc(sizeof(Interval));
00661
00662 switch (dtype)
00663 {
00664 case DTK_DELTA:
00665 if (tm2interval(tm, fsec, result) != 0)
00666 ereport(ERROR,
00667 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
00668 errmsg("interval out of range")));
00669 break;
00670
00671 case DTK_INVALID:
00672 ereport(ERROR,
00673 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00674 errmsg("date/time value \"%s\" is no longer supported", str)));
00675 break;
00676
00677 default:
00678 elog(ERROR, "unexpected dtype %d while parsing interval \"%s\"",
00679 dtype, str);
00680 }
00681
00682 AdjustIntervalForTypmod(result, typmod);
00683
00684 PG_RETURN_INTERVAL_P(result);
00685 }
00686
00687
00688
00689
00690 Datum
00691 interval_out(PG_FUNCTION_ARGS)
00692 {
00693 Interval *span = PG_GETARG_INTERVAL_P(0);
00694 char *result;
00695 struct pg_tm tt,
00696 *tm = &tt;
00697 fsec_t fsec;
00698 char buf[MAXDATELEN + 1];
00699
00700 if (interval2tm(*span, tm, &fsec) != 0)
00701 elog(ERROR, "could not convert interval to tm");
00702
00703 EncodeInterval(tm, fsec, IntervalStyle, buf);
00704
00705 result = pstrdup(buf);
00706 PG_RETURN_CSTRING(result);
00707 }
00708
00709
00710
00711
00712 Datum
00713 interval_recv(PG_FUNCTION_ARGS)
00714 {
00715 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
00716
00717 #ifdef NOT_USED
00718 Oid typelem = PG_GETARG_OID(1);
00719 #endif
00720 int32 typmod = PG_GETARG_INT32(2);
00721 Interval *interval;
00722
00723 interval = (Interval *) palloc(sizeof(Interval));
00724
00725 #ifdef HAVE_INT64_TIMESTAMP
00726 interval->time = pq_getmsgint64(buf);
00727 #else
00728 interval->time = pq_getmsgfloat8(buf);
00729 #endif
00730 interval->day = pq_getmsgint(buf, sizeof(interval->day));
00731 interval->month = pq_getmsgint(buf, sizeof(interval->month));
00732
00733 AdjustIntervalForTypmod(interval, typmod);
00734
00735 PG_RETURN_INTERVAL_P(interval);
00736 }
00737
00738
00739
00740
00741 Datum
00742 interval_send(PG_FUNCTION_ARGS)
00743 {
00744 Interval *interval = PG_GETARG_INTERVAL_P(0);
00745 StringInfoData buf;
00746
00747 pq_begintypsend(&buf);
00748 #ifdef HAVE_INT64_TIMESTAMP
00749 pq_sendint64(&buf, interval->time);
00750 #else
00751 pq_sendfloat8(&buf, interval->time);
00752 #endif
00753 pq_sendint(&buf, interval->day, sizeof(interval->day));
00754 pq_sendint(&buf, interval->month, sizeof(interval->month));
00755 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
00756 }
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770 Datum
00771 intervaltypmodin(PG_FUNCTION_ARGS)
00772 {
00773 ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
00774 int32 *tl;
00775 int n;
00776 int32 typmod;
00777
00778 tl = ArrayGetIntegerTypmods(ta, &n);
00779
00780
00781
00782
00783
00784
00785
00786 if (n > 0)
00787 {
00788 switch (tl[0])
00789 {
00790 case INTERVAL_MASK(YEAR):
00791 case INTERVAL_MASK(MONTH):
00792 case INTERVAL_MASK(DAY):
00793 case INTERVAL_MASK(HOUR):
00794 case INTERVAL_MASK(MINUTE):
00795 case INTERVAL_MASK(SECOND):
00796 case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH):
00797 case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR):
00798 case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
00799 case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
00800 case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
00801 case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
00802 case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
00803 case INTERVAL_FULL_RANGE:
00804
00805 break;
00806 default:
00807 ereport(ERROR,
00808 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00809 errmsg("invalid INTERVAL type modifier")));
00810 }
00811 }
00812
00813 if (n == 1)
00814 {
00815 if (tl[0] != INTERVAL_FULL_RANGE)
00816 typmod = INTERVAL_TYPMOD(INTERVAL_FULL_PRECISION, tl[0]);
00817 else
00818 typmod = -1;
00819 }
00820 else if (n == 2)
00821 {
00822 if (tl[1] < 0)
00823 ereport(ERROR,
00824 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00825 errmsg("INTERVAL(%d) precision must not be negative",
00826 tl[1])));
00827 if (tl[1] > MAX_INTERVAL_PRECISION)
00828 {
00829 ereport(WARNING,
00830 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00831 errmsg("INTERVAL(%d) precision reduced to maximum allowed, %d",
00832 tl[1], MAX_INTERVAL_PRECISION)));
00833 typmod = INTERVAL_TYPMOD(MAX_INTERVAL_PRECISION, tl[0]);
00834 }
00835 else
00836 typmod = INTERVAL_TYPMOD(tl[1], tl[0]);
00837 }
00838 else
00839 {
00840 ereport(ERROR,
00841 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00842 errmsg("invalid INTERVAL type modifier")));
00843 typmod = 0;
00844 }
00845
00846 PG_RETURN_INT32(typmod);
00847 }
00848
00849 Datum
00850 intervaltypmodout(PG_FUNCTION_ARGS)
00851 {
00852 int32 typmod = PG_GETARG_INT32(0);
00853 char *res = (char *) palloc(64);
00854 int fields;
00855 int precision;
00856 const char *fieldstr;
00857
00858 if (typmod < 0)
00859 {
00860 *res = '\0';
00861 PG_RETURN_CSTRING(res);
00862 }
00863
00864 fields = INTERVAL_RANGE(typmod);
00865 precision = INTERVAL_PRECISION(typmod);
00866
00867 switch (fields)
00868 {
00869 case INTERVAL_MASK(YEAR):
00870 fieldstr = " year";
00871 break;
00872 case INTERVAL_MASK(MONTH):
00873 fieldstr = " month";
00874 break;
00875 case INTERVAL_MASK(DAY):
00876 fieldstr = " day";
00877 break;
00878 case INTERVAL_MASK(HOUR):
00879 fieldstr = " hour";
00880 break;
00881 case INTERVAL_MASK(MINUTE):
00882 fieldstr = " minute";
00883 break;
00884 case INTERVAL_MASK(SECOND):
00885 fieldstr = " second";
00886 break;
00887 case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH):
00888 fieldstr = " year to month";
00889 break;
00890 case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR):
00891 fieldstr = " day to hour";
00892 break;
00893 case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
00894 fieldstr = " day to minute";
00895 break;
00896 case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
00897 fieldstr = " day to second";
00898 break;
00899 case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
00900 fieldstr = " hour to minute";
00901 break;
00902 case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
00903 fieldstr = " hour to second";
00904 break;
00905 case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
00906 fieldstr = " minute to second";
00907 break;
00908 case INTERVAL_FULL_RANGE:
00909 fieldstr = "";
00910 break;
00911 default:
00912 elog(ERROR, "invalid INTERVAL typmod: 0x%x", typmod);
00913 fieldstr = "";
00914 break;
00915 }
00916
00917 if (precision != INTERVAL_FULL_PRECISION)
00918 snprintf(res, 64, "%s(%d)", fieldstr, precision);
00919 else
00920 snprintf(res, 64, "%s", fieldstr);
00921
00922 PG_RETURN_CSTRING(res);
00923 }
00924
00925
00926
00927
00928
00929
00930
00931 Datum
00932 interval_transform(PG_FUNCTION_ARGS)
00933 {
00934 FuncExpr *expr = (FuncExpr *) PG_GETARG_POINTER(0);
00935 Node *ret = NULL;
00936 Node *typmod;
00937
00938 Assert(IsA(expr, FuncExpr));
00939 Assert(list_length(expr->args) >= 2);
00940
00941 typmod = (Node *) lsecond(expr->args);
00942
00943 if (IsA(typmod, Const) &&!((Const *) typmod)->constisnull)
00944 {
00945 Node *source = (Node *) linitial(expr->args);
00946 int32 old_typmod = exprTypmod(source);
00947 int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
00948 int old_range;
00949 int old_precis;
00950 int new_range = INTERVAL_RANGE(new_typmod);
00951 int new_precis = INTERVAL_PRECISION(new_typmod);
00952 int new_range_fls;
00953 int old_range_fls;
00954
00955 if (old_typmod < 0)
00956 {
00957 old_range = INTERVAL_FULL_RANGE;
00958 old_precis = INTERVAL_FULL_PRECISION;
00959 }
00960 else
00961 {
00962 old_range = INTERVAL_RANGE(old_typmod);
00963 old_precis = INTERVAL_PRECISION(old_typmod);
00964 }
00965
00966
00967
00968
00969
00970
00971
00972
00973 new_range_fls = fls(new_range);
00974 old_range_fls = fls(old_range);
00975 if (new_typmod < 0 ||
00976 ((new_range_fls >= SECOND || new_range_fls >= old_range_fls) &&
00977 (old_range_fls < SECOND || new_precis >= MAX_INTERVAL_PRECISION ||
00978 new_precis >= old_precis)))
00979 ret = relabel_to_typmod(source, new_typmod);
00980 }
00981
00982 PG_RETURN_POINTER(ret);
00983 }
00984
00985
00986
00987
00988
00989 Datum
00990 interval_scale(PG_FUNCTION_ARGS)
00991 {
00992 Interval *interval = PG_GETARG_INTERVAL_P(0);
00993 int32 typmod = PG_GETARG_INT32(1);
00994 Interval *result;
00995
00996 result = palloc(sizeof(Interval));
00997 *result = *interval;
00998
00999 AdjustIntervalForTypmod(result, typmod);
01000
01001 PG_RETURN_INTERVAL_P(result);
01002 }
01003
01004
01005
01006
01007
01008 static void
01009 AdjustIntervalForTypmod(Interval *interval, int32 typmod)
01010 {
01011 #ifdef HAVE_INT64_TIMESTAMP
01012 static const int64 IntervalScales[MAX_INTERVAL_PRECISION + 1] = {
01013 INT64CONST(1000000),
01014 INT64CONST(100000),
01015 INT64CONST(10000),
01016 INT64CONST(1000),
01017 INT64CONST(100),
01018 INT64CONST(10),
01019 INT64CONST(1)
01020 };
01021
01022 static const int64 IntervalOffsets[MAX_INTERVAL_PRECISION + 1] = {
01023 INT64CONST(500000),
01024 INT64CONST(50000),
01025 INT64CONST(5000),
01026 INT64CONST(500),
01027 INT64CONST(50),
01028 INT64CONST(5),
01029 INT64CONST(0)
01030 };
01031 #else
01032 static const double IntervalScales[MAX_INTERVAL_PRECISION + 1] = {
01033 1,
01034 10,
01035 100,
01036 1000,
01037 10000,
01038 100000,
01039 1000000
01040 };
01041 #endif
01042
01043
01044
01045
01046
01047 if (typmod >= 0)
01048 {
01049 int range = INTERVAL_RANGE(typmod);
01050 int precision = INTERVAL_PRECISION(typmod);
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072 if (range == INTERVAL_FULL_RANGE)
01073 {
01074
01075 }
01076 else if (range == INTERVAL_MASK(YEAR))
01077 {
01078 interval->month = (interval->month / MONTHS_PER_YEAR) * MONTHS_PER_YEAR;
01079 interval->day = 0;
01080 interval->time = 0;
01081 }
01082 else if (range == INTERVAL_MASK(MONTH))
01083 {
01084 interval->day = 0;
01085 interval->time = 0;
01086 }
01087
01088 else if (range == (INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH)))
01089 {
01090 interval->day = 0;
01091 interval->time = 0;
01092 }
01093 else if (range == INTERVAL_MASK(DAY))
01094 {
01095 interval->time = 0;
01096 }
01097 else if (range == INTERVAL_MASK(HOUR))
01098 {
01099 #ifdef HAVE_INT64_TIMESTAMP
01100 interval->time = (interval->time / USECS_PER_HOUR) *
01101 USECS_PER_HOUR;
01102 #else
01103 interval->time = ((int) (interval->time / SECS_PER_HOUR)) * (double) SECS_PER_HOUR;
01104 #endif
01105 }
01106 else if (range == INTERVAL_MASK(MINUTE))
01107 {
01108 #ifdef HAVE_INT64_TIMESTAMP
01109 interval->time = (interval->time / USECS_PER_MINUTE) *
01110 USECS_PER_MINUTE;
01111 #else
01112 interval->time = ((int) (interval->time / SECS_PER_MINUTE)) * (double) SECS_PER_MINUTE;
01113 #endif
01114 }
01115 else if (range == INTERVAL_MASK(SECOND))
01116 {
01117
01118 }
01119
01120 else if (range == (INTERVAL_MASK(DAY) |
01121 INTERVAL_MASK(HOUR)))
01122 {
01123 #ifdef HAVE_INT64_TIMESTAMP
01124 interval->time = (interval->time / USECS_PER_HOUR) *
01125 USECS_PER_HOUR;
01126 #else
01127 interval->time = ((int) (interval->time / SECS_PER_HOUR)) * (double) SECS_PER_HOUR;
01128 #endif
01129 }
01130
01131 else if (range == (INTERVAL_MASK(DAY) |
01132 INTERVAL_MASK(HOUR) |
01133 INTERVAL_MASK(MINUTE)))
01134 {
01135 #ifdef HAVE_INT64_TIMESTAMP
01136 interval->time = (interval->time / USECS_PER_MINUTE) *
01137 USECS_PER_MINUTE;
01138 #else
01139 interval->time = ((int) (interval->time / SECS_PER_MINUTE)) * (double) SECS_PER_MINUTE;
01140 #endif
01141 }
01142
01143 else if (range == (INTERVAL_MASK(DAY) |
01144 INTERVAL_MASK(HOUR) |
01145 INTERVAL_MASK(MINUTE) |
01146 INTERVAL_MASK(SECOND)))
01147 {
01148
01149 }
01150
01151 else if (range == (INTERVAL_MASK(HOUR) |
01152 INTERVAL_MASK(MINUTE)))
01153 {
01154 #ifdef HAVE_INT64_TIMESTAMP
01155 interval->time = (interval->time / USECS_PER_MINUTE) *
01156 USECS_PER_MINUTE;
01157 #else
01158 interval->time = ((int) (interval->time / SECS_PER_MINUTE)) * (double) SECS_PER_MINUTE;
01159 #endif
01160 }
01161
01162 else if (range == (INTERVAL_MASK(HOUR) |
01163 INTERVAL_MASK(MINUTE) |
01164 INTERVAL_MASK(SECOND)))
01165 {
01166
01167 }
01168
01169 else if (range == (INTERVAL_MASK(MINUTE) |
01170 INTERVAL_MASK(SECOND)))
01171 {
01172
01173 }
01174 else
01175 elog(ERROR, "unrecognized interval typmod: %d", typmod);
01176
01177
01178 if (precision != INTERVAL_FULL_PRECISION)
01179 {
01180 if (precision < 0 || precision > MAX_INTERVAL_PRECISION)
01181 ereport(ERROR,
01182 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
01183 errmsg("interval(%d) precision must be between %d and %d",
01184 precision, 0, MAX_INTERVAL_PRECISION)));
01185
01186
01187
01188
01189
01190
01191
01192
01193 #ifdef HAVE_INT64_TIMESTAMP
01194 if (interval->time >= INT64CONST(0))
01195 {
01196 interval->time = ((interval->time +
01197 IntervalOffsets[precision]) /
01198 IntervalScales[precision]) *
01199 IntervalScales[precision];
01200 }
01201 else
01202 {
01203 interval->time = -(((-interval->time +
01204 IntervalOffsets[precision]) /
01205 IntervalScales[precision]) *
01206 IntervalScales[precision]);
01207 }
01208 #else
01209 interval->time = rint(((double) interval->time) *
01210 IntervalScales[precision]) /
01211 IntervalScales[precision];
01212 #endif
01213 }
01214 }
01215 }
01216
01217
01218
01219
01220
01221 static void
01222 EncodeSpecialTimestamp(Timestamp dt, char *str)
01223 {
01224 if (TIMESTAMP_IS_NOBEGIN(dt))
01225 strcpy(str, EARLY);
01226 else if (TIMESTAMP_IS_NOEND(dt))
01227 strcpy(str, LATE);
01228 else
01229 elog(ERROR, "invalid argument for EncodeSpecialTimestamp");
01230 }
01231
01232 Datum
01233 now(PG_FUNCTION_ARGS)
01234 {
01235 PG_RETURN_TIMESTAMPTZ(GetCurrentTransactionStartTimestamp());
01236 }
01237
01238 Datum
01239 statement_timestamp(PG_FUNCTION_ARGS)
01240 {
01241 PG_RETURN_TIMESTAMPTZ(GetCurrentStatementStartTimestamp());
01242 }
01243
01244 Datum
01245 clock_timestamp(PG_FUNCTION_ARGS)
01246 {
01247 PG_RETURN_TIMESTAMPTZ(GetCurrentTimestamp());
01248 }
01249
01250 Datum
01251 pg_postmaster_start_time(PG_FUNCTION_ARGS)
01252 {
01253 PG_RETURN_TIMESTAMPTZ(PgStartTime);
01254 }
01255
01256 Datum
01257 pg_conf_load_time(PG_FUNCTION_ARGS)
01258 {
01259 PG_RETURN_TIMESTAMPTZ(PgReloadTime);
01260 }
01261
01262
01263
01264
01265
01266
01267
01268 TimestampTz
01269 GetCurrentTimestamp(void)
01270 {
01271 TimestampTz result;
01272 struct timeval tp;
01273
01274 gettimeofday(&tp, NULL);
01275
01276 result = (TimestampTz) tp.tv_sec -
01277 ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
01278
01279 #ifdef HAVE_INT64_TIMESTAMP
01280 result = (result * USECS_PER_SEC) + tp.tv_usec;
01281 #else
01282 result = result + (tp.tv_usec / 1000000.0);
01283 #endif
01284
01285 return result;
01286 }
01287
01288
01289
01290
01291
01292
01293
01294
01295 #ifndef HAVE_INT64_TIMESTAMP
01296 int64
01297 GetCurrentIntegerTimestamp(void)
01298 {
01299 int64 result;
01300 struct timeval tp;
01301
01302 gettimeofday(&tp, NULL);
01303
01304 result = (int64) tp.tv_sec -
01305 ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
01306
01307 result = (result * USECS_PER_SEC) + tp.tv_usec;
01308
01309 return result;
01310 }
01311 #endif
01312
01313
01314
01315
01316
01317
01318
01319 #ifndef HAVE_INT64_TIMESTAMP
01320 TimestampTz
01321 IntegerTimestampToTimestampTz(int64 timestamp)
01322 {
01323 TimestampTz result;
01324
01325 result = timestamp / USECS_PER_SEC;
01326 result += (timestamp % USECS_PER_SEC) / 1000000.0;
01327
01328 return result;
01329 }
01330 #endif
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341
01342
01343 void
01344 TimestampDifference(TimestampTz start_time, TimestampTz stop_time,
01345 long *secs, int *microsecs)
01346 {
01347 TimestampTz diff = stop_time - start_time;
01348
01349 if (diff <= 0)
01350 {
01351 *secs = 0;
01352 *microsecs = 0;
01353 }
01354 else
01355 {
01356 #ifdef HAVE_INT64_TIMESTAMP
01357 *secs = (long) (diff / USECS_PER_SEC);
01358 *microsecs = (int) (diff % USECS_PER_SEC);
01359 #else
01360 *secs = (long) diff;
01361 *microsecs = (int) ((diff - *secs) * 1000000.0);
01362 #endif
01363 }
01364 }
01365
01366
01367
01368
01369
01370
01371
01372
01373 bool
01374 TimestampDifferenceExceeds(TimestampTz start_time,
01375 TimestampTz stop_time,
01376 int msec)
01377 {
01378 TimestampTz diff = stop_time - start_time;
01379
01380 #ifdef HAVE_INT64_TIMESTAMP
01381 return (diff >= msec * INT64CONST(1000));
01382 #else
01383 return (diff * 1000.0 >= msec);
01384 #endif
01385 }
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398 TimestampTz
01399 time_t_to_timestamptz(pg_time_t tm)
01400 {
01401 TimestampTz result;
01402
01403 result = (TimestampTz) tm -
01404 ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
01405
01406 #ifdef HAVE_INT64_TIMESTAMP
01407 result *= USECS_PER_SEC;
01408 #endif
01409
01410 return result;
01411 }
01412
01413
01414
01415
01416
01417
01418
01419
01420
01421
01422
01423 pg_time_t
01424 timestamptz_to_time_t(TimestampTz t)
01425 {
01426 pg_time_t result;
01427
01428 #ifdef HAVE_INT64_TIMESTAMP
01429 result = (pg_time_t) (t / USECS_PER_SEC +
01430 ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY));
01431 #else
01432 result = (pg_time_t) (t +
01433 ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY));
01434 #endif
01435
01436 return result;
01437 }
01438
01439
01440
01441
01442
01443
01444
01445
01446 const char *
01447 timestamptz_to_str(TimestampTz t)
01448 {
01449 static char buf[MAXDATELEN + 1];
01450 int tz;
01451 struct pg_tm tt,
01452 *tm = &tt;
01453 fsec_t fsec;
01454 const char *tzn;
01455
01456 if (TIMESTAMP_NOT_FINITE(t))
01457 EncodeSpecialTimestamp(t, buf);
01458 else if (timestamp2tm(t, &tz, tm, &fsec, &tzn, NULL) == 0)
01459 EncodeDateTime(tm, fsec, true, tz, tzn, USE_ISO_DATES, buf);
01460 else
01461 strlcpy(buf, "(timestamp out of range)", sizeof(buf));
01462
01463 return buf;
01464 }
01465
01466
01467 void
01468 dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
01469 {
01470 TimeOffset time;
01471
01472 time = jd;
01473
01474 #ifdef HAVE_INT64_TIMESTAMP
01475 *hour = time / USECS_PER_HOUR;
01476 time -= (*hour) * USECS_PER_HOUR;
01477 *min = time / USECS_PER_MINUTE;
01478 time -= (*min) * USECS_PER_MINUTE;
01479 *sec = time / USECS_PER_SEC;
01480 *fsec = time - (*sec * USECS_PER_SEC);
01481 #else
01482 *hour = time / SECS_PER_HOUR;
01483 time -= (*hour) * SECS_PER_HOUR;
01484 *min = time / SECS_PER_MINUTE;
01485 time -= (*min) * SECS_PER_MINUTE;
01486 *sec = time;
01487 *fsec = time - *sec;
01488 #endif
01489 }
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504 int
01505 timestamp2tm(Timestamp dt, int *tzp, struct pg_tm * tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
01506 {
01507 Timestamp date;
01508 Timestamp time;
01509 pg_time_t utime;
01510
01511
01512
01513
01514
01515
01516 if (attimezone == NULL && HasCTZSet && tzp != NULL)
01517 {
01518 #ifdef HAVE_INT64_TIMESTAMP
01519 dt -= CTimeZone * USECS_PER_SEC;
01520 #else
01521 dt -= CTimeZone;
01522 #endif
01523 }
01524
01525 #ifdef HAVE_INT64_TIMESTAMP
01526 time = dt;
01527 TMODULO(time, date, USECS_PER_DAY);
01528
01529 if (time < INT64CONST(0))
01530 {
01531 time += USECS_PER_DAY;
01532 date -= 1;
01533 }
01534
01535
01536 date += POSTGRES_EPOCH_JDATE;
01537
01538
01539 if (date < 0 || date > (Timestamp) INT_MAX)
01540 return -1;
01541
01542 j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
01543 dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
01544 #else
01545 time = dt;
01546 TMODULO(time, date, (double) SECS_PER_DAY);
01547
01548 if (time < 0)
01549 {
01550 time += SECS_PER_DAY;
01551 date -= 1;
01552 }
01553
01554
01555 date += POSTGRES_EPOCH_JDATE;
01556
01557 recalc_d:
01558
01559 if (date < 0 || date > (Timestamp) INT_MAX)
01560 return -1;
01561
01562 j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
01563 recalc_t:
01564 dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
01565
01566 *fsec = TSROUND(*fsec);
01567
01568 if (*fsec >= 1.0)
01569 {
01570 time = ceil(time);
01571 if (time >= (double) SECS_PER_DAY)
01572 {
01573 time = 0;
01574 date += 1;
01575 goto recalc_d;
01576 }
01577 goto recalc_t;
01578 }
01579 #endif
01580
01581
01582 if (tzp == NULL)
01583 {
01584 tm->tm_isdst = -1;
01585 tm->tm_gmtoff = 0;
01586 tm->tm_zone = NULL;
01587 if (tzn != NULL)
01588 *tzn = NULL;
01589 return 0;
01590 }
01591
01592
01593
01594
01595
01596 if (attimezone == NULL && HasCTZSet)
01597 {
01598 *tzp = CTimeZone;
01599 tm->tm_isdst = 0;
01600 tm->tm_gmtoff = CTimeZone;
01601 tm->tm_zone = NULL;
01602 if (tzn != NULL)
01603 *tzn = NULL;
01604 return 0;
01605 }
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617 #ifdef HAVE_INT64_TIMESTAMP
01618 dt = (dt - *fsec) / USECS_PER_SEC +
01619 (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY;
01620 #else
01621 dt = rint(dt - *fsec +
01622 (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
01623 #endif
01624 utime = (pg_time_t) dt;
01625 if ((Timestamp) utime == dt)
01626 {
01627 struct pg_tm *tx = pg_localtime(&utime,
01628 attimezone ? attimezone : session_timezone);
01629
01630 tm->tm_year = tx->tm_year + 1900;
01631 tm->tm_mon = tx->tm_mon + 1;
01632 tm->tm_mday = tx->tm_mday;
01633 tm->tm_hour = tx->tm_hour;
01634 tm->tm_min = tx->tm_min;
01635 tm->tm_sec = tx->tm_sec;
01636 tm->tm_isdst = tx->tm_isdst;
01637 tm->tm_gmtoff = tx->tm_gmtoff;
01638 tm->tm_zone = tx->tm_zone;
01639 *tzp = -tm->tm_gmtoff;
01640 if (tzn != NULL)
01641 *tzn = tm->tm_zone;
01642 }
01643 else
01644 {
01645
01646
01647
01648 *tzp = 0;
01649
01650 tm->tm_isdst = -1;
01651 tm->tm_gmtoff = 0;
01652 tm->tm_zone = NULL;
01653 if (tzn != NULL)
01654 *tzn = NULL;
01655 }
01656
01657 return 0;
01658 }
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668 int
01669 tm2timestamp(struct pg_tm * tm, fsec_t fsec, int *tzp, Timestamp *result)
01670 {
01671 TimeOffset date;
01672 TimeOffset time;
01673
01674
01675 if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
01676 {
01677 *result = 0;
01678 return -1;
01679 }
01680
01681 date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
01682 time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
01683
01684 #ifdef HAVE_INT64_TIMESTAMP
01685 *result = date * USECS_PER_DAY + time;
01686
01687 if ((*result - time) / USECS_PER_DAY != date)
01688 {
01689 *result = 0;
01690 return -1;
01691 }
01692
01693
01694 if ((*result < 0 && date > 0) ||
01695 (*result > 0 && date < -1))
01696 {
01697 *result = 0;
01698 return -1;
01699 }
01700 #else
01701 *result = date * SECS_PER_DAY + time;
01702 #endif
01703 if (tzp != NULL)
01704 *result = dt2local(*result, -(*tzp));
01705
01706 return 0;
01707 }
01708
01709
01710
01711
01712
01713 int
01714 interval2tm(Interval span, struct pg_tm * tm, fsec_t *fsec)
01715 {
01716 TimeOffset time;
01717 TimeOffset tfrac;
01718
01719 tm->tm_year = span.month / MONTHS_PER_YEAR;
01720 tm->tm_mon = span.month % MONTHS_PER_YEAR;
01721 tm->tm_mday = span.day;
01722 time = span.time;
01723
01724 #ifdef HAVE_INT64_TIMESTAMP
01725 tfrac = time / USECS_PER_HOUR;
01726 time -= tfrac * USECS_PER_HOUR;
01727 tm->tm_hour = tfrac;
01728 tfrac = time / USECS_PER_MINUTE;
01729 time -= tfrac * USECS_PER_MINUTE;
01730 tm->tm_min = tfrac;
01731 tfrac = time / USECS_PER_SEC;
01732 *fsec = time - (tfrac * USECS_PER_SEC);
01733 tm->tm_sec = tfrac;
01734 #else
01735 recalc:
01736 TMODULO(time, tfrac, (double) SECS_PER_HOUR);
01737 tm->tm_hour = tfrac;
01738 TMODULO(time, tfrac, (double) SECS_PER_MINUTE);
01739 tm->tm_min = tfrac;
01740 TMODULO(time, tfrac, 1.0);
01741 tm->tm_sec = tfrac;
01742 time = TSROUND(time);
01743
01744 if (time >= 1.0)
01745 {
01746 time = ceil(span.time);
01747 goto recalc;
01748 }
01749 *fsec = time;
01750 #endif
01751
01752 return 0;
01753 }
01754
01755 int
01756 tm2interval(struct pg_tm * tm, fsec_t fsec, Interval *span)
01757 {
01758 span->month = tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon;
01759 span->day = tm->tm_mday;
01760 #ifdef HAVE_INT64_TIMESTAMP
01761 span->time = (((((tm->tm_hour * INT64CONST(60)) +
01762 tm->tm_min) * INT64CONST(60)) +
01763 tm->tm_sec) * USECS_PER_SEC) + fsec;
01764 #else
01765 span->time = (((tm->tm_hour * (double) MINS_PER_HOUR) +
01766 tm->tm_min) * (double) SECS_PER_MINUTE) +
01767 tm->tm_sec + fsec;
01768 #endif
01769
01770 return 0;
01771 }
01772
01773 static TimeOffset
01774 time2t(const int hour, const int min, const int sec, const fsec_t fsec)
01775 {
01776 #ifdef HAVE_INT64_TIMESTAMP
01777 return (((((hour * MINS_PER_HOUR) + min) * SECS_PER_MINUTE) + sec) * USECS_PER_SEC) + fsec;
01778 #else
01779 return (((hour * MINS_PER_HOUR) + min) * SECS_PER_MINUTE) + sec + fsec;
01780 #endif
01781 }
01782
01783 static Timestamp
01784 dt2local(Timestamp dt, int tz)
01785 {
01786 #ifdef HAVE_INT64_TIMESTAMP
01787 dt -= (tz * USECS_PER_SEC);
01788 #else
01789 dt -= tz;
01790 #endif
01791 return dt;
01792 }
01793
01794
01795
01796
01797
01798
01799
01800 Datum
01801 timestamp_finite(PG_FUNCTION_ARGS)
01802 {
01803 Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
01804
01805 PG_RETURN_BOOL(!TIMESTAMP_NOT_FINITE(timestamp));
01806 }
01807
01808 Datum
01809 interval_finite(PG_FUNCTION_ARGS)
01810 {
01811 PG_RETURN_BOOL(true);
01812 }
01813
01814
01815
01816
01817
01818
01819 void
01820 GetEpochTime(struct pg_tm * tm)
01821 {
01822 struct pg_tm *t0;
01823 pg_time_t epoch = 0;
01824
01825 t0 = pg_gmtime(&epoch);
01826
01827 tm->tm_year = t0->tm_year;
01828 tm->tm_mon = t0->tm_mon;
01829 tm->tm_mday = t0->tm_mday;
01830 tm->tm_hour = t0->tm_hour;
01831 tm->tm_min = t0->tm_min;
01832 tm->tm_sec = t0->tm_sec;
01833
01834 tm->tm_year += 1900;
01835 tm->tm_mon++;
01836 }
01837
01838 Timestamp
01839 SetEpochTimestamp(void)
01840 {
01841 Timestamp dt;
01842 struct pg_tm tt,
01843 *tm = &tt;
01844
01845 GetEpochTime(tm);
01846
01847 tm2timestamp(tm, 0, NULL, &dt);
01848
01849 return dt;
01850 }
01851
01852
01853
01854
01855
01856
01857
01858
01859
01860 int
01861 timestamp_cmp_internal(Timestamp dt1, Timestamp dt2)
01862 {
01863 #ifdef HAVE_INT64_TIMESTAMP
01864 return (dt1 < dt2) ? -1 : ((dt1 > dt2) ? 1 : 0);
01865 #else
01866
01867
01868
01869
01870
01871
01872
01873
01874 if (isnan(dt1))
01875 {
01876 if (isnan(dt2))
01877 return 0;
01878 else
01879 return 1;
01880 }
01881 else if (isnan(dt2))
01882 {
01883 return -1;
01884 }
01885 else
01886 {
01887 if (dt1 > dt2)
01888 return 1;
01889 else if (dt1 < dt2)
01890 return -1;
01891 else
01892 return 0;
01893 }
01894 #endif
01895 }
01896
01897 Datum
01898 timestamp_eq(PG_FUNCTION_ARGS)
01899 {
01900 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
01901 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
01902
01903 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
01904 }
01905
01906 Datum
01907 timestamp_ne(PG_FUNCTION_ARGS)
01908 {
01909 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
01910 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
01911
01912 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
01913 }
01914
01915 Datum
01916 timestamp_lt(PG_FUNCTION_ARGS)
01917 {
01918 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
01919 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
01920
01921 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
01922 }
01923
01924 Datum
01925 timestamp_gt(PG_FUNCTION_ARGS)
01926 {
01927 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
01928 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
01929
01930 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
01931 }
01932
01933 Datum
01934 timestamp_le(PG_FUNCTION_ARGS)
01935 {
01936 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
01937 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
01938
01939 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
01940 }
01941
01942 Datum
01943 timestamp_ge(PG_FUNCTION_ARGS)
01944 {
01945 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
01946 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
01947
01948 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
01949 }
01950
01951 Datum
01952 timestamp_cmp(PG_FUNCTION_ARGS)
01953 {
01954 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
01955 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
01956
01957 PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
01958 }
01959
01960
01961 static int
01962 timestamp_fastcmp(Datum x, Datum y, SortSupport ssup)
01963 {
01964 Timestamp a = DatumGetTimestamp(x);
01965 Timestamp b = DatumGetTimestamp(y);
01966
01967 return timestamp_cmp_internal(a, b);
01968 }
01969
01970 Datum
01971 timestamp_sortsupport(PG_FUNCTION_ARGS)
01972 {
01973 SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
01974
01975 ssup->comparator = timestamp_fastcmp;
01976 PG_RETURN_VOID();
01977 }
01978
01979 Datum
01980 timestamp_hash(PG_FUNCTION_ARGS)
01981 {
01982
01983 #ifdef HAVE_INT64_TIMESTAMP
01984 return hashint8(fcinfo);
01985 #else
01986 return hashfloat8(fcinfo);
01987 #endif
01988 }
01989
01990
01991
01992
01993
01994
01995 Datum
01996 timestamp_eq_timestamptz(PG_FUNCTION_ARGS)
01997 {
01998 Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
01999 TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
02000 TimestampTz dt1;
02001
02002 dt1 = timestamp2timestamptz(timestampVal);
02003
02004 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
02005 }
02006
02007 Datum
02008 timestamp_ne_timestamptz(PG_FUNCTION_ARGS)
02009 {
02010 Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
02011 TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
02012 TimestampTz dt1;
02013
02014 dt1 = timestamp2timestamptz(timestampVal);
02015
02016 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
02017 }
02018
02019 Datum
02020 timestamp_lt_timestamptz(PG_FUNCTION_ARGS)
02021 {
02022 Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
02023 TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
02024 TimestampTz dt1;
02025
02026 dt1 = timestamp2timestamptz(timestampVal);
02027
02028 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
02029 }
02030
02031 Datum
02032 timestamp_gt_timestamptz(PG_FUNCTION_ARGS)
02033 {
02034 Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
02035 TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
02036 TimestampTz dt1;
02037
02038 dt1 = timestamp2timestamptz(timestampVal);
02039
02040 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
02041 }
02042
02043 Datum
02044 timestamp_le_timestamptz(PG_FUNCTION_ARGS)
02045 {
02046 Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
02047 TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
02048 TimestampTz dt1;
02049
02050 dt1 = timestamp2timestamptz(timestampVal);
02051
02052 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
02053 }
02054
02055 Datum
02056 timestamp_ge_timestamptz(PG_FUNCTION_ARGS)
02057 {
02058 Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
02059 TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
02060 TimestampTz dt1;
02061
02062 dt1 = timestamp2timestamptz(timestampVal);
02063
02064 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
02065 }
02066
02067 Datum
02068 timestamp_cmp_timestamptz(PG_FUNCTION_ARGS)
02069 {
02070 Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
02071 TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
02072 TimestampTz dt1;
02073
02074 dt1 = timestamp2timestamptz(timestampVal);
02075
02076 PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
02077 }
02078
02079 Datum
02080 timestamptz_eq_timestamp(PG_FUNCTION_ARGS)
02081 {
02082 TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
02083 Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
02084 TimestampTz dt2;
02085
02086 dt2 = timestamp2timestamptz(timestampVal);
02087
02088 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
02089 }
02090
02091 Datum
02092 timestamptz_ne_timestamp(PG_FUNCTION_ARGS)
02093 {
02094 TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
02095 Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
02096 TimestampTz dt2;
02097
02098 dt2 = timestamp2timestamptz(timestampVal);
02099
02100 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
02101 }
02102
02103 Datum
02104 timestamptz_lt_timestamp(PG_FUNCTION_ARGS)
02105 {
02106 TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
02107 Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
02108 TimestampTz dt2;
02109
02110 dt2 = timestamp2timestamptz(timestampVal);
02111
02112 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
02113 }
02114
02115 Datum
02116 timestamptz_gt_timestamp(PG_FUNCTION_ARGS)
02117 {
02118 TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
02119 Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
02120 TimestampTz dt2;
02121
02122 dt2 = timestamp2timestamptz(timestampVal);
02123
02124 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
02125 }
02126
02127 Datum
02128 timestamptz_le_timestamp(PG_FUNCTION_ARGS)
02129 {
02130 TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
02131 Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
02132 TimestampTz dt2;
02133
02134 dt2 = timestamp2timestamptz(timestampVal);
02135
02136 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
02137 }
02138
02139 Datum
02140 timestamptz_ge_timestamp(PG_FUNCTION_ARGS)
02141 {
02142 TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
02143 Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
02144 TimestampTz dt2;
02145
02146 dt2 = timestamp2timestamptz(timestampVal);
02147
02148 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
02149 }
02150
02151 Datum
02152 timestamptz_cmp_timestamp(PG_FUNCTION_ARGS)
02153 {
02154 TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
02155 Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
02156 TimestampTz dt2;
02157
02158 dt2 = timestamp2timestamptz(timestampVal);
02159
02160 PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
02161 }
02162
02163
02164
02165
02166
02167
02168
02169 static inline TimeOffset
02170 interval_cmp_value(const Interval *interval)
02171 {
02172 TimeOffset span;
02173
02174 span = interval->time;
02175
02176 #ifdef HAVE_INT64_TIMESTAMP
02177 span += interval->month * INT64CONST(30) * USECS_PER_DAY;
02178 span += interval->day * INT64CONST(24) * USECS_PER_HOUR;
02179 #else
02180 span += interval->month * ((double) DAYS_PER_MONTH * SECS_PER_DAY);
02181 span += interval->day * ((double) HOURS_PER_DAY * SECS_PER_HOUR);
02182 #endif
02183
02184 return span;
02185 }
02186
02187 static int
02188 interval_cmp_internal(Interval *interval1, Interval *interval2)
02189 {
02190 TimeOffset span1 = interval_cmp_value(interval1);
02191 TimeOffset span2 = interval_cmp_value(interval2);
02192
02193 return ((span1 < span2) ? -1 : (span1 > span2) ? 1 : 0);
02194 }
02195
02196 Datum
02197 interval_eq(PG_FUNCTION_ARGS)
02198 {
02199 Interval *interval1 = PG_GETARG_INTERVAL_P(0);
02200 Interval *interval2 = PG_GETARG_INTERVAL_P(1);
02201
02202 PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) == 0);
02203 }
02204
02205 Datum
02206 interval_ne(PG_FUNCTION_ARGS)
02207 {
02208 Interval *interval1 = PG_GETARG_INTERVAL_P(0);
02209 Interval *interval2 = PG_GETARG_INTERVAL_P(1);
02210
02211 PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) != 0);
02212 }
02213
02214 Datum
02215 interval_lt(PG_FUNCTION_ARGS)
02216 {
02217 Interval *interval1 = PG_GETARG_INTERVAL_P(0);
02218 Interval *interval2 = PG_GETARG_INTERVAL_P(1);
02219
02220 PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) < 0);
02221 }
02222
02223 Datum
02224 interval_gt(PG_FUNCTION_ARGS)
02225 {
02226 Interval *interval1 = PG_GETARG_INTERVAL_P(0);
02227 Interval *interval2 = PG_GETARG_INTERVAL_P(1);
02228
02229 PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) > 0);
02230 }
02231
02232 Datum
02233 interval_le(PG_FUNCTION_ARGS)
02234 {
02235 Interval *interval1 = PG_GETARG_INTERVAL_P(0);
02236 Interval *interval2 = PG_GETARG_INTERVAL_P(1);
02237
02238 PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) <= 0);
02239 }
02240
02241 Datum
02242 interval_ge(PG_FUNCTION_ARGS)
02243 {
02244 Interval *interval1 = PG_GETARG_INTERVAL_P(0);
02245 Interval *interval2 = PG_GETARG_INTERVAL_P(1);
02246
02247 PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) >= 0);
02248 }
02249
02250 Datum
02251 interval_cmp(PG_FUNCTION_ARGS)
02252 {
02253 Interval *interval1 = PG_GETARG_INTERVAL_P(0);
02254 Interval *interval2 = PG_GETARG_INTERVAL_P(1);
02255
02256 PG_RETURN_INT32(interval_cmp_internal(interval1, interval2));
02257 }
02258
02259
02260
02261
02262
02263
02264
02265
02266 Datum
02267 interval_hash(PG_FUNCTION_ARGS)
02268 {
02269 Interval *interval = PG_GETARG_INTERVAL_P(0);
02270 TimeOffset span = interval_cmp_value(interval);
02271
02272 #ifdef HAVE_INT64_TIMESTAMP
02273 return DirectFunctionCall1(hashint8, Int64GetDatumFast(span));
02274 #else
02275 return DirectFunctionCall1(hashfloat8, Float8GetDatumFast(span));
02276 #endif
02277 }
02278
02279
02280
02281
02282
02283
02284
02285 Datum
02286 overlaps_timestamp(PG_FUNCTION_ARGS)
02287 {
02288
02289
02290
02291
02292
02293 Datum ts1 = PG_GETARG_DATUM(0);
02294 Datum te1 = PG_GETARG_DATUM(1);
02295 Datum ts2 = PG_GETARG_DATUM(2);
02296 Datum te2 = PG_GETARG_DATUM(3);
02297 bool ts1IsNull = PG_ARGISNULL(0);
02298 bool te1IsNull = PG_ARGISNULL(1);
02299 bool ts2IsNull = PG_ARGISNULL(2);
02300 bool te2IsNull = PG_ARGISNULL(3);
02301
02302 #define TIMESTAMP_GT(t1,t2) \
02303 DatumGetBool(DirectFunctionCall2(timestamp_gt,t1,t2))
02304 #define TIMESTAMP_LT(t1,t2) \
02305 DatumGetBool(DirectFunctionCall2(timestamp_lt,t1,t2))
02306
02307
02308
02309
02310
02311
02312 if (ts1IsNull)
02313 {
02314 if (te1IsNull)
02315 PG_RETURN_NULL();
02316
02317 ts1 = te1;
02318 te1IsNull = true;
02319 }
02320 else if (!te1IsNull)
02321 {
02322 if (TIMESTAMP_GT(ts1, te1))
02323 {
02324 Datum tt = ts1;
02325
02326 ts1 = te1;
02327 te1 = tt;
02328 }
02329 }
02330
02331
02332 if (ts2IsNull)
02333 {
02334 if (te2IsNull)
02335 PG_RETURN_NULL();
02336
02337 ts2 = te2;
02338 te2IsNull = true;
02339 }
02340 else if (!te2IsNull)
02341 {
02342 if (TIMESTAMP_GT(ts2, te2))
02343 {
02344 Datum tt = ts2;
02345
02346 ts2 = te2;
02347 te2 = tt;
02348 }
02349 }
02350
02351
02352
02353
02354
02355 if (TIMESTAMP_GT(ts1, ts2))
02356 {
02357
02358
02359
02360
02361 if (te2IsNull)
02362 PG_RETURN_NULL();
02363 if (TIMESTAMP_LT(ts1, te2))
02364 PG_RETURN_BOOL(true);
02365 if (te1IsNull)
02366 PG_RETURN_NULL();
02367
02368
02369
02370
02371
02372 PG_RETURN_BOOL(false);
02373 }
02374 else if (TIMESTAMP_LT(ts1, ts2))
02375 {
02376
02377 if (te1IsNull)
02378 PG_RETURN_NULL();
02379 if (TIMESTAMP_LT(ts2, te1))
02380 PG_RETURN_BOOL(true);
02381 if (te2IsNull)
02382 PG_RETURN_NULL();
02383
02384
02385
02386
02387
02388 PG_RETURN_BOOL(false);
02389 }
02390 else
02391 {
02392
02393
02394
02395
02396 if (te1IsNull || te2IsNull)
02397 PG_RETURN_NULL();
02398 PG_RETURN_BOOL(true);
02399 }
02400
02401 #undef TIMESTAMP_GT
02402 #undef TIMESTAMP_LT
02403 }
02404
02405
02406
02407
02408
02409
02410 Datum
02411 timestamp_smaller(PG_FUNCTION_ARGS)
02412 {
02413 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
02414 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
02415 Timestamp result;
02416
02417
02418 if (timestamp_cmp_internal(dt1, dt2) < 0)
02419 result = dt1;
02420 else
02421 result = dt2;
02422 PG_RETURN_TIMESTAMP(result);
02423 }
02424
02425 Datum
02426 timestamp_larger(PG_FUNCTION_ARGS)
02427 {
02428 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
02429 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
02430 Timestamp result;
02431
02432 if (timestamp_cmp_internal(dt1, dt2) > 0)
02433 result = dt1;
02434 else
02435 result = dt2;
02436 PG_RETURN_TIMESTAMP(result);
02437 }
02438
02439
02440 Datum
02441 timestamp_mi(PG_FUNCTION_ARGS)
02442 {
02443 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
02444 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
02445 Interval *result;
02446
02447 result = (Interval *) palloc(sizeof(Interval));
02448
02449 if (TIMESTAMP_NOT_FINITE(dt1) || TIMESTAMP_NOT_FINITE(dt2))
02450 ereport(ERROR,
02451 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
02452 errmsg("cannot subtract infinite timestamps")));
02453
02454 result->time = dt1 - dt2;
02455
02456 result->month = 0;
02457 result->day = 0;
02458
02459
02460
02461
02462
02463
02464
02465
02466
02467
02468
02469
02470
02471
02472
02473
02474
02475
02476
02477
02478
02479
02480
02481
02482
02483
02484 result = DatumGetIntervalP(DirectFunctionCall1(interval_justify_hours,
02485 IntervalPGetDatum(result)));
02486
02487 PG_RETURN_INTERVAL_P(result);
02488 }
02489
02490
02491
02492
02493
02494
02495
02496
02497
02498
02499
02500
02501
02502 Datum
02503 interval_justify_interval(PG_FUNCTION_ARGS)
02504 {
02505 Interval *span = PG_GETARG_INTERVAL_P(0);
02506 Interval *result;
02507 TimeOffset wholeday;
02508 int32 wholemonth;
02509
02510 result = (Interval *) palloc(sizeof(Interval));
02511 result->month = span->month;
02512 result->day = span->day;
02513 result->time = span->time;
02514
02515 #ifdef HAVE_INT64_TIMESTAMP
02516 TMODULO(result->time, wholeday, USECS_PER_DAY);
02517 #else
02518 TMODULO(result->time, wholeday, (double) SECS_PER_DAY);
02519 #endif
02520 result->day += wholeday;
02521
02522 wholemonth = result->day / DAYS_PER_MONTH;
02523 result->day -= wholemonth * DAYS_PER_MONTH;
02524 result->month += wholemonth;
02525
02526 if (result->month > 0 &&
02527 (result->day < 0 || (result->day == 0 && result->time < 0)))
02528 {
02529 result->day += DAYS_PER_MONTH;
02530 result->month--;
02531 }
02532 else if (result->month < 0 &&
02533 (result->day > 0 || (result->day == 0 && result->time > 0)))
02534 {
02535 result->day -= DAYS_PER_MONTH;
02536 result->month++;
02537 }
02538
02539 if (result->day > 0 && result->time < 0)
02540 {
02541 #ifdef HAVE_INT64_TIMESTAMP
02542 result->time += USECS_PER_DAY;
02543 #else
02544 result->time += (double) SECS_PER_DAY;
02545 #endif
02546 result->day--;
02547 }
02548 else if (result->day < 0 && result->time > 0)
02549 {
02550 #ifdef HAVE_INT64_TIMESTAMP
02551 result->time -= USECS_PER_DAY;
02552 #else
02553 result->time -= (double) SECS_PER_DAY;
02554 #endif
02555 result->day++;
02556 }
02557
02558 PG_RETURN_INTERVAL_P(result);
02559 }
02560
02561
02562
02563
02564
02565
02566
02567
02568
02569 Datum
02570 interval_justify_hours(PG_FUNCTION_ARGS)
02571 {
02572 Interval *span = PG_GETARG_INTERVAL_P(0);
02573 Interval *result;
02574 TimeOffset wholeday;
02575
02576 result = (Interval *) palloc(sizeof(Interval));
02577 result->month = span->month;
02578 result->day = span->day;
02579 result->time = span->time;
02580
02581 #ifdef HAVE_INT64_TIMESTAMP
02582 TMODULO(result->time, wholeday, USECS_PER_DAY);
02583 #else
02584 TMODULO(result->time, wholeday, (double) SECS_PER_DAY);
02585 #endif
02586 result->day += wholeday;
02587
02588 if (result->day > 0 && result->time < 0)
02589 {
02590 #ifdef HAVE_INT64_TIMESTAMP
02591 result->time += USECS_PER_DAY;
02592 #else
02593 result->time += (double) SECS_PER_DAY;
02594 #endif
02595 result->day--;
02596 }
02597 else if (result->day < 0 && result->time > 0)
02598 {
02599 #ifdef HAVE_INT64_TIMESTAMP
02600 result->time -= USECS_PER_DAY;
02601 #else
02602 result->time -= (double) SECS_PER_DAY;
02603 #endif
02604 result->day++;
02605 }
02606
02607 PG_RETURN_INTERVAL_P(result);
02608 }
02609
02610
02611
02612
02613
02614
02615
02616 Datum
02617 interval_justify_days(PG_FUNCTION_ARGS)
02618 {
02619 Interval *span = PG_GETARG_INTERVAL_P(0);
02620 Interval *result;
02621 int32 wholemonth;
02622
02623 result = (Interval *) palloc(sizeof(Interval));
02624 result->month = span->month;
02625 result->day = span->day;
02626 result->time = span->time;
02627
02628 wholemonth = result->day / DAYS_PER_MONTH;
02629 result->day -= wholemonth * DAYS_PER_MONTH;
02630 result->month += wholemonth;
02631
02632 if (result->month > 0 && result->day < 0)
02633 {
02634 result->day += DAYS_PER_MONTH;
02635 result->month--;
02636 }
02637 else if (result->month < 0 && result->day > 0)
02638 {
02639 result->day -= DAYS_PER_MONTH;
02640 result->month++;
02641 }
02642
02643 PG_RETURN_INTERVAL_P(result);
02644 }
02645
02646
02647
02648
02649
02650
02651
02652
02653
02654
02655
02656 Datum
02657 timestamp_pl_interval(PG_FUNCTION_ARGS)
02658 {
02659 Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
02660 Interval *span = PG_GETARG_INTERVAL_P(1);
02661 Timestamp result;
02662
02663 if (TIMESTAMP_NOT_FINITE(timestamp))
02664 result = timestamp;
02665 else
02666 {
02667 if (span->month != 0)
02668 {
02669 struct pg_tm tt,
02670 *tm = &tt;
02671 fsec_t fsec;
02672
02673 if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
02674 ereport(ERROR,
02675 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
02676 errmsg("timestamp out of range")));
02677
02678 tm->tm_mon += span->month;
02679 if (tm->tm_mon > MONTHS_PER_YEAR)
02680 {
02681 tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
02682 tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1;
02683 }
02684 else if (tm->tm_mon < 1)
02685 {
02686 tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1;
02687 tm->tm_mon = tm->tm_mon % MONTHS_PER_YEAR + MONTHS_PER_YEAR;
02688 }
02689
02690
02691 if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
02692 tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
02693
02694 if (tm2timestamp(tm, fsec, NULL, ×tamp) != 0)
02695 ereport(ERROR,
02696 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
02697 errmsg("timestamp out of range")));
02698 }
02699
02700 if (span->day != 0)
02701 {
02702 struct pg_tm tt,
02703 *tm = &tt;
02704 fsec_t fsec;
02705 int julian;
02706
02707 if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
02708 ereport(ERROR,
02709 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
02710 errmsg("timestamp out of range")));
02711
02712
02713 julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + span->day;
02714 j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
02715
02716 if (tm2timestamp(tm, fsec, NULL, ×tamp) != 0)
02717 ereport(ERROR,
02718 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
02719 errmsg("timestamp out of range")));
02720 }
02721
02722 timestamp += span->time;
02723 result = timestamp;
02724 }
02725
02726 PG_RETURN_TIMESTAMP(result);
02727 }
02728
02729 Datum
02730 timestamp_mi_interval(PG_FUNCTION_ARGS)
02731 {
02732 Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
02733 Interval *span = PG_GETARG_INTERVAL_P(1);
02734 Interval tspan;
02735
02736 tspan.month = -span->month;
02737 tspan.day = -span->day;
02738 tspan.time = -span->time;
02739
02740 return DirectFunctionCall2(timestamp_pl_interval,
02741 TimestampGetDatum(timestamp),
02742 PointerGetDatum(&tspan));
02743 }
02744
02745
02746
02747
02748
02749
02750
02751
02752
02753
02754
02755 Datum
02756 timestamptz_pl_interval(PG_FUNCTION_ARGS)
02757 {
02758 TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
02759 Interval *span = PG_GETARG_INTERVAL_P(1);
02760 TimestampTz result;
02761 int tz;
02762
02763 if (TIMESTAMP_NOT_FINITE(timestamp))
02764 result = timestamp;
02765 else
02766 {
02767 if (span->month != 0)
02768 {
02769 struct pg_tm tt,
02770 *tm = &tt;
02771 fsec_t fsec;
02772
02773 if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
02774 ereport(ERROR,
02775 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
02776 errmsg("timestamp out of range")));
02777
02778 tm->tm_mon += span->month;
02779 if (tm->tm_mon > MONTHS_PER_YEAR)
02780 {
02781 tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
02782 tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1;
02783 }
02784 else if (tm->tm_mon < 1)
02785 {
02786 tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1;
02787 tm->tm_mon = tm->tm_mon % MONTHS_PER_YEAR + MONTHS_PER_YEAR;
02788 }
02789
02790
02791 if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
02792 tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
02793
02794 tz = DetermineTimeZoneOffset(tm, session_timezone);
02795
02796 if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0)
02797 ereport(ERROR,
02798 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
02799 errmsg("timestamp out of range")));
02800 }
02801
02802 if (span->day != 0)
02803 {
02804 struct pg_tm tt,
02805 *tm = &tt;
02806 fsec_t fsec;
02807 int julian;
02808
02809 if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
02810 ereport(ERROR,
02811 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
02812 errmsg("timestamp out of range")));
02813
02814
02815 julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + span->day;
02816 j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
02817
02818 tz = DetermineTimeZoneOffset(tm, session_timezone);
02819
02820 if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0)
02821 ereport(ERROR,
02822 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
02823 errmsg("timestamp out of range")));
02824 }
02825
02826 timestamp += span->time;
02827 result = timestamp;
02828 }
02829
02830 PG_RETURN_TIMESTAMP(result);
02831 }
02832
02833 Datum
02834 timestamptz_mi_interval(PG_FUNCTION_ARGS)
02835 {
02836 TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
02837 Interval *span = PG_GETARG_INTERVAL_P(1);
02838 Interval tspan;
02839
02840 tspan.month = -span->month;
02841 tspan.day = -span->day;
02842 tspan.time = -span->time;
02843
02844 return DirectFunctionCall2(timestamptz_pl_interval,
02845 TimestampGetDatum(timestamp),
02846 PointerGetDatum(&tspan));
02847 }
02848
02849
02850 Datum
02851 interval_um(PG_FUNCTION_ARGS)
02852 {
02853 Interval *interval = PG_GETARG_INTERVAL_P(0);
02854 Interval *result;
02855
02856 result = (Interval *) palloc(sizeof(Interval));
02857
02858 result->time = -interval->time;
02859 result->day = -interval->day;
02860 result->month = -interval->month;
02861
02862 PG_RETURN_INTERVAL_P(result);
02863 }
02864
02865
02866 Datum
02867 interval_smaller(PG_FUNCTION_ARGS)
02868 {
02869 Interval *interval1 = PG_GETARG_INTERVAL_P(0);
02870 Interval *interval2 = PG_GETARG_INTERVAL_P(1);
02871 Interval *result;
02872
02873
02874 if (interval_cmp_internal(interval1, interval2) < 0)
02875 result = interval1;
02876 else
02877 result = interval2;
02878 PG_RETURN_INTERVAL_P(result);
02879 }
02880
02881 Datum
02882 interval_larger(PG_FUNCTION_ARGS)
02883 {
02884 Interval *interval1 = PG_GETARG_INTERVAL_P(0);
02885 Interval *interval2 = PG_GETARG_INTERVAL_P(1);
02886 Interval *result;
02887
02888 if (interval_cmp_internal(interval1, interval2) > 0)
02889 result = interval1;
02890 else
02891 result = interval2;
02892 PG_RETURN_INTERVAL_P(result);
02893 }
02894
02895 Datum
02896 interval_pl(PG_FUNCTION_ARGS)
02897 {
02898 Interval *span1 = PG_GETARG_INTERVAL_P(0);
02899 Interval *span2 = PG_GETARG_INTERVAL_P(1);
02900 Interval *result;
02901
02902 result = (Interval *) palloc(sizeof(Interval));
02903
02904 result->month = span1->month + span2->month;
02905 result->day = span1->day + span2->day;
02906 result->time = span1->time + span2->time;
02907
02908 PG_RETURN_INTERVAL_P(result);
02909 }
02910
02911 Datum
02912 interval_mi(PG_FUNCTION_ARGS)
02913 {
02914 Interval *span1 = PG_GETARG_INTERVAL_P(0);
02915 Interval *span2 = PG_GETARG_INTERVAL_P(1);
02916 Interval *result;
02917
02918 result = (Interval *) palloc(sizeof(Interval));
02919
02920 result->month = span1->month - span2->month;
02921 result->day = span1->day - span2->day;
02922 result->time = span1->time - span2->time;
02923
02924 PG_RETURN_INTERVAL_P(result);
02925 }
02926
02927
02928
02929
02930
02931
02932
02933 Datum
02934 interval_mul(PG_FUNCTION_ARGS)
02935 {
02936 Interval *span = PG_GETARG_INTERVAL_P(0);
02937 float8 factor = PG_GETARG_FLOAT8(1);
02938 double month_remainder_days,
02939 sec_remainder;
02940 int32 orig_month = span->month,
02941 orig_day = span->day;
02942 Interval *result;
02943
02944 result = (Interval *) palloc(sizeof(Interval));
02945
02946 result->month = (int32) (span->month * factor);
02947 result->day = (int32) (span->day * factor);
02948
02949
02950
02951
02952
02953
02954
02955
02956
02957
02958
02959
02960
02961
02962
02963
02964
02965
02966
02967 month_remainder_days = (orig_month * factor - result->month) * DAYS_PER_MONTH;
02968 month_remainder_days = TSROUND(month_remainder_days);
02969 sec_remainder = (orig_day * factor - result->day +
02970 month_remainder_days - (int) month_remainder_days) * SECS_PER_DAY;
02971 sec_remainder = TSROUND(sec_remainder);
02972
02973
02974
02975
02976
02977
02978 if (Abs(sec_remainder) >= SECS_PER_DAY)
02979 {
02980 result->day += (int) (sec_remainder / SECS_PER_DAY);
02981 sec_remainder -= (int) (sec_remainder / SECS_PER_DAY) * SECS_PER_DAY;
02982 }
02983
02984
02985 result->day += (int32) month_remainder_days;
02986 #ifdef HAVE_INT64_TIMESTAMP
02987 result->time = rint(span->time * factor + sec_remainder * USECS_PER_SEC);
02988 #else
02989 result->time = span->time * factor + sec_remainder;
02990 #endif
02991
02992 PG_RETURN_INTERVAL_P(result);
02993 }
02994
02995 Datum
02996 mul_d_interval(PG_FUNCTION_ARGS)
02997 {
02998
02999 Datum factor = PG_GETARG_DATUM(0);
03000 Datum span = PG_GETARG_DATUM(1);
03001
03002 return DirectFunctionCall2(interval_mul, span, factor);
03003 }
03004
03005 Datum
03006 interval_div(PG_FUNCTION_ARGS)
03007 {
03008 Interval *span = PG_GETARG_INTERVAL_P(0);
03009 float8 factor = PG_GETARG_FLOAT8(1);
03010 double month_remainder_days,
03011 sec_remainder;
03012 int32 orig_month = span->month,
03013 orig_day = span->day;
03014 Interval *result;
03015
03016 result = (Interval *) palloc(sizeof(Interval));
03017
03018 if (factor == 0.0)
03019 ereport(ERROR,
03020 (errcode(ERRCODE_DIVISION_BY_ZERO),
03021 errmsg("division by zero")));
03022
03023 result->month = (int32) (span->month / factor);
03024 result->day = (int32) (span->day / factor);
03025
03026
03027
03028
03029 month_remainder_days = (orig_month / factor - result->month) * DAYS_PER_MONTH;
03030 month_remainder_days = TSROUND(month_remainder_days);
03031 sec_remainder = (orig_day / factor - result->day +
03032 month_remainder_days - (int) month_remainder_days) * SECS_PER_DAY;
03033 sec_remainder = TSROUND(sec_remainder);
03034 if (Abs(sec_remainder) >= SECS_PER_DAY)
03035 {
03036 result->day += (int) (sec_remainder / SECS_PER_DAY);
03037 sec_remainder -= (int) (sec_remainder / SECS_PER_DAY) * SECS_PER_DAY;
03038 }
03039
03040
03041 result->day += (int32) month_remainder_days;
03042 #ifdef HAVE_INT64_TIMESTAMP
03043 result->time = rint(span->time / factor + sec_remainder * USECS_PER_SEC);
03044 #else
03045
03046 result->time = span->time / factor + sec_remainder;
03047 #endif
03048
03049 PG_RETURN_INTERVAL_P(result);
03050 }
03051
03052
03053
03054
03055
03056
03057
03058
03059
03060
03061 Datum
03062 interval_accum(PG_FUNCTION_ARGS)
03063 {
03064 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
03065 Interval *newval = PG_GETARG_INTERVAL_P(1);
03066 Datum *transdatums;
03067 int ndatums;
03068 Interval sumX,
03069 N;
03070 Interval *newsum;
03071 ArrayType *result;
03072
03073 deconstruct_array(transarray,
03074 INTERVALOID, sizeof(Interval), false, 'd',
03075 &transdatums, NULL, &ndatums);
03076 if (ndatums != 2)
03077 elog(ERROR, "expected 2-element interval array");
03078
03079
03080
03081
03082
03083
03084
03085
03086
03087
03088 memcpy((void *) &sumX, DatumGetPointer(transdatums[0]), sizeof(Interval));
03089 memcpy((void *) &N, DatumGetPointer(transdatums[1]), sizeof(Interval));
03090
03091 newsum = DatumGetIntervalP(DirectFunctionCall2(interval_pl,
03092 IntervalPGetDatum(&sumX),
03093 IntervalPGetDatum(newval)));
03094 N.time += 1;
03095
03096 transdatums[0] = IntervalPGetDatum(newsum);
03097 transdatums[1] = IntervalPGetDatum(&N);
03098
03099 result = construct_array(transdatums, 2,
03100 INTERVALOID, sizeof(Interval), false, 'd');
03101
03102 PG_RETURN_ARRAYTYPE_P(result);
03103 }
03104
03105 Datum
03106 interval_avg(PG_FUNCTION_ARGS)
03107 {
03108 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
03109 Datum *transdatums;
03110 int ndatums;
03111 Interval sumX,
03112 N;
03113
03114 deconstruct_array(transarray,
03115 INTERVALOID, sizeof(Interval), false, 'd',
03116 &transdatums, NULL, &ndatums);
03117 if (ndatums != 2)
03118 elog(ERROR, "expected 2-element interval array");
03119
03120
03121
03122
03123
03124
03125
03126
03127
03128
03129 memcpy((void *) &sumX, DatumGetPointer(transdatums[0]), sizeof(Interval));
03130 memcpy((void *) &N, DatumGetPointer(transdatums[1]), sizeof(Interval));
03131
03132
03133 if (N.time == 0)
03134 PG_RETURN_NULL();
03135
03136 return DirectFunctionCall2(interval_div,
03137 IntervalPGetDatum(&sumX),
03138 Float8GetDatum(N.time));
03139 }
03140
03141
03142
03143
03144
03145
03146
03147
03148 Datum
03149 timestamp_age(PG_FUNCTION_ARGS)
03150 {
03151 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
03152 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
03153 Interval *result;
03154 fsec_t fsec,
03155 fsec1,
03156 fsec2;
03157 struct pg_tm tt,
03158 *tm = &tt;
03159 struct pg_tm tt1,
03160 *tm1 = &tt1;
03161 struct pg_tm tt2,
03162 *tm2 = &tt2;
03163
03164 result = (Interval *) palloc(sizeof(Interval));
03165
03166 if (timestamp2tm(dt1, NULL, tm1, &fsec1, NULL, NULL) == 0 &&
03167 timestamp2tm(dt2, NULL, tm2, &fsec2, NULL, NULL) == 0)
03168 {
03169
03170 fsec = fsec1 - fsec2;
03171 tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
03172 tm->tm_min = tm1->tm_min - tm2->tm_min;
03173 tm->tm_hour = tm1->tm_hour - tm2->tm_hour;
03174 tm->tm_mday = tm1->tm_mday - tm2->tm_mday;
03175 tm->tm_mon = tm1->tm_mon - tm2->tm_mon;
03176 tm->tm_year = tm1->tm_year - tm2->tm_year;
03177
03178
03179 if (dt1 < dt2)
03180 {
03181 fsec = -fsec;
03182 tm->tm_sec = -tm->tm_sec;
03183 tm->tm_min = -tm->tm_min;
03184 tm->tm_hour = -tm->tm_hour;
03185 tm->tm_mday = -tm->tm_mday;
03186 tm->tm_mon = -tm->tm_mon;
03187 tm->tm_year = -tm->tm_year;
03188 }
03189
03190
03191 while (fsec < 0)
03192 {
03193 #ifdef HAVE_INT64_TIMESTAMP
03194 fsec += USECS_PER_SEC;
03195 #else
03196 fsec += 1.0;
03197 #endif
03198 tm->tm_sec--;
03199 }
03200
03201 while (tm->tm_sec < 0)
03202 {
03203 tm->tm_sec += SECS_PER_MINUTE;
03204 tm->tm_min--;
03205 }
03206
03207 while (tm->tm_min < 0)
03208 {
03209 tm->tm_min += MINS_PER_HOUR;
03210 tm->tm_hour--;
03211 }
03212
03213 while (tm->tm_hour < 0)
03214 {
03215 tm->tm_hour += HOURS_PER_DAY;
03216 tm->tm_mday--;
03217 }
03218
03219 while (tm->tm_mday < 0)
03220 {
03221 if (dt1 < dt2)
03222 {
03223 tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
03224 tm->tm_mon--;
03225 }
03226 else
03227 {
03228 tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
03229 tm->tm_mon--;
03230 }
03231 }
03232
03233 while (tm->tm_mon < 0)
03234 {
03235 tm->tm_mon += MONTHS_PER_YEAR;
03236 tm->tm_year--;
03237 }
03238
03239
03240 if (dt1 < dt2)
03241 {
03242 fsec = -fsec;
03243 tm->tm_sec = -tm->tm_sec;
03244 tm->tm_min = -tm->tm_min;
03245 tm->tm_hour = -tm->tm_hour;
03246 tm->tm_mday = -tm->tm_mday;
03247 tm->tm_mon = -tm->tm_mon;
03248 tm->tm_year = -tm->tm_year;
03249 }
03250
03251 if (tm2interval(tm, fsec, result) != 0)
03252 ereport(ERROR,
03253 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
03254 errmsg("interval out of range")));
03255 }
03256 else
03257 ereport(ERROR,
03258 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
03259 errmsg("timestamp out of range")));
03260
03261 PG_RETURN_INTERVAL_P(result);
03262 }
03263
03264
03265
03266
03267
03268
03269
03270
03271 Datum
03272 timestamptz_age(PG_FUNCTION_ARGS)
03273 {
03274 TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
03275 TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
03276 Interval *result;
03277 fsec_t fsec,
03278 fsec1,
03279 fsec2;
03280 struct pg_tm tt,
03281 *tm = &tt;
03282 struct pg_tm tt1,
03283 *tm1 = &tt1;
03284 struct pg_tm tt2,
03285 *tm2 = &tt2;
03286 int tz1;
03287 int tz2;
03288
03289 result = (Interval *) palloc(sizeof(Interval));
03290
03291 if (timestamp2tm(dt1, &tz1, tm1, &fsec1, NULL, NULL) == 0 &&
03292 timestamp2tm(dt2, &tz2, tm2, &fsec2, NULL, NULL) == 0)
03293 {
03294
03295 fsec = fsec1 - fsec2;
03296 tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
03297 tm->tm_min = tm1->tm_min - tm2->tm_min;
03298 tm->tm_hour = tm1->tm_hour - tm2->tm_hour;
03299 tm->tm_mday = tm1->tm_mday - tm2->tm_mday;
03300 tm->tm_mon = tm1->tm_mon - tm2->tm_mon;
03301 tm->tm_year = tm1->tm_year - tm2->tm_year;
03302
03303
03304 if (dt1 < dt2)
03305 {
03306 fsec = -fsec;
03307 tm->tm_sec = -tm->tm_sec;
03308 tm->tm_min = -tm->tm_min;
03309 tm->tm_hour = -tm->tm_hour;
03310 tm->tm_mday = -tm->tm_mday;
03311 tm->tm_mon = -tm->tm_mon;
03312 tm->tm_year = -tm->tm_year;
03313 }
03314
03315
03316 while (fsec < 0)
03317 {
03318 #ifdef HAVE_INT64_TIMESTAMP
03319 fsec += USECS_PER_SEC;
03320 #else
03321 fsec += 1.0;
03322 #endif
03323 tm->tm_sec--;
03324 }
03325
03326 while (tm->tm_sec < 0)
03327 {
03328 tm->tm_sec += SECS_PER_MINUTE;
03329 tm->tm_min--;
03330 }
03331
03332 while (tm->tm_min < 0)
03333 {
03334 tm->tm_min += MINS_PER_HOUR;
03335 tm->tm_hour--;
03336 }
03337
03338 while (tm->tm_hour < 0)
03339 {
03340 tm->tm_hour += HOURS_PER_DAY;
03341 tm->tm_mday--;
03342 }
03343
03344 while (tm->tm_mday < 0)
03345 {
03346 if (dt1 < dt2)
03347 {
03348 tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
03349 tm->tm_mon--;
03350 }
03351 else
03352 {
03353 tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
03354 tm->tm_mon--;
03355 }
03356 }
03357
03358 while (tm->tm_mon < 0)
03359 {
03360 tm->tm_mon += MONTHS_PER_YEAR;
03361 tm->tm_year--;
03362 }
03363
03364
03365
03366
03367
03368
03369 if (dt1 < dt2)
03370 {
03371 fsec = -fsec;
03372 tm->tm_sec = -tm->tm_sec;
03373 tm->tm_min = -tm->tm_min;
03374 tm->tm_hour = -tm->tm_hour;
03375 tm->tm_mday = -tm->tm_mday;
03376 tm->tm_mon = -tm->tm_mon;
03377 tm->tm_year = -tm->tm_year;
03378 }
03379
03380 if (tm2interval(tm, fsec, result) != 0)
03381 ereport(ERROR,
03382 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
03383 errmsg("interval out of range")));
03384 }
03385 else
03386 ereport(ERROR,
03387 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
03388 errmsg("timestamp out of range")));
03389
03390 PG_RETURN_INTERVAL_P(result);
03391 }
03392
03393
03394
03395
03396
03397
03398
03399
03400
03401
03402 Datum
03403 timestamp_trunc(PG_FUNCTION_ARGS)
03404 {
03405 text *units = PG_GETARG_TEXT_PP(0);
03406 Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
03407 Timestamp result;
03408 int type,
03409 val;
03410 char *lowunits;
03411 fsec_t fsec;
03412 struct pg_tm tt,
03413 *tm = &tt;
03414
03415 if (TIMESTAMP_NOT_FINITE(timestamp))
03416 PG_RETURN_TIMESTAMP(timestamp);
03417
03418 lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
03419 VARSIZE_ANY_EXHDR(units),
03420 false);
03421
03422 type = DecodeUnits(0, lowunits, &val);
03423
03424 if (type == UNITS)
03425 {
03426 if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
03427 ereport(ERROR,
03428 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
03429 errmsg("timestamp out of range")));
03430
03431 switch (val)
03432 {
03433 case DTK_WEEK:
03434 {
03435 int woy;
03436
03437 woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
03438
03439
03440
03441
03442
03443
03444 if (woy >= 52 && tm->tm_mon == 1)
03445 --tm->tm_year;
03446 if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
03447 ++tm->tm_year;
03448 isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
03449 tm->tm_hour = 0;
03450 tm->tm_min = 0;
03451 tm->tm_sec = 0;
03452 fsec = 0;
03453 break;
03454 }
03455 case DTK_MILLENNIUM:
03456
03457 if (tm->tm_year > 0)
03458 tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999;
03459 else
03460 tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1;
03461 case DTK_CENTURY:
03462
03463 if (tm->tm_year > 0)
03464 tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99;
03465 else
03466 tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1;
03467 case DTK_DECADE:
03468
03469 if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
03470 {
03471 if (tm->tm_year > 0)
03472 tm->tm_year = (tm->tm_year / 10) * 10;
03473 else
03474 tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
03475 }
03476 case DTK_YEAR:
03477 tm->tm_mon = 1;
03478 case DTK_QUARTER:
03479 tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1;
03480 case DTK_MONTH:
03481 tm->tm_mday = 1;
03482 case DTK_DAY:
03483 tm->tm_hour = 0;
03484 case DTK_HOUR:
03485 tm->tm_min = 0;
03486 case DTK_MINUTE:
03487 tm->tm_sec = 0;
03488 case DTK_SECOND:
03489 fsec = 0;
03490 break;
03491
03492 case DTK_MILLISEC:
03493 #ifdef HAVE_INT64_TIMESTAMP
03494 fsec = (fsec / 1000) * 1000;
03495 #else
03496 fsec = floor(fsec * 1000) / 1000;
03497 #endif
03498 break;
03499
03500 case DTK_MICROSEC:
03501 #ifndef HAVE_INT64_TIMESTAMP
03502 fsec = floor(fsec * 1000000) / 1000000;
03503 #endif
03504 break;
03505
03506 default:
03507 ereport(ERROR,
03508 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
03509 errmsg("timestamp units \"%s\" not supported",
03510 lowunits)));
03511 result = 0;
03512 }
03513
03514 if (tm2timestamp(tm, fsec, NULL, &result) != 0)
03515 ereport(ERROR,
03516 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
03517 errmsg("timestamp out of range")));
03518 }
03519 else
03520 {
03521 ereport(ERROR,
03522 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
03523 errmsg("timestamp units \"%s\" not recognized",
03524 lowunits)));
03525 result = 0;
03526 }
03527
03528 PG_RETURN_TIMESTAMP(result);
03529 }
03530
03531
03532
03533
03534 Datum
03535 timestamptz_trunc(PG_FUNCTION_ARGS)
03536 {
03537 text *units = PG_GETARG_TEXT_PP(0);
03538 TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
03539 TimestampTz result;
03540 int tz;
03541 int type,
03542 val;
03543 bool redotz = false;
03544 char *lowunits;
03545 fsec_t fsec;
03546 struct pg_tm tt,
03547 *tm = &tt;
03548
03549 if (TIMESTAMP_NOT_FINITE(timestamp))
03550 PG_RETURN_TIMESTAMPTZ(timestamp);
03551
03552 lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
03553 VARSIZE_ANY_EXHDR(units),
03554 false);
03555
03556 type = DecodeUnits(0, lowunits, &val);
03557
03558 if (type == UNITS)
03559 {
03560 if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
03561 ereport(ERROR,
03562 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
03563 errmsg("timestamp out of range")));
03564
03565 switch (val)
03566 {
03567 case DTK_WEEK:
03568 {
03569 int woy;
03570
03571 woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
03572
03573
03574
03575
03576
03577
03578 if (woy >= 52 && tm->tm_mon == 1)
03579 --tm->tm_year;
03580 if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
03581 ++tm->tm_year;
03582 isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
03583 tm->tm_hour = 0;
03584 tm->tm_min = 0;
03585 tm->tm_sec = 0;
03586 fsec = 0;
03587 redotz = true;
03588 break;
03589 }
03590
03591 case DTK_MILLENNIUM:
03592
03593
03594
03595
03596
03597
03598 if (tm->tm_year > 0)
03599 tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999;
03600 else
03601 tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1;
03602
03603 case DTK_CENTURY:
03604
03605 if (tm->tm_year > 0)
03606 tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99;
03607 else
03608 tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1;
03609
03610 case DTK_DECADE:
03611
03612
03613
03614
03615
03616 if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
03617 {
03618 if (tm->tm_year > 0)
03619 tm->tm_year = (tm->tm_year / 10) * 10;
03620 else
03621 tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
03622 }
03623
03624 case DTK_YEAR:
03625 tm->tm_mon = 1;
03626
03627 case DTK_QUARTER:
03628 tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1;
03629
03630 case DTK_MONTH:
03631 tm->tm_mday = 1;
03632
03633 case DTK_DAY:
03634 tm->tm_hour = 0;
03635 redotz = true;
03636
03637 case DTK_HOUR:
03638 tm->tm_min = 0;
03639
03640 case DTK_MINUTE:
03641 tm->tm_sec = 0;
03642
03643 case DTK_SECOND:
03644 fsec = 0;
03645 break;
03646
03647 case DTK_MILLISEC:
03648 #ifdef HAVE_INT64_TIMESTAMP
03649 fsec = (fsec / 1000) * 1000;
03650 #else
03651 fsec = floor(fsec * 1000) / 1000;
03652 #endif
03653 break;
03654 case DTK_MICROSEC:
03655 #ifndef HAVE_INT64_TIMESTAMP
03656 fsec = floor(fsec * 1000000) / 1000000;
03657 #endif
03658 break;
03659
03660 default:
03661 ereport(ERROR,
03662 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
03663 errmsg("timestamp with time zone units \"%s\" not "
03664 "supported", lowunits)));
03665 result = 0;
03666 }
03667
03668 if (redotz)
03669 tz = DetermineTimeZoneOffset(tm, session_timezone);
03670
03671 if (tm2timestamp(tm, fsec, &tz, &result) != 0)
03672 ereport(ERROR,
03673 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
03674 errmsg("timestamp out of range")));
03675 }
03676 else
03677 {
03678 ereport(ERROR,
03679 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
03680 errmsg("timestamp with time zone units \"%s\" not recognized",
03681 lowunits)));
03682 result = 0;
03683 }
03684
03685 PG_RETURN_TIMESTAMPTZ(result);
03686 }
03687
03688
03689
03690
03691 Datum
03692 interval_trunc(PG_FUNCTION_ARGS)
03693 {
03694 text *units = PG_GETARG_TEXT_PP(0);
03695 Interval *interval = PG_GETARG_INTERVAL_P(1);
03696 Interval *result;
03697 int type,
03698 val;
03699 char *lowunits;
03700 fsec_t fsec;
03701 struct pg_tm tt,
03702 *tm = &tt;
03703
03704 result = (Interval *) palloc(sizeof(Interval));
03705
03706 lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
03707 VARSIZE_ANY_EXHDR(units),
03708 false);
03709
03710 type = DecodeUnits(0, lowunits, &val);
03711
03712 if (type == UNITS)
03713 {
03714 if (interval2tm(*interval, tm, &fsec) == 0)
03715 {
03716 switch (val)
03717 {
03718
03719 case DTK_MILLENNIUM:
03720
03721 tm->tm_year = (tm->tm_year / 1000) * 1000;
03722 case DTK_CENTURY:
03723
03724 tm->tm_year = (tm->tm_year / 100) * 100;
03725 case DTK_DECADE:
03726
03727 tm->tm_year = (tm->tm_year / 10) * 10;
03728 case DTK_YEAR:
03729 tm->tm_mon = 0;
03730 case DTK_QUARTER:
03731 tm->tm_mon = 3 * (tm->tm_mon / 3);
03732 case DTK_MONTH:
03733 tm->tm_mday = 0;
03734 case DTK_DAY:
03735 tm->tm_hour = 0;
03736 case DTK_HOUR:
03737 tm->tm_min = 0;
03738 case DTK_MINUTE:
03739 tm->tm_sec = 0;
03740 case DTK_SECOND:
03741 fsec = 0;
03742 break;
03743
03744 case DTK_MILLISEC:
03745 #ifdef HAVE_INT64_TIMESTAMP
03746 fsec = (fsec / 1000) * 1000;
03747 #else
03748 fsec = floor(fsec * 1000) / 1000;
03749 #endif
03750 break;
03751 case DTK_MICROSEC:
03752 #ifndef HAVE_INT64_TIMESTAMP
03753 fsec = floor(fsec * 1000000) / 1000000;
03754 #endif
03755 break;
03756
03757 default:
03758 if (val == DTK_WEEK)
03759 ereport(ERROR,
03760 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
03761 errmsg("interval units \"%s\" not supported "
03762 "because months usually have fractional weeks",
03763 lowunits)));
03764 else
03765 ereport(ERROR,
03766 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
03767 errmsg("interval units \"%s\" not supported",
03768 lowunits)));
03769 }
03770
03771 if (tm2interval(tm, fsec, result) != 0)
03772 ereport(ERROR,
03773 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
03774 errmsg("interval out of range")));
03775 }
03776 else
03777 elog(ERROR, "could not convert interval to tm");
03778 }
03779 else
03780 {
03781 ereport(ERROR,
03782 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
03783 errmsg("interval units \"%s\" not recognized",
03784 lowunits)));
03785 }
03786
03787 PG_RETURN_INTERVAL_P(result);
03788 }
03789
03790
03791
03792
03793
03794
03795 int
03796 isoweek2j(int year, int week)
03797 {
03798 int day0,
03799 day4;
03800
03801
03802 day4 = date2j(year, 1, 4);
03803
03804
03805 day0 = j2day(day4 - 1);
03806
03807 return ((week - 1) * 7) + (day4 - day0);
03808 }
03809
03810
03811
03812
03813
03814
03815 void
03816 isoweek2date(int woy, int *year, int *mon, int *mday)
03817 {
03818 j2date(isoweek2j(*year, woy), year, mon, mday);
03819 }
03820
03821
03822
03823
03824
03825
03826
03827
03828 void
03829 isoweekdate2date(int isoweek, int wday, int *year, int *mon, int *mday)
03830 {
03831 int jday;
03832
03833 jday = isoweek2j(*year, isoweek);
03834
03835 if (wday > 1)
03836 jday += wday - 2;
03837 else
03838 jday += 6;
03839 j2date(jday, year, mon, mday);
03840 }
03841
03842
03843
03844
03845
03846 int
03847 date2isoweek(int year, int mon, int mday)
03848 {
03849 float8 result;
03850 int day0,
03851 day4,
03852 dayn;
03853
03854
03855 dayn = date2j(year, mon, mday);
03856
03857
03858 day4 = date2j(year, 1, 4);
03859
03860
03861 day0 = j2day(day4 - 1);
03862
03863
03864
03865
03866
03867 if (dayn < day4 - day0)
03868 {
03869 day4 = date2j(year - 1, 1, 4);
03870
03871
03872 day0 = j2day(day4 - 1);
03873 }
03874
03875 result = (dayn - (day4 - day0)) / 7 + 1;
03876
03877
03878
03879
03880
03881 if (result >= 52)
03882 {
03883 day4 = date2j(year + 1, 1, 4);
03884
03885
03886 day0 = j2day(day4 - 1);
03887
03888 if (dayn >= day4 - day0)
03889 result = (dayn - (day4 - day0)) / 7 + 1;
03890 }
03891
03892 return (int) result;
03893 }
03894
03895
03896
03897
03898
03899
03900 int
03901 date2isoyear(int year, int mon, int mday)
03902 {
03903 float8 result;
03904 int day0,
03905 day4,
03906 dayn;
03907
03908
03909 dayn = date2j(year, mon, mday);
03910
03911
03912 day4 = date2j(year, 1, 4);
03913
03914
03915 day0 = j2day(day4 - 1);
03916
03917
03918
03919
03920
03921 if (dayn < day4 - day0)
03922 {
03923 day4 = date2j(year - 1, 1, 4);
03924
03925
03926 day0 = j2day(day4 - 1);
03927
03928 year--;
03929 }
03930
03931 result = (dayn - (day4 - day0)) / 7 + 1;
03932
03933
03934
03935
03936
03937 if (result >= 52)
03938 {
03939 day4 = date2j(year + 1, 1, 4);
03940
03941
03942 day0 = j2day(day4 - 1);
03943
03944 if (dayn >= day4 - day0)
03945 year++;
03946 }
03947
03948 return year;
03949 }
03950
03951
03952
03953
03954
03955
03956
03957 int
03958 date2isoyearday(int year, int mon, int mday)
03959 {
03960 return date2j(year, mon, mday) - isoweek2j(date2isoyear(year, mon, mday), 1) + 1;
03961 }
03962
03963
03964
03965
03966 Datum
03967 timestamp_part(PG_FUNCTION_ARGS)
03968 {
03969 text *units = PG_GETARG_TEXT_PP(0);
03970 Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
03971 float8 result;
03972 int type,
03973 val;
03974 char *lowunits;
03975 fsec_t fsec;
03976 struct pg_tm tt,
03977 *tm = &tt;
03978
03979 if (TIMESTAMP_NOT_FINITE(timestamp))
03980 {
03981 result = 0;
03982 PG_RETURN_FLOAT8(result);
03983 }
03984
03985 lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
03986 VARSIZE_ANY_EXHDR(units),
03987 false);
03988
03989 type = DecodeUnits(0, lowunits, &val);
03990 if (type == UNKNOWN_FIELD)
03991 type = DecodeSpecial(0, lowunits, &val);
03992
03993 if (type == UNITS)
03994 {
03995 if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
03996 ereport(ERROR,
03997 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
03998 errmsg("timestamp out of range")));
03999
04000 switch (val)
04001 {
04002 case DTK_MICROSEC:
04003 #ifdef HAVE_INT64_TIMESTAMP
04004 result = tm->tm_sec * 1000000.0 + fsec;
04005 #else
04006 result = (tm->tm_sec + fsec) * 1000000;
04007 #endif
04008 break;
04009
04010 case DTK_MILLISEC:
04011 #ifdef HAVE_INT64_TIMESTAMP
04012 result = tm->tm_sec * 1000.0 + fsec / 1000.0;
04013 #else
04014 result = (tm->tm_sec + fsec) * 1000;
04015 #endif
04016 break;
04017
04018 case DTK_SECOND:
04019 #ifdef HAVE_INT64_TIMESTAMP
04020 result = tm->tm_sec + fsec / 1000000.0;
04021 #else
04022 result = tm->tm_sec + fsec;
04023 #endif
04024 break;
04025
04026 case DTK_MINUTE:
04027 result = tm->tm_min;
04028 break;
04029
04030 case DTK_HOUR:
04031 result = tm->tm_hour;
04032 break;
04033
04034 case DTK_DAY:
04035 result = tm->tm_mday;
04036 break;
04037
04038 case DTK_MONTH:
04039 result = tm->tm_mon;
04040 break;
04041
04042 case DTK_QUARTER:
04043 result = (tm->tm_mon - 1) / 3 + 1;
04044 break;
04045
04046 case DTK_WEEK:
04047 result = (float8) date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
04048 break;
04049
04050 case DTK_YEAR:
04051 if (tm->tm_year > 0)
04052 result = tm->tm_year;
04053 else
04054
04055 result = tm->tm_year - 1;
04056 break;
04057
04058 case DTK_DECADE:
04059
04060
04061
04062
04063
04064
04065 if (tm->tm_year >= 0)
04066 result = tm->tm_year / 10;
04067 else
04068 result = -((8 - (tm->tm_year - 1)) / 10);
04069 break;
04070
04071 case DTK_CENTURY:
04072
04073
04074
04075
04076
04077
04078
04079 if (tm->tm_year > 0)
04080 result = (tm->tm_year + 99) / 100;
04081 else
04082
04083 result = -((99 - (tm->tm_year - 1)) / 100);
04084 break;
04085
04086 case DTK_MILLENNIUM:
04087
04088 if (tm->tm_year > 0)
04089 result = (tm->tm_year + 999) / 1000;
04090 else
04091 result = -((999 - (tm->tm_year - 1)) / 1000);
04092 break;
04093
04094 case DTK_JULIAN:
04095 result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
04096 #ifdef HAVE_INT64_TIMESTAMP
04097 result += ((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
04098 tm->tm_sec + (fsec / 1000000.0)) / (double) SECS_PER_DAY;
04099 #else
04100 result += ((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
04101 tm->tm_sec + fsec) / (double) SECS_PER_DAY;
04102 #endif
04103 break;
04104
04105 case DTK_ISOYEAR:
04106 result = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday);
04107 break;
04108
04109 case DTK_TZ:
04110 case DTK_TZ_MINUTE:
04111 case DTK_TZ_HOUR:
04112 default:
04113 ereport(ERROR,
04114 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
04115 errmsg("timestamp units \"%s\" not supported",
04116 lowunits)));
04117 result = 0;
04118 }
04119 }
04120 else if (type == RESERV)
04121 {
04122 switch (val)
04123 {
04124 case DTK_EPOCH:
04125 #ifdef HAVE_INT64_TIMESTAMP
04126 result = (timestamp - SetEpochTimestamp()) / 1000000.0;
04127 #else
04128 result = timestamp - SetEpochTimestamp();
04129 #endif
04130 break;
04131
04132 case DTK_DOW:
04133 case DTK_ISODOW:
04134 if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
04135 ereport(ERROR,
04136 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
04137 errmsg("timestamp out of range")));
04138 result = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
04139 if (val == DTK_ISODOW && result == 0)
04140 result = 7;
04141 break;
04142
04143 case DTK_DOY:
04144 if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
04145 ereport(ERROR,
04146 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
04147 errmsg("timestamp out of range")));
04148 result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
04149 - date2j(tm->tm_year, 1, 1) + 1);
04150 break;
04151
04152 default:
04153 ereport(ERROR,
04154 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
04155 errmsg("timestamp units \"%s\" not supported",
04156 lowunits)));
04157 result = 0;
04158 }
04159
04160 }
04161 else
04162 {
04163 ereport(ERROR,
04164 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
04165 errmsg("timestamp units \"%s\" not recognized", lowunits)));
04166 result = 0;
04167 }
04168
04169 PG_RETURN_FLOAT8(result);
04170 }
04171
04172
04173
04174
04175 Datum
04176 timestamptz_part(PG_FUNCTION_ARGS)
04177 {
04178 text *units = PG_GETARG_TEXT_PP(0);
04179 TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
04180 float8 result;
04181 int tz;
04182 int type,
04183 val;
04184 char *lowunits;
04185 double dummy;
04186 fsec_t fsec;
04187 struct pg_tm tt,
04188 *tm = &tt;
04189
04190 if (TIMESTAMP_NOT_FINITE(timestamp))
04191 {
04192 result = 0;
04193 PG_RETURN_FLOAT8(result);
04194 }
04195
04196 lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
04197 VARSIZE_ANY_EXHDR(units),
04198 false);
04199
04200 type = DecodeUnits(0, lowunits, &val);
04201 if (type == UNKNOWN_FIELD)
04202 type = DecodeSpecial(0, lowunits, &val);
04203
04204 if (type == UNITS)
04205 {
04206 if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
04207 ereport(ERROR,
04208 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
04209 errmsg("timestamp out of range")));
04210
04211 switch (val)
04212 {
04213 case DTK_TZ:
04214 result = -tz;
04215 break;
04216
04217 case DTK_TZ_MINUTE:
04218 result = -tz;
04219 result /= MINS_PER_HOUR;
04220 FMODULO(result, dummy, (double) MINS_PER_HOUR);
04221 break;
04222
04223 case DTK_TZ_HOUR:
04224 dummy = -tz;
04225 FMODULO(dummy, result, (double) SECS_PER_HOUR);
04226 break;
04227
04228 case DTK_MICROSEC:
04229 #ifdef HAVE_INT64_TIMESTAMP
04230 result = tm->tm_sec * 1000000.0 + fsec;
04231 #else
04232 result = (tm->tm_sec + fsec) * 1000000;
04233 #endif
04234 break;
04235
04236 case DTK_MILLISEC:
04237 #ifdef HAVE_INT64_TIMESTAMP
04238 result = tm->tm_sec * 1000.0 + fsec / 1000.0;
04239 #else
04240 result = (tm->tm_sec + fsec) * 1000;
04241 #endif
04242 break;
04243
04244 case DTK_SECOND:
04245 #ifdef HAVE_INT64_TIMESTAMP
04246 result = tm->tm_sec + fsec / 1000000.0;
04247 #else
04248 result = tm->tm_sec + fsec;
04249 #endif
04250 break;
04251
04252 case DTK_MINUTE:
04253 result = tm->tm_min;
04254 break;
04255
04256 case DTK_HOUR:
04257 result = tm->tm_hour;
04258 break;
04259
04260 case DTK_DAY:
04261 result = tm->tm_mday;
04262 break;
04263
04264 case DTK_MONTH:
04265 result = tm->tm_mon;
04266 break;
04267
04268 case DTK_QUARTER:
04269 result = (tm->tm_mon - 1) / 3 + 1;
04270 break;
04271
04272 case DTK_WEEK:
04273 result = (float8) date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
04274 break;
04275
04276 case DTK_YEAR:
04277 if (tm->tm_year > 0)
04278 result = tm->tm_year;
04279 else
04280
04281 result = tm->tm_year - 1;
04282 break;
04283
04284 case DTK_DECADE:
04285
04286 if (tm->tm_year > 0)
04287 result = tm->tm_year / 10;
04288 else
04289 result = -((8 - (tm->tm_year - 1)) / 10);
04290 break;
04291
04292 case DTK_CENTURY:
04293
04294 if (tm->tm_year > 0)
04295 result = (tm->tm_year + 99) / 100;
04296 else
04297 result = -((99 - (tm->tm_year - 1)) / 100);
04298 break;
04299
04300 case DTK_MILLENNIUM:
04301
04302 if (tm->tm_year > 0)
04303 result = (tm->tm_year + 999) / 1000;
04304 else
04305 result = -((999 - (tm->tm_year - 1)) / 1000);
04306 break;
04307
04308 case DTK_JULIAN:
04309 result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
04310 #ifdef HAVE_INT64_TIMESTAMP
04311 result += ((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
04312 tm->tm_sec + (fsec / 1000000.0)) / (double) SECS_PER_DAY;
04313 #else
04314 result += ((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
04315 tm->tm_sec + fsec) / (double) SECS_PER_DAY;
04316 #endif
04317 break;
04318
04319 case DTK_ISOYEAR:
04320 result = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday);
04321 break;
04322
04323 default:
04324 ereport(ERROR,
04325 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
04326 errmsg("timestamp with time zone units \"%s\" not supported",
04327 lowunits)));
04328 result = 0;
04329 }
04330
04331 }
04332 else if (type == RESERV)
04333 {
04334 switch (val)
04335 {
04336 case DTK_EPOCH:
04337 #ifdef HAVE_INT64_TIMESTAMP
04338 result = (timestamp - SetEpochTimestamp()) / 1000000.0;
04339 #else
04340 result = timestamp - SetEpochTimestamp();
04341 #endif
04342 break;
04343
04344 case DTK_DOW:
04345 case DTK_ISODOW:
04346 if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
04347 ereport(ERROR,
04348 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
04349 errmsg("timestamp out of range")));
04350 result = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
04351 if (val == DTK_ISODOW && result == 0)
04352 result = 7;
04353 break;
04354
04355 case DTK_DOY:
04356 if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
04357 ereport(ERROR,
04358 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
04359 errmsg("timestamp out of range")));
04360 result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
04361 - date2j(tm->tm_year, 1, 1) + 1);
04362 break;
04363
04364 default:
04365 ereport(ERROR,
04366 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
04367 errmsg("timestamp with time zone units \"%s\" not supported",
04368 lowunits)));
04369 result = 0;
04370 }
04371 }
04372 else
04373 {
04374 ereport(ERROR,
04375 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
04376 errmsg("timestamp with time zone units \"%s\" not recognized",
04377 lowunits)));
04378
04379 result = 0;
04380 }
04381
04382 PG_RETURN_FLOAT8(result);
04383 }
04384
04385
04386
04387
04388
04389 Datum
04390 interval_part(PG_FUNCTION_ARGS)
04391 {
04392 text *units = PG_GETARG_TEXT_PP(0);
04393 Interval *interval = PG_GETARG_INTERVAL_P(1);
04394 float8 result;
04395 int type,
04396 val;
04397 char *lowunits;
04398 fsec_t fsec;
04399 struct pg_tm tt,
04400 *tm = &tt;
04401
04402 lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
04403 VARSIZE_ANY_EXHDR(units),
04404 false);
04405
04406 type = DecodeUnits(0, lowunits, &val);
04407 if (type == UNKNOWN_FIELD)
04408 type = DecodeSpecial(0, lowunits, &val);
04409
04410 if (type == UNITS)
04411 {
04412 if (interval2tm(*interval, tm, &fsec) == 0)
04413 {
04414 switch (val)
04415 {
04416 case DTK_MICROSEC:
04417 #ifdef HAVE_INT64_TIMESTAMP
04418 result = tm->tm_sec * 1000000.0 + fsec;
04419 #else
04420 result = (tm->tm_sec + fsec) * 1000000;
04421 #endif
04422 break;
04423
04424 case DTK_MILLISEC:
04425 #ifdef HAVE_INT64_TIMESTAMP
04426 result = tm->tm_sec * 1000.0 + fsec / 1000.0;
04427 #else
04428 result = (tm->tm_sec + fsec) * 1000;
04429 #endif
04430 break;
04431
04432 case DTK_SECOND:
04433 #ifdef HAVE_INT64_TIMESTAMP
04434 result = tm->tm_sec + fsec / 1000000.0;
04435 #else
04436 result = tm->tm_sec + fsec;
04437 #endif
04438 break;
04439
04440 case DTK_MINUTE:
04441 result = tm->tm_min;
04442 break;
04443
04444 case DTK_HOUR:
04445 result = tm->tm_hour;
04446 break;
04447
04448 case DTK_DAY:
04449 result = tm->tm_mday;
04450 break;
04451
04452 case DTK_MONTH:
04453 result = tm->tm_mon;
04454 break;
04455
04456 case DTK_QUARTER:
04457 result = (tm->tm_mon / 3) + 1;
04458 break;
04459
04460 case DTK_YEAR:
04461 result = tm->tm_year;
04462 break;
04463
04464 case DTK_DECADE:
04465
04466 result = tm->tm_year / 10;
04467 break;
04468
04469 case DTK_CENTURY:
04470
04471 result = tm->tm_year / 100;
04472 break;
04473
04474 case DTK_MILLENNIUM:
04475
04476 result = tm->tm_year / 1000;
04477 break;
04478
04479 default:
04480 ereport(ERROR,
04481 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
04482 errmsg("interval units \"%s\" not supported",
04483 lowunits)));
04484 result = 0;
04485 }
04486
04487 }
04488 else
04489 {
04490 elog(ERROR, "could not convert interval to tm");
04491 result = 0;
04492 }
04493 }
04494 else if (type == RESERV && val == DTK_EPOCH)
04495 {
04496 #ifdef HAVE_INT64_TIMESTAMP
04497 result = interval->time / 1000000.0;
04498 #else
04499 result = interval->time;
04500 #endif
04501 result += ((double) DAYS_PER_YEAR * SECS_PER_DAY) * (interval->month / MONTHS_PER_YEAR);
04502 result += ((double) DAYS_PER_MONTH * SECS_PER_DAY) * (interval->month % MONTHS_PER_YEAR);
04503 result += ((double) SECS_PER_DAY) * interval->day;
04504 }
04505 else
04506 {
04507 ereport(ERROR,
04508 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
04509 errmsg("interval units \"%s\" not recognized",
04510 lowunits)));
04511 result = 0;
04512 }
04513
04514 PG_RETURN_FLOAT8(result);
04515 }
04516
04517
04518
04519
04520
04521
04522
04523
04524
04525
04526 Datum
04527 timestamp_zone(PG_FUNCTION_ARGS)
04528 {
04529 text *zone = PG_GETARG_TEXT_PP(0);
04530 Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
04531 TimestampTz result;
04532 int tz;
04533 char tzname[TZ_STRLEN_MAX + 1];
04534 char *lowzone;
04535 int type,
04536 val;
04537 pg_tz *tzp;
04538
04539 if (TIMESTAMP_NOT_FINITE(timestamp))
04540 PG_RETURN_TIMESTAMPTZ(timestamp);
04541
04542
04543
04544
04545
04546
04547
04548
04549
04550 text_to_cstring_buffer(zone, tzname, sizeof(tzname));
04551 lowzone = downcase_truncate_identifier(tzname,
04552 strlen(tzname),
04553 false);
04554
04555 type = DecodeSpecial(0, lowzone, &val);
04556
04557 if (type == TZ || type == DTZ)
04558 {
04559 tz = -(val * MINS_PER_HOUR);
04560 result = dt2local(timestamp, tz);
04561 }
04562 else
04563 {
04564 tzp = pg_tzset(tzname);
04565 if (tzp)
04566 {
04567
04568 struct pg_tm tm;
04569 fsec_t fsec;
04570
04571 if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
04572 ereport(ERROR,
04573 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
04574 errmsg("timestamp out of range")));
04575 tz = DetermineTimeZoneOffset(&tm, tzp);
04576 if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
04577 ereport(ERROR,
04578 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
04579 errmsg("could not convert to time zone \"%s\"",
04580 tzname)));
04581 }
04582 else
04583 {
04584 ereport(ERROR,
04585 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
04586 errmsg("time zone \"%s\" not recognized", tzname)));
04587 result = 0;
04588 }
04589 }
04590
04591 PG_RETURN_TIMESTAMPTZ(result);
04592 }
04593
04594
04595
04596
04597 Datum
04598 timestamp_izone(PG_FUNCTION_ARGS)
04599 {
04600 Interval *zone = PG_GETARG_INTERVAL_P(0);
04601 Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
04602 TimestampTz result;
04603 int tz;
04604
04605 if (TIMESTAMP_NOT_FINITE(timestamp))
04606 PG_RETURN_TIMESTAMPTZ(timestamp);
04607
04608 if (zone->month != 0 || zone->day != 0)
04609 ereport(ERROR,
04610 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
04611 errmsg("interval time zone \"%s\" must not include months or days",
04612 DatumGetCString(DirectFunctionCall1(interval_out,
04613 PointerGetDatum(zone))))));
04614
04615 #ifdef HAVE_INT64_TIMESTAMP
04616 tz = zone->time / USECS_PER_SEC;
04617 #else
04618 tz = zone->time;
04619 #endif
04620
04621 result = dt2local(timestamp, tz);
04622
04623 PG_RETURN_TIMESTAMPTZ(result);
04624 }
04625
04626
04627
04628
04629 Datum
04630 timestamp_timestamptz(PG_FUNCTION_ARGS)
04631 {
04632 Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
04633
04634 PG_RETURN_TIMESTAMPTZ(timestamp2timestamptz(timestamp));
04635 }
04636
04637 static TimestampTz
04638 timestamp2timestamptz(Timestamp timestamp)
04639 {
04640 TimestampTz result;
04641 struct pg_tm tt,
04642 *tm = &tt;
04643 fsec_t fsec;
04644 int tz;
04645
04646 if (TIMESTAMP_NOT_FINITE(timestamp))
04647 result = timestamp;
04648 else
04649 {
04650 if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
04651 ereport(ERROR,
04652 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
04653 errmsg("timestamp out of range")));
04654
04655 tz = DetermineTimeZoneOffset(tm, session_timezone);
04656
04657 if (tm2timestamp(tm, fsec, &tz, &result) != 0)
04658 ereport(ERROR,
04659 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
04660 errmsg("timestamp out of range")));
04661 }
04662
04663 return result;
04664 }
04665
04666
04667
04668
04669 Datum
04670 timestamptz_timestamp(PG_FUNCTION_ARGS)
04671 {
04672 TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
04673 Timestamp result;
04674 struct pg_tm tt,
04675 *tm = &tt;
04676 fsec_t fsec;
04677 int tz;
04678
04679 if (TIMESTAMP_NOT_FINITE(timestamp))
04680 result = timestamp;
04681 else
04682 {
04683 if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
04684 ereport(ERROR,
04685 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
04686 errmsg("timestamp out of range")));
04687 if (tm2timestamp(tm, fsec, NULL, &result) != 0)
04688 ereport(ERROR,
04689 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
04690 errmsg("timestamp out of range")));
04691 }
04692 PG_RETURN_TIMESTAMP(result);
04693 }
04694
04695
04696
04697
04698
04699 Datum
04700 timestamptz_zone(PG_FUNCTION_ARGS)
04701 {
04702 text *zone = PG_GETARG_TEXT_PP(0);
04703 TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
04704 Timestamp result;
04705 int tz;
04706 char tzname[TZ_STRLEN_MAX + 1];
04707 char *lowzone;
04708 int type,
04709 val;
04710 pg_tz *tzp;
04711
04712 if (TIMESTAMP_NOT_FINITE(timestamp))
04713 PG_RETURN_TIMESTAMP(timestamp);
04714
04715
04716
04717
04718
04719
04720
04721
04722
04723 text_to_cstring_buffer(zone, tzname, sizeof(tzname));
04724 lowzone = downcase_truncate_identifier(tzname,
04725 strlen(tzname),
04726 false);
04727
04728 type = DecodeSpecial(0, lowzone, &val);
04729
04730 if (type == TZ || type == DTZ)
04731 {
04732 tz = val * MINS_PER_HOUR;
04733 result = dt2local(timestamp, tz);
04734 }
04735 else
04736 {
04737 tzp = pg_tzset(tzname);
04738 if (tzp)
04739 {
04740
04741 struct pg_tm tm;
04742 fsec_t fsec;
04743
04744 if (timestamp2tm(timestamp, &tz, &tm, &fsec, NULL, tzp) != 0)
04745 ereport(ERROR,
04746 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
04747 errmsg("timestamp out of range")));
04748 if (tm2timestamp(&tm, fsec, NULL, &result) != 0)
04749 ereport(ERROR,
04750 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
04751 errmsg("could not convert to time zone \"%s\"",
04752 tzname)));
04753 }
04754 else
04755 {
04756 ereport(ERROR,
04757 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
04758 errmsg("time zone \"%s\" not recognized", tzname)));
04759 result = 0;
04760 }
04761 }
04762
04763 PG_RETURN_TIMESTAMP(result);
04764 }
04765
04766
04767
04768
04769
04770 Datum
04771 timestamptz_izone(PG_FUNCTION_ARGS)
04772 {
04773 Interval *zone = PG_GETARG_INTERVAL_P(0);
04774 TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
04775 Timestamp result;
04776 int tz;
04777
04778 if (TIMESTAMP_NOT_FINITE(timestamp))
04779 PG_RETURN_TIMESTAMP(timestamp);
04780
04781 if (zone->month != 0 || zone->day != 0)
04782 ereport(ERROR,
04783 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
04784 errmsg("interval time zone \"%s\" must not include months or days",
04785 DatumGetCString(DirectFunctionCall1(interval_out,
04786 PointerGetDatum(zone))))));
04787
04788 #ifdef HAVE_INT64_TIMESTAMP
04789 tz = -(zone->time / USECS_PER_SEC);
04790 #else
04791 tz = -zone->time;
04792 #endif
04793
04794 result = dt2local(timestamp, tz);
04795
04796 PG_RETURN_TIMESTAMP(result);
04797 }
04798
04799
04800
04801
04802 Datum
04803 generate_series_timestamp(PG_FUNCTION_ARGS)
04804 {
04805 FuncCallContext *funcctx;
04806 generate_series_timestamp_fctx *fctx;
04807 Timestamp result;
04808
04809
04810 if (SRF_IS_FIRSTCALL())
04811 {
04812 Timestamp start = PG_GETARG_TIMESTAMP(0);
04813 Timestamp finish = PG_GETARG_TIMESTAMP(1);
04814 Interval *step = PG_GETARG_INTERVAL_P(2);
04815 MemoryContext oldcontext;
04816 Interval interval_zero;
04817
04818
04819 funcctx = SRF_FIRSTCALL_INIT();
04820
04821
04822
04823
04824 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
04825
04826
04827 fctx = (generate_series_timestamp_fctx *)
04828 palloc(sizeof(generate_series_timestamp_fctx));
04829
04830
04831
04832
04833
04834 fctx->current = start;
04835 fctx->finish = finish;
04836 fctx->step = *step;
04837
04838
04839 MemSet(&interval_zero, 0, sizeof(Interval));
04840 fctx->step_sign = interval_cmp_internal(&fctx->step, &interval_zero);
04841
04842 if (fctx->step_sign == 0)
04843 ereport(ERROR,
04844 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
04845 errmsg("step size cannot equal zero")));
04846
04847 funcctx->user_fctx = fctx;
04848 MemoryContextSwitchTo(oldcontext);
04849 }
04850
04851
04852 funcctx = SRF_PERCALL_SETUP();
04853
04854
04855
04856
04857 fctx = funcctx->user_fctx;
04858 result = fctx->current;
04859
04860 if (fctx->step_sign > 0 ?
04861 timestamp_cmp_internal(result, fctx->finish) <= 0 :
04862 timestamp_cmp_internal(result, fctx->finish) >= 0)
04863 {
04864
04865 fctx->current = DatumGetTimestamp(
04866 DirectFunctionCall2(timestamp_pl_interval,
04867 TimestampGetDatum(fctx->current),
04868 PointerGetDatum(&fctx->step)));
04869
04870
04871 SRF_RETURN_NEXT(funcctx, TimestampGetDatum(result));
04872 }
04873 else
04874 {
04875
04876 SRF_RETURN_DONE(funcctx);
04877 }
04878 }
04879
04880
04881
04882
04883 Datum
04884 generate_series_timestamptz(PG_FUNCTION_ARGS)
04885 {
04886 FuncCallContext *funcctx;
04887 generate_series_timestamptz_fctx *fctx;
04888 TimestampTz result;
04889
04890
04891 if (SRF_IS_FIRSTCALL())
04892 {
04893 TimestampTz start = PG_GETARG_TIMESTAMPTZ(0);
04894 TimestampTz finish = PG_GETARG_TIMESTAMPTZ(1);
04895 Interval *step = PG_GETARG_INTERVAL_P(2);
04896 MemoryContext oldcontext;
04897 Interval interval_zero;
04898
04899
04900 funcctx = SRF_FIRSTCALL_INIT();
04901
04902
04903
04904
04905 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
04906
04907
04908 fctx = (generate_series_timestamptz_fctx *)
04909 palloc(sizeof(generate_series_timestamptz_fctx));
04910
04911
04912
04913
04914
04915 fctx->current = start;
04916 fctx->finish = finish;
04917 fctx->step = *step;
04918
04919
04920 MemSet(&interval_zero, 0, sizeof(Interval));
04921 fctx->step_sign = interval_cmp_internal(&fctx->step, &interval_zero);
04922
04923 if (fctx->step_sign == 0)
04924 ereport(ERROR,
04925 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
04926 errmsg("step size cannot equal zero")));
04927
04928 funcctx->user_fctx = fctx;
04929 MemoryContextSwitchTo(oldcontext);
04930 }
04931
04932
04933 funcctx = SRF_PERCALL_SETUP();
04934
04935
04936
04937
04938 fctx = funcctx->user_fctx;
04939 result = fctx->current;
04940
04941 if (fctx->step_sign > 0 ?
04942 timestamp_cmp_internal(result, fctx->finish) <= 0 :
04943 timestamp_cmp_internal(result, fctx->finish) >= 0)
04944 {
04945
04946 fctx->current = DatumGetTimestampTz(
04947 DirectFunctionCall2(timestamptz_pl_interval,
04948 TimestampTzGetDatum(fctx->current),
04949 PointerGetDatum(&fctx->step)));
04950
04951
04952 SRF_RETURN_NEXT(funcctx, TimestampTzGetDatum(result));
04953 }
04954 else
04955 {
04956
04957 SRF_RETURN_DONE(funcctx);
04958 }
04959 }