/Users/deen/code/yugabyte-db/src/postgres/src/backend/utils/adt/nabstime.c
Line | Count | Source (jump to first uncovered line) |
1 | | /*------------------------------------------------------------------------- |
2 | | * |
3 | | * nabstime.c |
4 | | * Utilities for the built-in type "AbsoluteTime". |
5 | | * Functions for the built-in type "RelativeTime". |
6 | | * Functions for the built-in type "TimeInterval". |
7 | | * |
8 | | * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group |
9 | | * Portions Copyright (c) 1994, Regents of the University of California |
10 | | * |
11 | | * |
12 | | * IDENTIFICATION |
13 | | * src/backend/utils/adt/nabstime.c |
14 | | * |
15 | | *------------------------------------------------------------------------- |
16 | | */ |
17 | | #include "postgres.h" |
18 | | |
19 | | #include <ctype.h> |
20 | | #include <float.h> |
21 | | #include <limits.h> |
22 | | #include <math.h> |
23 | | #include <time.h> |
24 | | #include <sys/time.h> |
25 | | |
26 | | #include "libpq/pqformat.h" |
27 | | #include "miscadmin.h" |
28 | | #include "utils/builtins.h" |
29 | | #include "utils/datetime.h" |
30 | | #include "utils/nabstime.h" |
31 | | |
32 | 6 | #define MIN_DAYNUM (-24856) /* December 13, 1901 */ |
33 | 4 | #define MAX_DAYNUM 24854 /* January 18, 2038 */ |
34 | | |
35 | | /* |
36 | | * Unix epoch is Jan 1 00:00:00 1970. |
37 | | * Postgres knows about times sixty-eight years on either side of that |
38 | | * for these 4-byte types. |
39 | | * |
40 | | * "tinterval" is two 4-byte fields. |
41 | | * Definitions for parsing tinterval. |
42 | | */ |
43 | | |
44 | 5 | #define IsSpace(C) ((C) == ' ') |
45 | | |
46 | 1 | #define T_INTERVAL_INVAL 0 /* data represents no valid tinterval */ |
47 | 1 | #define T_INTERVAL_VALID 1 /* data represents a valid tinterval */ |
48 | | /* |
49 | | * ['Mon May 10 23:59:12 1943 PST' 'Sun Jan 14 03:14:21 1973 PST'] |
50 | | * 0 1 2 3 4 5 6 |
51 | | * 1234567890123456789012345678901234567890123456789012345678901234 |
52 | | * |
53 | | * we allocate some extra -- timezones are usually 3 characters but |
54 | | * this is not in the POSIX standard... |
55 | | */ |
56 | 1 | #define T_INTERVAL_LEN 80 |
57 | 2 | #define INVALID_INTERVAL_STR "Undefined Range" |
58 | | #define INVALID_INTERVAL_STR_LEN (sizeof(INVALID_INTERVAL_STR)-1) |
59 | | |
60 | | #define ABSTIMEMIN(t1, t2) \ |
61 | 1 | (DatumGetBool(DirectFunctionCall2(abstimele, \ |
62 | 1 | AbsoluteTimeGetDatum(t1), \ |
63 | 1 | AbsoluteTimeGetDatum(t2))) ? (t1) : (t2)0 ) |
64 | | #define ABSTIMEMAX(t1, t2) \ |
65 | 1 | (DatumGetBool(DirectFunctionCall2(abstimelt, \ |
66 | 1 | AbsoluteTimeGetDatum(t1), \ |
67 | 1 | AbsoluteTimeGetDatum(t2))) ? (t2) : (t1)0 ) |
68 | | |
69 | | |
70 | | /* |
71 | | * Function prototypes -- internal to this file only |
72 | | */ |
73 | | |
74 | | static AbsoluteTime tm2abstime(struct pg_tm *tm, int tz); |
75 | | static void reltime2tm(RelativeTime time, struct pg_tm *tm); |
76 | | static void parsetinterval(char *i_string, |
77 | | AbsoluteTime *i_start, |
78 | | AbsoluteTime *i_end); |
79 | | |
80 | | |
81 | | /* |
82 | | * GetCurrentAbsoluteTime() |
83 | | * |
84 | | * Get the current system time (relative to Unix epoch). |
85 | | * |
86 | | * NB: this will overflow in 2038; it should be gone long before that. |
87 | | */ |
88 | | AbsoluteTime |
89 | | GetCurrentAbsoluteTime(void) |
90 | 0 | { |
91 | 0 | time_t now; |
92 | |
|
93 | 0 | now = time(NULL); |
94 | 0 | return (AbsoluteTime) now; |
95 | 0 | } |
96 | | |
97 | | |
98 | | void |
99 | | abstime2tm(AbsoluteTime _time, int *tzp, struct pg_tm *tm, char **tzn) |
100 | 2 | { |
101 | 2 | pg_time_t time = (pg_time_t) _time; |
102 | 2 | struct pg_tm *tx; |
103 | | |
104 | 2 | if (tzp != NULL) |
105 | 2 | tx = pg_localtime(&time, session_timezone); |
106 | 0 | else |
107 | 0 | tx = pg_gmtime(&time); |
108 | | |
109 | 2 | if (tx == NULL) |
110 | 0 | elog(ERROR, "could not convert abstime to timestamp: %m"); |
111 | | |
112 | 2 | tm->tm_year = tx->tm_year + 1900; |
113 | 2 | tm->tm_mon = tx->tm_mon + 1; |
114 | 2 | tm->tm_mday = tx->tm_mday; |
115 | 2 | tm->tm_hour = tx->tm_hour; |
116 | 2 | tm->tm_min = tx->tm_min; |
117 | 2 | tm->tm_sec = tx->tm_sec; |
118 | 2 | tm->tm_isdst = tx->tm_isdst; |
119 | | |
120 | 2 | tm->tm_gmtoff = tx->tm_gmtoff; |
121 | 2 | tm->tm_zone = tx->tm_zone; |
122 | | |
123 | 2 | if (tzp != NULL) |
124 | 2 | { |
125 | 2 | *tzp = -tm->tm_gmtoff; /* tm_gmtoff is Sun/DEC-ism */ |
126 | | |
127 | | /* |
128 | | * XXX FreeBSD man pages indicate that this should work - tgl 97/04/23 |
129 | | */ |
130 | 2 | if (tzn != NULL) |
131 | 2 | { |
132 | | /* |
133 | | * Copy no more than MAXTZLEN bytes of timezone to tzn, in case it |
134 | | * contains an error message, which doesn't fit in the buffer |
135 | | */ |
136 | 2 | StrNCpy(*tzn, tm->tm_zone, MAXTZLEN + 1); |
137 | 2 | if (strlen(tm->tm_zone) > MAXTZLEN) |
138 | 2 | ereport(WARNING, |
139 | 2 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
140 | 2 | errmsg("invalid time zone name: \"%s\"", |
141 | 2 | tm->tm_zone))); |
142 | 2 | } |
143 | 2 | } |
144 | 0 | else |
145 | 0 | tm->tm_isdst = -1; |
146 | 2 | } |
147 | | |
148 | | |
149 | | /* tm2abstime() |
150 | | * Convert a tm structure to abstime. |
151 | | * Note that tm has full year (not 1900-based) and 1-based month. |
152 | | */ |
153 | | static AbsoluteTime |
154 | | tm2abstime(struct pg_tm *tm, int tz) |
155 | 2 | { |
156 | 2 | int day; |
157 | 2 | AbsoluteTime sec; |
158 | | |
159 | | /* validate, before going out of range on some members */ |
160 | 2 | if (tm->tm_year < 1901 || tm->tm_year > 2038 || |
161 | 2 | tm->tm_mon < 1 || tm->tm_mon > MONTHS_PER_YEAR || |
162 | 2 | tm->tm_mday < 1 || tm->tm_mday > 31 || |
163 | 2 | tm->tm_hour < 0 || |
164 | 2 | tm->tm_hour > HOURS_PER_DAY || /* test for > 24:00:00 */ |
165 | 2 | (tm->tm_hour == HOURS_PER_DAY && (0 tm->tm_min > 00 || tm->tm_sec > 00 )) || |
166 | 2 | tm->tm_min < 0 || tm->tm_min > MINS_PER_HOUR - 1 || |
167 | 2 | tm->tm_sec < 0 || tm->tm_sec > SECS_PER_MINUTE) |
168 | 0 | return INVALID_ABSTIME; |
169 | | |
170 | 2 | day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - UNIX_EPOCH_JDATE; |
171 | | |
172 | | /* check for time out of range */ |
173 | 2 | if (day < MIN_DAYNUM || day > MAX_DAYNUM) |
174 | 0 | return INVALID_ABSTIME; |
175 | | |
176 | | /* convert to seconds */ |
177 | 2 | sec = tm->tm_sec + tz + (tm->tm_min + (day * HOURS_PER_DAY + tm->tm_hour) * MINS_PER_HOUR) * SECS_PER_MINUTE; |
178 | | |
179 | | /* |
180 | | * check for overflow. We need a little slop here because the H/M/S plus |
181 | | * TZ offset could add up to more than 1 day. |
182 | | */ |
183 | 2 | if ((day >= MAX_DAYNUM - 10 && sec < 00 ) || |
184 | 2 | (day <= MIN_DAYNUM + 10 && sec > 00 )) |
185 | 0 | return INVALID_ABSTIME; |
186 | | |
187 | | /* check for reserved values (e.g. "current" on edge of usual range */ |
188 | 2 | if (!AbsoluteTimeIsReal(sec)) |
189 | 0 | return INVALID_ABSTIME; |
190 | | |
191 | 2 | return sec; |
192 | 2 | } |
193 | | |
194 | | |
195 | | /* abstimein() |
196 | | * Decode date/time string and return abstime. |
197 | | */ |
198 | | Datum |
199 | | abstimein(PG_FUNCTION_ARGS) |
200 | 2 | { |
201 | 2 | char *str = PG_GETARG_CSTRING(0); |
202 | 2 | AbsoluteTime result; |
203 | 2 | fsec_t fsec; |
204 | 2 | int tz = 0; |
205 | 2 | struct pg_tm date, |
206 | 2 | *tm = &date; |
207 | 2 | int dterr; |
208 | 2 | char *field[MAXDATEFIELDS]; |
209 | 2 | char workbuf[MAXDATELEN + 1]; |
210 | 2 | int dtype; |
211 | 2 | int nf, |
212 | 2 | ftype[MAXDATEFIELDS]; |
213 | | |
214 | 2 | dterr = ParseDateTime(str, workbuf, sizeof(workbuf), |
215 | 2 | field, ftype, MAXDATEFIELDS, &nf); |
216 | 2 | if (dterr == 0) |
217 | 2 | dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz); |
218 | 2 | if (dterr != 0) |
219 | 0 | DateTimeParseError(dterr, str, "abstime"); |
220 | | |
221 | 2 | switch (dtype) |
222 | 2 | { |
223 | 2 | case DTK_DATE: |
224 | 2 | result = tm2abstime(tm, tz); |
225 | 2 | break; |
226 | | |
227 | 0 | case DTK_EPOCH: |
228 | | |
229 | | /* |
230 | | * Don't bother retaining this as a reserved value, but instead |
231 | | * just set to the actual epoch time (1970-01-01) |
232 | | */ |
233 | 0 | result = 0; |
234 | 0 | break; |
235 | | |
236 | 0 | case DTK_LATE: |
237 | 0 | result = NOEND_ABSTIME; |
238 | 0 | break; |
239 | | |
240 | 0 | case DTK_EARLY: |
241 | 0 | result = NOSTART_ABSTIME; |
242 | 0 | break; |
243 | | |
244 | 0 | case DTK_INVALID: |
245 | 0 | result = INVALID_ABSTIME; |
246 | 0 | break; |
247 | | |
248 | 0 | default: |
249 | 0 | elog(ERROR, "unexpected dtype %d while parsing abstime \"%s\"", |
250 | 0 | dtype, str); |
251 | 0 | result = INVALID_ABSTIME; |
252 | 0 | break; |
253 | 2 | }; |
254 | | |
255 | 2 | PG_RETURN_ABSOLUTETIME(result); |
256 | 2 | } |
257 | | |
258 | | |
259 | | /* abstimeout() |
260 | | * Given an AbsoluteTime return the English text version of the date |
261 | | */ |
262 | | Datum |
263 | | abstimeout(PG_FUNCTION_ARGS) |
264 | 2 | { |
265 | 2 | AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0); |
266 | 2 | char *result; |
267 | 2 | int tz; |
268 | 2 | double fsec = 0; |
269 | 2 | struct pg_tm tt, |
270 | 2 | *tm = &tt; |
271 | 2 | char buf[MAXDATELEN + 1]; |
272 | 2 | char zone[MAXDATELEN + 1], |
273 | 2 | *tzn = zone; |
274 | | |
275 | 2 | switch (time) |
276 | 2 | { |
277 | | /* |
278 | | * Note that timestamp no longer supports 'invalid'. Retain |
279 | | * 'invalid' for abstime for now, but dump it someday. |
280 | | */ |
281 | 0 | case INVALID_ABSTIME: |
282 | 0 | strcpy(buf, INVALID); |
283 | 0 | break; |
284 | 0 | case NOEND_ABSTIME: |
285 | 0 | strcpy(buf, LATE); |
286 | 0 | break; |
287 | 0 | case NOSTART_ABSTIME: |
288 | 0 | strcpy(buf, EARLY); |
289 | 0 | break; |
290 | 2 | default: |
291 | 2 | abstime2tm(time, &tz, tm, &tzn); |
292 | 2 | EncodeDateTime(tm, fsec, true, tz, tzn, DateStyle, buf); |
293 | 2 | break; |
294 | 2 | } |
295 | | |
296 | 2 | result = pstrdup(buf); |
297 | 2 | PG_RETURN_CSTRING(result); |
298 | 2 | } |
299 | | |
300 | | /* |
301 | | * abstimerecv - converts external binary format to abstime |
302 | | */ |
303 | | Datum |
304 | | abstimerecv(PG_FUNCTION_ARGS) |
305 | 0 | { |
306 | 0 | StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); |
307 | |
|
308 | 0 | PG_RETURN_ABSOLUTETIME((AbsoluteTime) pq_getmsgint(buf, sizeof(AbsoluteTime))); |
309 | 0 | } |
310 | | |
311 | | /* |
312 | | * abstimesend - converts abstime to binary format |
313 | | */ |
314 | | Datum |
315 | | abstimesend(PG_FUNCTION_ARGS) |
316 | 0 | { |
317 | 0 | AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0); |
318 | 0 | StringInfoData buf; |
319 | |
|
320 | 0 | pq_begintypsend(&buf); |
321 | 0 | pq_sendint32(&buf, time); |
322 | 0 | PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); |
323 | 0 | } |
324 | | |
325 | | |
326 | | /* abstime_finite() |
327 | | */ |
328 | | Datum |
329 | | abstime_finite(PG_FUNCTION_ARGS) |
330 | 0 | { |
331 | 0 | AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0); |
332 | |
|
333 | 0 | PG_RETURN_BOOL(abstime != INVALID_ABSTIME && |
334 | 0 | abstime != NOSTART_ABSTIME && |
335 | 0 | abstime != NOEND_ABSTIME); |
336 | 0 | } |
337 | | |
338 | | |
339 | | /* |
340 | | * abstime comparison routines |
341 | | */ |
342 | | static int |
343 | | abstime_cmp_internal(AbsoluteTime a, AbsoluteTime b) |
344 | 2 | { |
345 | | /* |
346 | | * We consider all INVALIDs to be equal and larger than any non-INVALID. |
347 | | * This is somewhat arbitrary; the important thing is to have a consistent |
348 | | * sort order. |
349 | | */ |
350 | 2 | if (a == INVALID_ABSTIME) |
351 | 0 | { |
352 | 0 | if (b == INVALID_ABSTIME) |
353 | 0 | return 0; /* INVALID = INVALID */ |
354 | 0 | else |
355 | 0 | return 1; /* INVALID > non-INVALID */ |
356 | 0 | } |
357 | | |
358 | 2 | if (b == INVALID_ABSTIME) |
359 | 0 | return -1; /* non-INVALID < INVALID */ |
360 | | |
361 | 2 | if (a > b) |
362 | 0 | return 1; |
363 | 2 | else if (a == b) |
364 | 0 | return 0; |
365 | 2 | else |
366 | 2 | return -1; |
367 | 2 | } |
368 | | |
369 | | Datum |
370 | | abstimeeq(PG_FUNCTION_ARGS) |
371 | 0 | { |
372 | 0 | AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0); |
373 | 0 | AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1); |
374 | |
|
375 | 0 | PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) == 0); |
376 | 0 | } |
377 | | |
378 | | Datum |
379 | | abstimene(PG_FUNCTION_ARGS) |
380 | 0 | { |
381 | 0 | AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0); |
382 | 0 | AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1); |
383 | |
|
384 | 0 | PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) != 0); |
385 | 0 | } |
386 | | |
387 | | Datum |
388 | | abstimelt(PG_FUNCTION_ARGS) |
389 | 1 | { |
390 | 1 | AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0); |
391 | 1 | AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1); |
392 | | |
393 | 1 | PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) < 0); |
394 | 1 | } |
395 | | |
396 | | Datum |
397 | | abstimegt(PG_FUNCTION_ARGS) |
398 | 0 | { |
399 | 0 | AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0); |
400 | 0 | AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1); |
401 | |
|
402 | 0 | PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) > 0); |
403 | 0 | } |
404 | | |
405 | | Datum |
406 | | abstimele(PG_FUNCTION_ARGS) |
407 | 1 | { |
408 | 1 | AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0); |
409 | 1 | AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1); |
410 | | |
411 | 1 | PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) <= 0); |
412 | 1 | } |
413 | | |
414 | | Datum |
415 | | abstimege(PG_FUNCTION_ARGS) |
416 | 0 | { |
417 | 0 | AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0); |
418 | 0 | AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1); |
419 | |
|
420 | 0 | PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) >= 0); |
421 | 0 | } |
422 | | |
423 | | Datum |
424 | | btabstimecmp(PG_FUNCTION_ARGS) |
425 | 0 | { |
426 | 0 | AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0); |
427 | 0 | AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1); |
428 | |
|
429 | 0 | PG_RETURN_INT32(abstime_cmp_internal(t1, t2)); |
430 | 0 | } |
431 | | |
432 | | |
433 | | /* timestamp_abstime() |
434 | | * Convert timestamp to abstime. |
435 | | */ |
436 | | Datum |
437 | | timestamp_abstime(PG_FUNCTION_ARGS) |
438 | 0 | { |
439 | 0 | Timestamp timestamp = PG_GETARG_TIMESTAMP(0); |
440 | 0 | AbsoluteTime result; |
441 | 0 | fsec_t fsec; |
442 | 0 | int tz; |
443 | 0 | struct pg_tm tt, |
444 | 0 | *tm = &tt; |
445 | |
|
446 | 0 | if (TIMESTAMP_IS_NOBEGIN(timestamp)) |
447 | 0 | result = NOSTART_ABSTIME; |
448 | 0 | else if (TIMESTAMP_IS_NOEND(timestamp)) |
449 | 0 | result = NOEND_ABSTIME; |
450 | 0 | else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0) |
451 | 0 | { |
452 | 0 | tz = DetermineTimeZoneOffset(tm, session_timezone); |
453 | 0 | result = tm2abstime(tm, tz); |
454 | 0 | } |
455 | 0 | else |
456 | 0 | { |
457 | 0 | ereport(ERROR, |
458 | 0 | (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), |
459 | 0 | errmsg("timestamp out of range"))); |
460 | 0 | result = INVALID_ABSTIME; |
461 | 0 | } |
462 | | |
463 | 0 | PG_RETURN_ABSOLUTETIME(result); |
464 | 0 | } |
465 | | |
466 | | /* abstime_timestamp() |
467 | | * Convert abstime to timestamp. |
468 | | */ |
469 | | Datum |
470 | | abstime_timestamp(PG_FUNCTION_ARGS) |
471 | 0 | { |
472 | 0 | AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0); |
473 | 0 | Timestamp result; |
474 | 0 | struct pg_tm tt, |
475 | 0 | *tm = &tt; |
476 | 0 | int tz; |
477 | 0 | char zone[MAXDATELEN + 1], |
478 | 0 | *tzn = zone; |
479 | |
|
480 | 0 | switch (abstime) |
481 | 0 | { |
482 | 0 | case INVALID_ABSTIME: |
483 | 0 | ereport(ERROR, |
484 | 0 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
485 | 0 | errmsg("cannot convert abstime \"invalid\" to timestamp"))); |
486 | 0 | TIMESTAMP_NOBEGIN(result); |
487 | 0 | break; |
488 | | |
489 | 0 | case NOSTART_ABSTIME: |
490 | 0 | TIMESTAMP_NOBEGIN(result); |
491 | 0 | break; |
492 | | |
493 | 0 | case NOEND_ABSTIME: |
494 | 0 | TIMESTAMP_NOEND(result); |
495 | 0 | break; |
496 | | |
497 | 0 | default: |
498 | 0 | abstime2tm(abstime, &tz, tm, &tzn); |
499 | 0 | if (tm2timestamp(tm, 0, NULL, &result) != 0) |
500 | 0 | ereport(ERROR, |
501 | 0 | (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), |
502 | 0 | errmsg("timestamp out of range"))); |
503 | 0 | break; |
504 | 0 | }; |
505 | |
|
506 | 0 | PG_RETURN_TIMESTAMP(result); |
507 | 0 | } |
508 | | |
509 | | |
510 | | /* timestamptz_abstime() |
511 | | * Convert timestamp with time zone to abstime. |
512 | | */ |
513 | | Datum |
514 | | timestamptz_abstime(PG_FUNCTION_ARGS) |
515 | 0 | { |
516 | 0 | TimestampTz timestamp = PG_GETARG_TIMESTAMP(0); |
517 | 0 | AbsoluteTime result; |
518 | 0 | fsec_t fsec; |
519 | 0 | struct pg_tm tt, |
520 | 0 | *tm = &tt; |
521 | |
|
522 | 0 | if (TIMESTAMP_IS_NOBEGIN(timestamp)) |
523 | 0 | result = NOSTART_ABSTIME; |
524 | 0 | else if (TIMESTAMP_IS_NOEND(timestamp)) |
525 | 0 | result = NOEND_ABSTIME; |
526 | 0 | else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0) |
527 | 0 | result = tm2abstime(tm, 0); |
528 | 0 | else |
529 | 0 | { |
530 | 0 | ereport(ERROR, |
531 | 0 | (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), |
532 | 0 | errmsg("timestamp out of range"))); |
533 | 0 | result = INVALID_ABSTIME; |
534 | 0 | } |
535 | | |
536 | 0 | PG_RETURN_ABSOLUTETIME(result); |
537 | 0 | } |
538 | | |
539 | | /* abstime_timestamptz() |
540 | | * Convert abstime to timestamp with time zone. |
541 | | */ |
542 | | Datum |
543 | | abstime_timestamptz(PG_FUNCTION_ARGS) |
544 | 0 | { |
545 | 0 | AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0); |
546 | 0 | TimestampTz result; |
547 | 0 | struct pg_tm tt, |
548 | 0 | *tm = &tt; |
549 | 0 | int tz; |
550 | 0 | char zone[MAXDATELEN + 1], |
551 | 0 | *tzn = zone; |
552 | |
|
553 | 0 | switch (abstime) |
554 | 0 | { |
555 | 0 | case INVALID_ABSTIME: |
556 | 0 | ereport(ERROR, |
557 | 0 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
558 | 0 | errmsg("cannot convert abstime \"invalid\" to timestamp"))); |
559 | 0 | TIMESTAMP_NOBEGIN(result); |
560 | 0 | break; |
561 | | |
562 | 0 | case NOSTART_ABSTIME: |
563 | 0 | TIMESTAMP_NOBEGIN(result); |
564 | 0 | break; |
565 | | |
566 | 0 | case NOEND_ABSTIME: |
567 | 0 | TIMESTAMP_NOEND(result); |
568 | 0 | break; |
569 | | |
570 | 0 | default: |
571 | 0 | abstime2tm(abstime, &tz, tm, &tzn); |
572 | 0 | if (tm2timestamp(tm, 0, &tz, &result) != 0) |
573 | 0 | ereport(ERROR, |
574 | 0 | (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), |
575 | 0 | errmsg("timestamp out of range"))); |
576 | 0 | break; |
577 | 0 | }; |
578 | |
|
579 | 0 | PG_RETURN_TIMESTAMP(result); |
580 | 0 | } |
581 | | |
582 | | |
583 | | /***************************************************************************** |
584 | | * USER I/O ROUTINES * |
585 | | *****************************************************************************/ |
586 | | |
587 | | /* |
588 | | * reltimein - converts a reltime string in an internal format |
589 | | */ |
590 | | Datum |
591 | | reltimein(PG_FUNCTION_ARGS) |
592 | 0 | { |
593 | 0 | char *str = PG_GETARG_CSTRING(0); |
594 | 0 | RelativeTime result; |
595 | 0 | struct pg_tm tt, |
596 | 0 | *tm = &tt; |
597 | 0 | fsec_t fsec; |
598 | 0 | int dtype; |
599 | 0 | int dterr; |
600 | 0 | char *field[MAXDATEFIELDS]; |
601 | 0 | int nf, |
602 | 0 | ftype[MAXDATEFIELDS]; |
603 | 0 | char workbuf[MAXDATELEN + 1]; |
604 | |
|
605 | 0 | dterr = ParseDateTime(str, workbuf, sizeof(workbuf), |
606 | 0 | field, ftype, MAXDATEFIELDS, &nf); |
607 | 0 | if (dterr == 0) |
608 | 0 | dterr = DecodeInterval(field, ftype, nf, INTERVAL_FULL_RANGE, |
609 | 0 | &dtype, tm, &fsec); |
610 | | |
611 | | /* if those functions think it's a bad format, try ISO8601 style */ |
612 | 0 | if (dterr == DTERR_BAD_FORMAT) |
613 | 0 | dterr = DecodeISO8601Interval(str, |
614 | 0 | &dtype, tm, &fsec); |
615 | |
|
616 | 0 | if (dterr != 0) |
617 | 0 | { |
618 | 0 | if (dterr == DTERR_FIELD_OVERFLOW) |
619 | 0 | dterr = DTERR_INTERVAL_OVERFLOW; |
620 | 0 | DateTimeParseError(dterr, str, "reltime"); |
621 | 0 | } |
622 | | |
623 | 0 | switch (dtype) |
624 | 0 | { |
625 | 0 | case DTK_DELTA: |
626 | 0 | result = ((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec; |
627 | 0 | result += tm->tm_year * SECS_PER_YEAR + ((tm->tm_mon * DAYS_PER_MONTH) + tm->tm_mday) * SECS_PER_DAY; |
628 | 0 | break; |
629 | | |
630 | 0 | default: |
631 | 0 | elog(ERROR, "unexpected dtype %d while parsing reltime \"%s\"", |
632 | 0 | dtype, str); |
633 | 0 | result = INVALID_RELTIME; |
634 | 0 | break; |
635 | 0 | } |
636 | | |
637 | 0 | PG_RETURN_RELATIVETIME(result); |
638 | 0 | } |
639 | | |
640 | | /* |
641 | | * reltimeout - converts the internal format to a reltime string |
642 | | */ |
643 | | Datum |
644 | | reltimeout(PG_FUNCTION_ARGS) |
645 | 0 | { |
646 | 0 | RelativeTime time = PG_GETARG_RELATIVETIME(0); |
647 | 0 | char *result; |
648 | 0 | struct pg_tm tt, |
649 | 0 | *tm = &tt; |
650 | 0 | char buf[MAXDATELEN + 1]; |
651 | |
|
652 | 0 | reltime2tm(time, tm); |
653 | 0 | EncodeInterval(tm, 0, IntervalStyle, buf); |
654 | |
|
655 | 0 | result = pstrdup(buf); |
656 | 0 | PG_RETURN_CSTRING(result); |
657 | 0 | } |
658 | | |
659 | | /* |
660 | | * reltimerecv - converts external binary format to reltime |
661 | | */ |
662 | | Datum |
663 | | reltimerecv(PG_FUNCTION_ARGS) |
664 | 0 | { |
665 | 0 | StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); |
666 | |
|
667 | 0 | PG_RETURN_RELATIVETIME((RelativeTime) pq_getmsgint(buf, sizeof(RelativeTime))); |
668 | 0 | } |
669 | | |
670 | | /* |
671 | | * reltimesend - converts reltime to binary format |
672 | | */ |
673 | | Datum |
674 | | reltimesend(PG_FUNCTION_ARGS) |
675 | 0 | { |
676 | 0 | RelativeTime time = PG_GETARG_RELATIVETIME(0); |
677 | 0 | StringInfoData buf; |
678 | |
|
679 | 0 | pq_begintypsend(&buf); |
680 | 0 | pq_sendint32(&buf, time); |
681 | 0 | PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); |
682 | 0 | } |
683 | | |
684 | | |
685 | | static void |
686 | | reltime2tm(RelativeTime time, struct pg_tm *tm) |
687 | 0 | { |
688 | 0 | double dtime = time; |
689 | |
|
690 | 0 | FMODULO(dtime, tm->tm_year, 31557600); |
691 | 0 | FMODULO(dtime, tm->tm_mon, 2592000); |
692 | 0 | FMODULO(dtime, tm->tm_mday, SECS_PER_DAY); |
693 | 0 | FMODULO(dtime, tm->tm_hour, SECS_PER_HOUR); |
694 | 0 | FMODULO(dtime, tm->tm_min, SECS_PER_MINUTE); |
695 | 0 | FMODULO(dtime, tm->tm_sec, 1); |
696 | 0 | } |
697 | | |
698 | | |
699 | | /* |
700 | | * tintervalin - converts a tinterval string to internal format |
701 | | */ |
702 | | Datum |
703 | | tintervalin(PG_FUNCTION_ARGS) |
704 | 1 | { |
705 | 1 | char *tintervalstr = PG_GETARG_CSTRING(0); |
706 | 1 | TimeInterval tinterval; |
707 | 1 | AbsoluteTime i_start, |
708 | 1 | i_end, |
709 | 1 | t1, |
710 | 1 | t2; |
711 | | |
712 | 1 | parsetinterval(tintervalstr, &t1, &t2); |
713 | | |
714 | 1 | tinterval = (TimeInterval) palloc(sizeof(TimeIntervalData)); |
715 | | |
716 | 1 | if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME) |
717 | 0 | tinterval->status = T_INTERVAL_INVAL; /* undefined */ |
718 | 1 | else |
719 | 1 | tinterval->status = T_INTERVAL_VALID; |
720 | | |
721 | 1 | i_start = ABSTIMEMIN(t1, t2); |
722 | 1 | i_end = ABSTIMEMAX(t1, t2); |
723 | 1 | tinterval->data[0] = i_start; |
724 | 1 | tinterval->data[1] = i_end; |
725 | | |
726 | 1 | PG_RETURN_TIMEINTERVAL(tinterval); |
727 | 1 | } |
728 | | |
729 | | |
730 | | /* |
731 | | * tintervalout - converts an internal tinterval format to a string |
732 | | */ |
733 | | Datum |
734 | | tintervalout(PG_FUNCTION_ARGS) |
735 | 1 | { |
736 | 1 | TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(0); |
737 | 1 | char *i_str, |
738 | 1 | *p; |
739 | | |
740 | 1 | i_str = (char *) palloc(T_INTERVAL_LEN); /* ["..." "..."] */ |
741 | 1 | strcpy(i_str, "[\""); |
742 | 1 | if (tinterval->status == T_INTERVAL_INVAL) |
743 | 0 | strcat(i_str, INVALID_INTERVAL_STR); |
744 | 1 | else |
745 | 1 | { |
746 | 1 | p = DatumGetCString(DirectFunctionCall1(abstimeout, |
747 | 1 | AbsoluteTimeGetDatum(tinterval->data[0]))); |
748 | 1 | strcat(i_str, p); |
749 | 1 | pfree(p); |
750 | 1 | strcat(i_str, "\" \""); |
751 | 1 | p = DatumGetCString(DirectFunctionCall1(abstimeout, |
752 | 1 | AbsoluteTimeGetDatum(tinterval->data[1]))); |
753 | 1 | strcat(i_str, p); |
754 | 1 | pfree(p); |
755 | 1 | } |
756 | 1 | strcat(i_str, "\"]"); |
757 | 1 | PG_RETURN_CSTRING(i_str); |
758 | 1 | } |
759 | | |
760 | | /* |
761 | | * tintervalrecv - converts external binary format to tinterval |
762 | | */ |
763 | | Datum |
764 | | tintervalrecv(PG_FUNCTION_ARGS) |
765 | 0 | { |
766 | 0 | StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); |
767 | 0 | TimeInterval tinterval; |
768 | 0 | int32 status; |
769 | |
|
770 | 0 | tinterval = (TimeInterval) palloc(sizeof(TimeIntervalData)); |
771 | |
|
772 | 0 | tinterval->status = pq_getmsgint(buf, sizeof(tinterval->status)); |
773 | 0 | tinterval->data[0] = pq_getmsgint(buf, sizeof(tinterval->data[0])); |
774 | 0 | tinterval->data[1] = pq_getmsgint(buf, sizeof(tinterval->data[1])); |
775 | |
|
776 | 0 | if (tinterval->data[0] == INVALID_ABSTIME || |
777 | 0 | tinterval->data[1] == INVALID_ABSTIME) |
778 | 0 | status = T_INTERVAL_INVAL; /* undefined */ |
779 | 0 | else |
780 | 0 | status = T_INTERVAL_VALID; |
781 | |
|
782 | 0 | if (status != tinterval->status) |
783 | 0 | ereport(ERROR, |
784 | 0 | (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), |
785 | 0 | errmsg("invalid status in external \"tinterval\" value"))); |
786 | | |
787 | 0 | PG_RETURN_TIMEINTERVAL(tinterval); |
788 | 0 | } |
789 | | |
790 | | /* |
791 | | * tintervalsend - converts tinterval to binary format |
792 | | */ |
793 | | Datum |
794 | | tintervalsend(PG_FUNCTION_ARGS) |
795 | 0 | { |
796 | 0 | TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(0); |
797 | 0 | StringInfoData buf; |
798 | |
|
799 | 0 | pq_begintypsend(&buf); |
800 | 0 | pq_sendint32(&buf, tinterval->status); |
801 | 0 | pq_sendint32(&buf, tinterval->data[0]); |
802 | 0 | pq_sendint32(&buf, tinterval->data[1]); |
803 | 0 | PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); |
804 | 0 | } |
805 | | |
806 | | |
807 | | /***************************************************************************** |
808 | | * PUBLIC ROUTINES * |
809 | | *****************************************************************************/ |
810 | | |
811 | | Datum |
812 | | interval_reltime(PG_FUNCTION_ARGS) |
813 | 0 | { |
814 | 0 | Interval *interval = PG_GETARG_INTERVAL_P(0); |
815 | 0 | RelativeTime time; |
816 | 0 | int year, |
817 | 0 | month, |
818 | 0 | day; |
819 | 0 | TimeOffset span; |
820 | |
|
821 | 0 | year = interval->month / MONTHS_PER_YEAR; |
822 | 0 | month = interval->month % MONTHS_PER_YEAR; |
823 | 0 | day = interval->day; |
824 | |
|
825 | 0 | span = ((INT64CONST(365250000) * year + INT64CONST(30000000) * month + |
826 | 0 | INT64CONST(1000000) * day) * INT64CONST(86400)) + |
827 | 0 | interval->time; |
828 | 0 | span /= USECS_PER_SEC; |
829 | |
|
830 | 0 | if (span < INT_MIN || span > INT_MAX) |
831 | 0 | time = INVALID_RELTIME; |
832 | 0 | else |
833 | 0 | time = span; |
834 | |
|
835 | 0 | PG_RETURN_RELATIVETIME(time); |
836 | 0 | } |
837 | | |
838 | | |
839 | | Datum |
840 | | reltime_interval(PG_FUNCTION_ARGS) |
841 | 0 | { |
842 | 0 | RelativeTime reltime = PG_GETARG_RELATIVETIME(0); |
843 | 0 | Interval *result; |
844 | 0 | int year, |
845 | 0 | month, |
846 | 0 | day; |
847 | |
|
848 | 0 | result = (Interval *) palloc(sizeof(Interval)); |
849 | |
|
850 | 0 | switch (reltime) |
851 | 0 | { |
852 | 0 | case INVALID_RELTIME: |
853 | 0 | ereport(ERROR, |
854 | 0 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
855 | 0 | errmsg("cannot convert reltime \"invalid\" to interval"))); |
856 | 0 | result->time = 0; |
857 | 0 | result->day = 0; |
858 | 0 | result->month = 0; |
859 | 0 | break; |
860 | | |
861 | 0 | default: |
862 | 0 | year = reltime / SECS_PER_YEAR; |
863 | 0 | reltime -= year * SECS_PER_YEAR; |
864 | 0 | month = reltime / (DAYS_PER_MONTH * SECS_PER_DAY); |
865 | 0 | reltime -= month * (DAYS_PER_MONTH * SECS_PER_DAY); |
866 | 0 | day = reltime / SECS_PER_DAY; |
867 | 0 | reltime -= day * SECS_PER_DAY; |
868 | |
|
869 | 0 | result->time = (reltime * USECS_PER_SEC); |
870 | 0 | result->month = MONTHS_PER_YEAR * year + month; |
871 | 0 | result->day = day; |
872 | 0 | break; |
873 | 0 | } |
874 | | |
875 | 0 | PG_RETURN_INTERVAL_P(result); |
876 | 0 | } |
877 | | |
878 | | |
879 | | /* |
880 | | * mktinterval - creates a time interval with endpoints t1 and t2 |
881 | | */ |
882 | | Datum |
883 | | mktinterval(PG_FUNCTION_ARGS) |
884 | 0 | { |
885 | 0 | AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0); |
886 | 0 | AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1); |
887 | 0 | AbsoluteTime tstart = ABSTIMEMIN(t1, t2); |
888 | 0 | AbsoluteTime tend = ABSTIMEMAX(t1, t2); |
889 | 0 | TimeInterval tinterval; |
890 | |
|
891 | 0 | tinterval = (TimeInterval) palloc(sizeof(TimeIntervalData)); |
892 | |
|
893 | 0 | if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME) |
894 | 0 | tinterval->status = T_INTERVAL_INVAL; |
895 | | |
896 | 0 | else |
897 | 0 | { |
898 | 0 | tinterval->status = T_INTERVAL_VALID; |
899 | 0 | tinterval->data[0] = tstart; |
900 | 0 | tinterval->data[1] = tend; |
901 | 0 | } |
902 | |
|
903 | 0 | PG_RETURN_TIMEINTERVAL(tinterval); |
904 | 0 | } |
905 | | |
906 | | /* |
907 | | * timepl, timemi and abstimemi use the formula |
908 | | * abstime + reltime = abstime |
909 | | * so abstime - reltime = abstime |
910 | | * and abstime - abstime = reltime |
911 | | */ |
912 | | |
913 | | /* |
914 | | * timepl - returns the value of (abstime t1 + reltime t2) |
915 | | */ |
916 | | Datum |
917 | | timepl(PG_FUNCTION_ARGS) |
918 | 0 | { |
919 | 0 | AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0); |
920 | 0 | RelativeTime t2 = PG_GETARG_RELATIVETIME(1); |
921 | |
|
922 | 0 | if (AbsoluteTimeIsReal(t1) && |
923 | 0 | RelativeTimeIsValid(t2) && |
924 | 0 | ((t2 > 0 && t1 < NOEND_ABSTIME - t2) || |
925 | 0 | (t2 <= 0 && t1 > NOSTART_ABSTIME - t2))) /* prevent overflow */ |
926 | 0 | PG_RETURN_ABSOLUTETIME(t1 + t2); |
927 | | |
928 | 0 | PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME); |
929 | 0 | } |
930 | | |
931 | | |
932 | | /* |
933 | | * timemi - returns the value of (abstime t1 - reltime t2) |
934 | | */ |
935 | | Datum |
936 | | timemi(PG_FUNCTION_ARGS) |
937 | 0 | { |
938 | 0 | AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0); |
939 | 0 | RelativeTime t2 = PG_GETARG_RELATIVETIME(1); |
940 | |
|
941 | 0 | if (AbsoluteTimeIsReal(t1) && |
942 | 0 | RelativeTimeIsValid(t2) && |
943 | 0 | ((t2 > 0 && t1 > NOSTART_ABSTIME + t2) || |
944 | 0 | (t2 <= 0 && t1 < NOEND_ABSTIME + t2))) /* prevent overflow */ |
945 | 0 | PG_RETURN_ABSOLUTETIME(t1 - t2); |
946 | | |
947 | 0 | PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME); |
948 | 0 | } |
949 | | |
950 | | |
951 | | /* |
952 | | * intinterval - returns true iff absolute date is in the tinterval |
953 | | */ |
954 | | Datum |
955 | | intinterval(PG_FUNCTION_ARGS) |
956 | 0 | { |
957 | 0 | AbsoluteTime t = PG_GETARG_ABSOLUTETIME(0); |
958 | 0 | TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(1); |
959 | |
|
960 | 0 | if (tinterval->status == T_INTERVAL_VALID && t != INVALID_ABSTIME) |
961 | 0 | { |
962 | 0 | if (DatumGetBool(DirectFunctionCall2(abstimege, |
963 | 0 | AbsoluteTimeGetDatum(t), |
964 | 0 | AbsoluteTimeGetDatum(tinterval->data[0]))) && |
965 | 0 | DatumGetBool(DirectFunctionCall2(abstimele, |
966 | 0 | AbsoluteTimeGetDatum(t), |
967 | 0 | AbsoluteTimeGetDatum(tinterval->data[1])))) |
968 | 0 | PG_RETURN_BOOL(true); |
969 | 0 | } |
970 | 0 | PG_RETURN_BOOL(false); |
971 | 0 | } |
972 | | |
973 | | /* |
974 | | * tintervalrel - returns relative time corresponding to tinterval |
975 | | */ |
976 | | Datum |
977 | | tintervalrel(PG_FUNCTION_ARGS) |
978 | 0 | { |
979 | 0 | TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(0); |
980 | 0 | AbsoluteTime t1 = tinterval->data[0]; |
981 | 0 | AbsoluteTime t2 = tinterval->data[1]; |
982 | |
|
983 | 0 | if (tinterval->status != T_INTERVAL_VALID) |
984 | 0 | PG_RETURN_RELATIVETIME(INVALID_RELTIME); |
985 | | |
986 | 0 | if (AbsoluteTimeIsReal(t1) && |
987 | 0 | AbsoluteTimeIsReal(t2)) |
988 | 0 | PG_RETURN_RELATIVETIME(t2 - t1); |
989 | | |
990 | 0 | PG_RETURN_RELATIVETIME(INVALID_RELTIME); |
991 | 0 | } |
992 | | |
993 | | |
994 | | /* |
995 | | * timenow - returns time "now", internal format |
996 | | * |
997 | | * Now AbsoluteTime is time since Jan 1 1970 -mer 7 Feb 1992 |
998 | | */ |
999 | | Datum |
1000 | | timenow(PG_FUNCTION_ARGS) |
1001 | 0 | { |
1002 | 0 | PG_RETURN_ABSOLUTETIME(GetCurrentAbsoluteTime()); |
1003 | 0 | } |
1004 | | |
1005 | | /* |
1006 | | * reltime comparison routines |
1007 | | */ |
1008 | | static int |
1009 | | reltime_cmp_internal(RelativeTime a, RelativeTime b) |
1010 | 0 | { |
1011 | | /* |
1012 | | * We consider all INVALIDs to be equal and larger than any non-INVALID. |
1013 | | * This is somewhat arbitrary; the important thing is to have a consistent |
1014 | | * sort order. |
1015 | | */ |
1016 | 0 | if (a == INVALID_RELTIME) |
1017 | 0 | { |
1018 | 0 | if (b == INVALID_RELTIME) |
1019 | 0 | return 0; /* INVALID = INVALID */ |
1020 | 0 | else |
1021 | 0 | return 1; /* INVALID > non-INVALID */ |
1022 | 0 | } |
1023 | | |
1024 | 0 | if (b == INVALID_RELTIME) |
1025 | 0 | return -1; /* non-INVALID < INVALID */ |
1026 | | |
1027 | 0 | if (a > b) |
1028 | 0 | return 1; |
1029 | 0 | else if (a == b) |
1030 | 0 | return 0; |
1031 | 0 | else |
1032 | 0 | return -1; |
1033 | 0 | } |
1034 | | |
1035 | | Datum |
1036 | | reltimeeq(PG_FUNCTION_ARGS) |
1037 | 0 | { |
1038 | 0 | RelativeTime t1 = PG_GETARG_RELATIVETIME(0); |
1039 | 0 | RelativeTime t2 = PG_GETARG_RELATIVETIME(1); |
1040 | |
|
1041 | 0 | PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) == 0); |
1042 | 0 | } |
1043 | | |
1044 | | Datum |
1045 | | reltimene(PG_FUNCTION_ARGS) |
1046 | 0 | { |
1047 | 0 | RelativeTime t1 = PG_GETARG_RELATIVETIME(0); |
1048 | 0 | RelativeTime t2 = PG_GETARG_RELATIVETIME(1); |
1049 | |
|
1050 | 0 | PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) != 0); |
1051 | 0 | } |
1052 | | |
1053 | | Datum |
1054 | | reltimelt(PG_FUNCTION_ARGS) |
1055 | 0 | { |
1056 | 0 | RelativeTime t1 = PG_GETARG_RELATIVETIME(0); |
1057 | 0 | RelativeTime t2 = PG_GETARG_RELATIVETIME(1); |
1058 | |
|
1059 | 0 | PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) < 0); |
1060 | 0 | } |
1061 | | |
1062 | | Datum |
1063 | | reltimegt(PG_FUNCTION_ARGS) |
1064 | 0 | { |
1065 | 0 | RelativeTime t1 = PG_GETARG_RELATIVETIME(0); |
1066 | 0 | RelativeTime t2 = PG_GETARG_RELATIVETIME(1); |
1067 | |
|
1068 | 0 | PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) > 0); |
1069 | 0 | } |
1070 | | |
1071 | | Datum |
1072 | | reltimele(PG_FUNCTION_ARGS) |
1073 | 0 | { |
1074 | 0 | RelativeTime t1 = PG_GETARG_RELATIVETIME(0); |
1075 | 0 | RelativeTime t2 = PG_GETARG_RELATIVETIME(1); |
1076 | |
|
1077 | 0 | PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) <= 0); |
1078 | 0 | } |
1079 | | |
1080 | | Datum |
1081 | | reltimege(PG_FUNCTION_ARGS) |
1082 | 0 | { |
1083 | 0 | RelativeTime t1 = PG_GETARG_RELATIVETIME(0); |
1084 | 0 | RelativeTime t2 = PG_GETARG_RELATIVETIME(1); |
1085 | |
|
1086 | 0 | PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) >= 0); |
1087 | 0 | } |
1088 | | |
1089 | | Datum |
1090 | | btreltimecmp(PG_FUNCTION_ARGS) |
1091 | 0 | { |
1092 | 0 | RelativeTime t1 = PG_GETARG_RELATIVETIME(0); |
1093 | 0 | RelativeTime t2 = PG_GETARG_RELATIVETIME(1); |
1094 | |
|
1095 | 0 | PG_RETURN_INT32(reltime_cmp_internal(t1, t2)); |
1096 | 0 | } |
1097 | | |
1098 | | |
1099 | | /* |
1100 | | * tintervalsame - returns true iff tinterval i1 is same as tinterval i2 |
1101 | | * Check begin and end time. |
1102 | | */ |
1103 | | Datum |
1104 | | tintervalsame(PG_FUNCTION_ARGS) |
1105 | 0 | { |
1106 | 0 | TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0); |
1107 | 0 | TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1); |
1108 | |
|
1109 | 0 | if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) |
1110 | 0 | PG_RETURN_BOOL(false); |
1111 | | |
1112 | 0 | if (DatumGetBool(DirectFunctionCall2(abstimeeq, |
1113 | 0 | AbsoluteTimeGetDatum(i1->data[0]), |
1114 | 0 | AbsoluteTimeGetDatum(i2->data[0]))) && |
1115 | 0 | DatumGetBool(DirectFunctionCall2(abstimeeq, |
1116 | 0 | AbsoluteTimeGetDatum(i1->data[1]), |
1117 | 0 | AbsoluteTimeGetDatum(i2->data[1])))) |
1118 | 0 | PG_RETURN_BOOL(true); |
1119 | 0 | PG_RETURN_BOOL(false); |
1120 | 0 | } |
1121 | | |
1122 | | /* |
1123 | | * tinterval comparison routines |
1124 | | * |
1125 | | * Note: comparison is based only on the lengths of the tintervals, not on |
1126 | | * endpoint values (as long as they're not INVALID). This is pretty bogus, |
1127 | | * but since it's only a legacy datatype, we're not going to change it. |
1128 | | * |
1129 | | * Some other bogus things that won't be changed for compatibility reasons: |
1130 | | * 1. The interval length computations overflow at 2^31 seconds, causing |
1131 | | * intervals longer than that to sort oddly compared to those shorter. |
1132 | | * 2. infinity and minus infinity (NOEND_ABSTIME and NOSTART_ABSTIME) are |
1133 | | * just ordinary integers. Since this code doesn't handle them specially, |
1134 | | * it's possible for [a b] to be considered longer than [c infinity] for |
1135 | | * finite abstimes a, b, c. In combination with the previous point, the |
1136 | | * interval [-infinity infinity] is treated as being shorter than many finite |
1137 | | * intervals :-( |
1138 | | * |
1139 | | * If tinterval is ever reimplemented atop timestamp, it'd be good to give |
1140 | | * some consideration to avoiding these problems. |
1141 | | */ |
1142 | | static int |
1143 | | tinterval_cmp_internal(TimeInterval a, TimeInterval b) |
1144 | 0 | { |
1145 | 0 | bool a_invalid; |
1146 | 0 | bool b_invalid; |
1147 | 0 | AbsoluteTime a_len; |
1148 | 0 | AbsoluteTime b_len; |
1149 | | |
1150 | | /* |
1151 | | * We consider all INVALIDs to be equal and larger than any non-INVALID. |
1152 | | * This is somewhat arbitrary; the important thing is to have a consistent |
1153 | | * sort order. |
1154 | | */ |
1155 | 0 | a_invalid = a->status == T_INTERVAL_INVAL || |
1156 | 0 | a->data[0] == INVALID_ABSTIME || |
1157 | 0 | a->data[1] == INVALID_ABSTIME; |
1158 | 0 | b_invalid = b->status == T_INTERVAL_INVAL || |
1159 | 0 | b->data[0] == INVALID_ABSTIME || |
1160 | 0 | b->data[1] == INVALID_ABSTIME; |
1161 | |
|
1162 | 0 | if (a_invalid) |
1163 | 0 | { |
1164 | 0 | if (b_invalid) |
1165 | 0 | return 0; /* INVALID = INVALID */ |
1166 | 0 | else |
1167 | 0 | return 1; /* INVALID > non-INVALID */ |
1168 | 0 | } |
1169 | | |
1170 | 0 | if (b_invalid) |
1171 | 0 | return -1; /* non-INVALID < INVALID */ |
1172 | | |
1173 | 0 | a_len = a->data[1] - a->data[0]; |
1174 | 0 | b_len = b->data[1] - b->data[0]; |
1175 | |
|
1176 | 0 | if (a_len > b_len) |
1177 | 0 | return 1; |
1178 | 0 | else if (a_len == b_len) |
1179 | 0 | return 0; |
1180 | 0 | else |
1181 | 0 | return -1; |
1182 | 0 | } |
1183 | | |
1184 | | Datum |
1185 | | tintervaleq(PG_FUNCTION_ARGS) |
1186 | 0 | { |
1187 | 0 | TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0); |
1188 | 0 | TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1); |
1189 | |
|
1190 | 0 | PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) == 0); |
1191 | 0 | } |
1192 | | |
1193 | | Datum |
1194 | | tintervalne(PG_FUNCTION_ARGS) |
1195 | 0 | { |
1196 | 0 | TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0); |
1197 | 0 | TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1); |
1198 | |
|
1199 | 0 | PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) != 0); |
1200 | 0 | } |
1201 | | |
1202 | | Datum |
1203 | | tintervallt(PG_FUNCTION_ARGS) |
1204 | 0 | { |
1205 | 0 | TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0); |
1206 | 0 | TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1); |
1207 | |
|
1208 | 0 | PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) < 0); |
1209 | 0 | } |
1210 | | |
1211 | | Datum |
1212 | | tintervalle(PG_FUNCTION_ARGS) |
1213 | 0 | { |
1214 | 0 | TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0); |
1215 | 0 | TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1); |
1216 | |
|
1217 | 0 | PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) <= 0); |
1218 | 0 | } |
1219 | | |
1220 | | Datum |
1221 | | tintervalgt(PG_FUNCTION_ARGS) |
1222 | 0 | { |
1223 | 0 | TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0); |
1224 | 0 | TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1); |
1225 | |
|
1226 | 0 | PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) > 0); |
1227 | 0 | } |
1228 | | |
1229 | | Datum |
1230 | | tintervalge(PG_FUNCTION_ARGS) |
1231 | 0 | { |
1232 | 0 | TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0); |
1233 | 0 | TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1); |
1234 | |
|
1235 | 0 | PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) >= 0); |
1236 | 0 | } |
1237 | | |
1238 | | Datum |
1239 | | bttintervalcmp(PG_FUNCTION_ARGS) |
1240 | 0 | { |
1241 | 0 | TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0); |
1242 | 0 | TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1); |
1243 | |
|
1244 | 0 | PG_RETURN_INT32(tinterval_cmp_internal(i1, i2)); |
1245 | 0 | } |
1246 | | |
1247 | | |
1248 | | /* |
1249 | | * tintervalleneq - returns true iff length of tinterval i is equal to |
1250 | | * reltime t |
1251 | | * tintervallenne - returns true iff length of tinterval i is not equal |
1252 | | * to reltime t |
1253 | | * tintervallenlt - returns true iff length of tinterval i is less than |
1254 | | * reltime t |
1255 | | * tintervallengt - returns true iff length of tinterval i is greater |
1256 | | * than reltime t |
1257 | | * tintervallenle - returns true iff length of tinterval i is less or |
1258 | | * equal than reltime t |
1259 | | * tintervallenge - returns true iff length of tinterval i is greater or |
1260 | | * equal than reltime t |
1261 | | */ |
1262 | | Datum |
1263 | | tintervalleneq(PG_FUNCTION_ARGS) |
1264 | 0 | { |
1265 | 0 | TimeInterval i = PG_GETARG_TIMEINTERVAL(0); |
1266 | 0 | RelativeTime t = PG_GETARG_RELATIVETIME(1); |
1267 | 0 | RelativeTime rt; |
1268 | |
|
1269 | 0 | if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME) |
1270 | 0 | PG_RETURN_BOOL(false); |
1271 | 0 | rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel, |
1272 | 0 | TimeIntervalGetDatum(i))); |
1273 | 0 | PG_RETURN_BOOL(rt != INVALID_RELTIME && rt == t); |
1274 | 0 | } |
1275 | | |
1276 | | Datum |
1277 | | tintervallenne(PG_FUNCTION_ARGS) |
1278 | 0 | { |
1279 | 0 | TimeInterval i = PG_GETARG_TIMEINTERVAL(0); |
1280 | 0 | RelativeTime t = PG_GETARG_RELATIVETIME(1); |
1281 | 0 | RelativeTime rt; |
1282 | |
|
1283 | 0 | if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME) |
1284 | 0 | PG_RETURN_BOOL(false); |
1285 | 0 | rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel, |
1286 | 0 | TimeIntervalGetDatum(i))); |
1287 | 0 | PG_RETURN_BOOL(rt != INVALID_RELTIME && rt != t); |
1288 | 0 | } |
1289 | | |
1290 | | Datum |
1291 | | tintervallenlt(PG_FUNCTION_ARGS) |
1292 | 0 | { |
1293 | 0 | TimeInterval i = PG_GETARG_TIMEINTERVAL(0); |
1294 | 0 | RelativeTime t = PG_GETARG_RELATIVETIME(1); |
1295 | 0 | RelativeTime rt; |
1296 | |
|
1297 | 0 | if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME) |
1298 | 0 | PG_RETURN_BOOL(false); |
1299 | 0 | rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel, |
1300 | 0 | TimeIntervalGetDatum(i))); |
1301 | 0 | PG_RETURN_BOOL(rt != INVALID_RELTIME && rt < t); |
1302 | 0 | } |
1303 | | |
1304 | | Datum |
1305 | | tintervallengt(PG_FUNCTION_ARGS) |
1306 | 0 | { |
1307 | 0 | TimeInterval i = PG_GETARG_TIMEINTERVAL(0); |
1308 | 0 | RelativeTime t = PG_GETARG_RELATIVETIME(1); |
1309 | 0 | RelativeTime rt; |
1310 | |
|
1311 | 0 | if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME) |
1312 | 0 | PG_RETURN_BOOL(false); |
1313 | 0 | rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel, |
1314 | 0 | TimeIntervalGetDatum(i))); |
1315 | 0 | PG_RETURN_BOOL(rt != INVALID_RELTIME && rt > t); |
1316 | 0 | } |
1317 | | |
1318 | | Datum |
1319 | | tintervallenle(PG_FUNCTION_ARGS) |
1320 | 0 | { |
1321 | 0 | TimeInterval i = PG_GETARG_TIMEINTERVAL(0); |
1322 | 0 | RelativeTime t = PG_GETARG_RELATIVETIME(1); |
1323 | 0 | RelativeTime rt; |
1324 | |
|
1325 | 0 | if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME) |
1326 | 0 | PG_RETURN_BOOL(false); |
1327 | 0 | rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel, |
1328 | 0 | TimeIntervalGetDatum(i))); |
1329 | 0 | PG_RETURN_BOOL(rt != INVALID_RELTIME && rt <= t); |
1330 | 0 | } |
1331 | | |
1332 | | Datum |
1333 | | tintervallenge(PG_FUNCTION_ARGS) |
1334 | 0 | { |
1335 | 0 | TimeInterval i = PG_GETARG_TIMEINTERVAL(0); |
1336 | 0 | RelativeTime t = PG_GETARG_RELATIVETIME(1); |
1337 | 0 | RelativeTime rt; |
1338 | |
|
1339 | 0 | if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME) |
1340 | 0 | PG_RETURN_BOOL(false); |
1341 | 0 | rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel, |
1342 | 0 | TimeIntervalGetDatum(i))); |
1343 | 0 | PG_RETURN_BOOL(rt != INVALID_RELTIME && rt >= t); |
1344 | 0 | } |
1345 | | |
1346 | | /* |
1347 | | * tintervalct - returns true iff tinterval i1 contains tinterval i2 |
1348 | | */ |
1349 | | Datum |
1350 | | tintervalct(PG_FUNCTION_ARGS) |
1351 | 0 | { |
1352 | 0 | TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0); |
1353 | 0 | TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1); |
1354 | |
|
1355 | 0 | if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) |
1356 | 0 | PG_RETURN_BOOL(false); |
1357 | 0 | if (DatumGetBool(DirectFunctionCall2(abstimele, |
1358 | 0 | AbsoluteTimeGetDatum(i1->data[0]), |
1359 | 0 | AbsoluteTimeGetDatum(i2->data[0]))) && |
1360 | 0 | DatumGetBool(DirectFunctionCall2(abstimege, |
1361 | 0 | AbsoluteTimeGetDatum(i1->data[1]), |
1362 | 0 | AbsoluteTimeGetDatum(i2->data[1])))) |
1363 | 0 | PG_RETURN_BOOL(true); |
1364 | 0 | PG_RETURN_BOOL(false); |
1365 | 0 | } |
1366 | | |
1367 | | /* |
1368 | | * tintervalov - returns true iff tinterval i1 (partially) overlaps i2 |
1369 | | */ |
1370 | | Datum |
1371 | | tintervalov(PG_FUNCTION_ARGS) |
1372 | 0 | { |
1373 | 0 | TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0); |
1374 | 0 | TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1); |
1375 | |
|
1376 | 0 | if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) |
1377 | 0 | PG_RETURN_BOOL(false); |
1378 | 0 | if (DatumGetBool(DirectFunctionCall2(abstimelt, |
1379 | 0 | AbsoluteTimeGetDatum(i1->data[1]), |
1380 | 0 | AbsoluteTimeGetDatum(i2->data[0]))) || |
1381 | 0 | DatumGetBool(DirectFunctionCall2(abstimegt, |
1382 | 0 | AbsoluteTimeGetDatum(i1->data[0]), |
1383 | 0 | AbsoluteTimeGetDatum(i2->data[1])))) |
1384 | 0 | PG_RETURN_BOOL(false); |
1385 | 0 | PG_RETURN_BOOL(true); |
1386 | 0 | } |
1387 | | |
1388 | | /* |
1389 | | * tintervalstart - returns the start of tinterval i |
1390 | | */ |
1391 | | Datum |
1392 | | tintervalstart(PG_FUNCTION_ARGS) |
1393 | 0 | { |
1394 | 0 | TimeInterval i = PG_GETARG_TIMEINTERVAL(0); |
1395 | |
|
1396 | 0 | if (i->status == T_INTERVAL_INVAL) |
1397 | 0 | PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME); |
1398 | 0 | PG_RETURN_ABSOLUTETIME(i->data[0]); |
1399 | 0 | } |
1400 | | |
1401 | | /* |
1402 | | * tintervalend - returns the end of tinterval i |
1403 | | */ |
1404 | | Datum |
1405 | | tintervalend(PG_FUNCTION_ARGS) |
1406 | 0 | { |
1407 | 0 | TimeInterval i = PG_GETARG_TIMEINTERVAL(0); |
1408 | |
|
1409 | 0 | if (i->status == T_INTERVAL_INVAL) |
1410 | 0 | PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME); |
1411 | 0 | PG_RETURN_ABSOLUTETIME(i->data[1]); |
1412 | 0 | } |
1413 | | |
1414 | | |
1415 | | /***************************************************************************** |
1416 | | * PRIVATE ROUTINES * |
1417 | | *****************************************************************************/ |
1418 | | |
1419 | | /* |
1420 | | * parsetinterval -- parse a tinterval string |
1421 | | * |
1422 | | * output parameters: |
1423 | | * i_start, i_end: tinterval margins |
1424 | | * |
1425 | | * Time interval: |
1426 | | * `[' {` '} `'' <AbsTime> `'' {` '} `'' <AbsTime> `'' {` '} `]' |
1427 | | * |
1428 | | * OR `Undefined Range' (see also INVALID_INTERVAL_STR) |
1429 | | * |
1430 | | * where <AbsTime> satisfies the syntax of absolute time. |
1431 | | * |
1432 | | * e.g. [ ' Jan 18 1902' 'Jan 1 00:00:00 1970'] |
1433 | | */ |
1434 | | static void |
1435 | | parsetinterval(char *i_string, |
1436 | | AbsoluteTime *i_start, |
1437 | | AbsoluteTime *i_end) |
1438 | 1 | { |
1439 | 1 | char *p, |
1440 | 1 | *p1; |
1441 | 1 | char c; |
1442 | | |
1443 | 1 | p = i_string; |
1444 | | /* skip leading blanks up to '[' */ |
1445 | 1 | while ((c = *p) != '\0') |
1446 | 1 | { |
1447 | 1 | if (IsSpace(c)) |
1448 | 0 | p++; |
1449 | 1 | else if (c != '[') |
1450 | 0 | goto bogus; /* syntax error */ |
1451 | 1 | else |
1452 | 1 | break; |
1453 | 1 | } |
1454 | 1 | if (c == '\0') |
1455 | 0 | goto bogus; /* syntax error */ |
1456 | 1 | p++; |
1457 | | /* skip leading blanks up to '"' */ |
1458 | 1 | while ((c = *p) != '\0') |
1459 | 1 | { |
1460 | 1 | if (IsSpace(c)) |
1461 | 0 | p++; |
1462 | 1 | else if (c != '"') |
1463 | 0 | goto bogus; /* syntax error */ |
1464 | 1 | else |
1465 | 1 | break; |
1466 | 1 | } |
1467 | 1 | if (c == '\0') |
1468 | 0 | goto bogus; /* syntax error */ |
1469 | 1 | p++; |
1470 | 1 | if (strncmp(INVALID_INTERVAL_STR, p, strlen(INVALID_INTERVAL_STR)) == 0) |
1471 | 0 | goto bogus; /* undefined range, handled like a syntax err. */ |
1472 | | /* search for the end of the first date and change it to a \0 */ |
1473 | 1 | p1 = p; |
1474 | 20 | while ((c = *p1) != '\0') |
1475 | 20 | { |
1476 | 20 | if (c == '"') |
1477 | 1 | break; |
1478 | 19 | p1++; |
1479 | 19 | } |
1480 | 1 | if (c == '\0') |
1481 | 0 | goto bogus; /* syntax error */ |
1482 | 1 | *p1 = '\0'; |
1483 | | /* get the first date */ |
1484 | 1 | *i_start = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein, |
1485 | 1 | CStringGetDatum(p))); |
1486 | | /* undo change to \0 */ |
1487 | 1 | *p1 = c; |
1488 | 1 | p = ++p1; |
1489 | | /* skip blanks up to '"', beginning of second date */ |
1490 | 2 | while ((c = *p) != '\0') |
1491 | 2 | { |
1492 | 2 | if (IsSpace(c)) |
1493 | 1 | p++; |
1494 | 1 | else if (c != '"') |
1495 | 0 | goto bogus; /* syntax error */ |
1496 | 1 | else |
1497 | 1 | break; |
1498 | 2 | } |
1499 | 1 | if (c == '\0') |
1500 | 0 | goto bogus; /* syntax error */ |
1501 | 1 | p++; |
1502 | | /* search for the end of the second date and change it to a \0 */ |
1503 | 1 | p1 = p; |
1504 | 20 | while ((c = *p1) != '\0') |
1505 | 20 | { |
1506 | 20 | if (c == '"') |
1507 | 1 | break; |
1508 | 19 | p1++; |
1509 | 19 | } |
1510 | 1 | if (c == '\0') |
1511 | 0 | goto bogus; /* syntax error */ |
1512 | 1 | *p1 = '\0'; |
1513 | | /* get the second date */ |
1514 | 1 | *i_end = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein, |
1515 | 1 | CStringGetDatum(p))); |
1516 | | /* undo change to \0 */ |
1517 | 1 | *p1 = c; |
1518 | 1 | p = ++p1; |
1519 | | /* skip blanks up to ']' */ |
1520 | 1 | while ((c = *p) != '\0') |
1521 | 1 | { |
1522 | 1 | if (IsSpace(c)) |
1523 | 0 | p++; |
1524 | 1 | else if (c != ']') |
1525 | 0 | goto bogus; /* syntax error */ |
1526 | 1 | else |
1527 | 1 | break; |
1528 | 1 | } |
1529 | 1 | if (c == '\0') |
1530 | 0 | goto bogus; /* syntax error */ |
1531 | 1 | p++; |
1532 | 1 | c = *p; |
1533 | 1 | if (c != '\0') |
1534 | 0 | goto bogus; /* syntax error */ |
1535 | | |
1536 | | /* it seems to be a valid tinterval */ |
1537 | 1 | return; |
1538 | | |
1539 | 1 | bogus: |
1540 | 0 | ereport(ERROR, |
1541 | 0 | (errcode(ERRCODE_INVALID_DATETIME_FORMAT), |
1542 | 0 | errmsg("invalid input syntax for type %s: \"%s\"", |
1543 | 0 | "tinterval", i_string))); |
1544 | 0 | *i_start = *i_end = INVALID_ABSTIME; /* keep compiler quiet */ |
1545 | 0 | } |
1546 | | |
1547 | | |
1548 | | /***************************************************************************** |
1549 | | * |
1550 | | *****************************************************************************/ |
1551 | | |
1552 | | /* |
1553 | | * timeofday - |
1554 | | * returns the current time as a text. similar to timenow() but returns |
1555 | | * seconds with more precision (up to microsecs). (I need this to compare |
1556 | | * the Wisconsin benchmark with Illustra whose TimeNow() shows current |
1557 | | * time with precision up to microsecs.) - ay 3/95 |
1558 | | */ |
1559 | | Datum |
1560 | | timeofday(PG_FUNCTION_ARGS) |
1561 | 0 | { |
1562 | 0 | struct timeval tp; |
1563 | 0 | char templ[128]; |
1564 | 0 | char buf[128]; |
1565 | 0 | pg_time_t tt; |
1566 | |
|
1567 | 0 | gettimeofday(&tp, NULL); |
1568 | 0 | tt = (pg_time_t) tp.tv_sec; |
1569 | 0 | pg_strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z", |
1570 | 0 | pg_localtime(&tt, session_timezone)); |
1571 | 0 | snprintf(buf, sizeof(buf), templ, tp.tv_usec); |
1572 | |
|
1573 | 0 | PG_RETURN_TEXT_P(cstring_to_text(buf)); |
1574 | 0 | } |