summaryrefslogtreecommitdiffstats
path: root/meta-oe/recipes-support/postgresql/files/0006-Fix-handling-of-wide-datetime-input-output.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-oe/recipes-support/postgresql/files/0006-Fix-handling-of-wide-datetime-input-output.patch')
-rw-r--r--meta-oe/recipes-support/postgresql/files/0006-Fix-handling-of-wide-datetime-input-output.patch465
1 files changed, 465 insertions, 0 deletions
diff --git a/meta-oe/recipes-support/postgresql/files/0006-Fix-handling-of-wide-datetime-input-output.patch b/meta-oe/recipes-support/postgresql/files/0006-Fix-handling-of-wide-datetime-input-output.patch
new file mode 100644
index 000000000..fac0a7347
--- /dev/null
+++ b/meta-oe/recipes-support/postgresql/files/0006-Fix-handling-of-wide-datetime-input-output.patch
@@ -0,0 +1,465 @@
1From f416622be81d1320417bbc7892fd562cae0dba72 Mon Sep 17 00:00:00 2001
2From: Noah Misch <noah@leadboat.com>
3Date: Mon, 17 Feb 2014 09:33:31 -0500
4Subject: [PATCH] Fix handling of wide datetime input/output.
5MIME-Version: 1.0
6Content-Type: text/plain; charset=UTF-8
7Content-Transfer-Encoding: 8bit
8
9commit f416622be81d1320417bbc7892fd562cae0dba72 REL9_2_STABLE
10
11Many server functions use the MAXDATELEN constant to size a buffer for
12parsing or displaying a datetime value. It was much too small for the
13longest possible interval output and slightly too small for certain
14valid timestamp input, particularly input with a long timezone name.
15The long input was rejected needlessly; the long output caused
16interval_out() to overrun its buffer. ECPG's pgtypes library has a copy
17of the vulnerable functions, which bore the same vulnerabilities along
18with some of its own. In contrast to the server, certain long inputs
19caused stack overflow rather than failing cleanly. Back-patch to 8.4
20(all supported versions).
21
22Reported by Daniel Schüssler, reviewed by Tom Lane.
23
24Security: CVE-2014-0063
25
26
27Upstream-Status: Backport
28
29Signed-off-by: Kai Kang <kai.kang@windriver.com>
30---
31 src/include/utils/datetime.h | 17 +++++---
32 src/interfaces/ecpg/pgtypeslib/datetime.c | 4 +-
33 src/interfaces/ecpg/pgtypeslib/dt.h | 17 +++++---
34 src/interfaces/ecpg/pgtypeslib/dt_common.c | 44 ++++++++++++++------
35 src/interfaces/ecpg/pgtypeslib/interval.c | 2 +-
36 src/interfaces/ecpg/pgtypeslib/timestamp.c | 2 +-
37 .../ecpg/test/expected/pgtypeslib-dt_test2.c | 22 +++++++---
38 .../ecpg/test/expected/pgtypeslib-dt_test2.stdout | 19 ++++++++
39 src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc | 10 ++++
40 src/test/regress/expected/interval.out | 7 +++
41 src/test/regress/sql/interval.sql | 2 +
42 11 files changed, 111 insertions(+), 35 deletions(-)
43
44diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h
45index d73cc8d..4b805b6 100644
46--- a/src/include/utils/datetime.h
47+++ b/src/include/utils/datetime.h
48@@ -188,12 +188,17 @@ struct tzEntry;
49 #define DTK_DATE_M (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY))
50 #define DTK_TIME_M (DTK_M(HOUR) | DTK_M(MINUTE) | DTK_ALL_SECS_M)
51
52-#define MAXDATELEN 63 /* maximum possible length of an input date
53- * string (not counting tr. null) */
54-#define MAXDATEFIELDS 25 /* maximum possible number of fields in a date
55- * string */
56-#define TOKMAXLEN 10 /* only this many chars are stored in
57- * datetktbl */
58+/*
59+ * Working buffer size for input and output of interval, timestamp, etc.
60+ * Inputs that need more working space will be rejected early. Longer outputs
61+ * will overrun buffers, so this must suffice for all possible output. As of
62+ * this writing, interval_out() needs the most space at ~90 bytes.
63+ */
64+#define MAXDATELEN 128
65+/* maximum possible number of fields in a date string */
66+#define MAXDATEFIELDS 25
67+/* only this many chars are stored in datetktbl */
68+#define TOKMAXLEN 10
69
70 /* keep this struct small; it gets used a lot */
71 typedef struct
72diff --git a/src/interfaces/ecpg/pgtypeslib/datetime.c b/src/interfaces/ecpg/pgtypeslib/datetime.c
73index 823626f..4adcd1e 100644
74--- a/src/interfaces/ecpg/pgtypeslib/datetime.c
75+++ b/src/interfaces/ecpg/pgtypeslib/datetime.c
76@@ -61,14 +61,14 @@ PGTYPESdate_from_asc(char *str, char **endptr)
77 int nf;
78 char *field[MAXDATEFIELDS];
79 int ftype[MAXDATEFIELDS];
80- char lowstr[MAXDATELEN + 1];
81+ char lowstr[MAXDATELEN + MAXDATEFIELDS];
82 char *realptr;
83 char **ptr = (endptr != NULL) ? endptr : &realptr;
84
85 bool EuroDates = FALSE;
86
87 errno = 0;
88- if (strlen(str) >= sizeof(lowstr))
89+ if (strlen(str) > MAXDATELEN)
90 {
91 errno = PGTYPES_DATE_BAD_DATE;
92 return INT_MIN;
93diff --git a/src/interfaces/ecpg/pgtypeslib/dt.h b/src/interfaces/ecpg/pgtypeslib/dt.h
94index dfe6f9e..2780593 100644
95--- a/src/interfaces/ecpg/pgtypeslib/dt.h
96+++ b/src/interfaces/ecpg/pgtypeslib/dt.h
97@@ -192,12 +192,17 @@ typedef double fsec_t;
98 #define DTK_DATE_M (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY))
99 #define DTK_TIME_M (DTK_M(HOUR) | DTK_M(MINUTE) | DTK_M(SECOND))
100
101-#define MAXDATELEN 63 /* maximum possible length of an input date
102- * string (not counting tr. null) */
103-#define MAXDATEFIELDS 25 /* maximum possible number of fields in a date
104- * string */
105-#define TOKMAXLEN 10 /* only this many chars are stored in
106- * datetktbl */
107+/*
108+ * Working buffer size for input and output of interval, timestamp, etc.
109+ * Inputs that need more working space will be rejected early. Longer outputs
110+ * will overrun buffers, so this must suffice for all possible output. As of
111+ * this writing, PGTYPESinterval_to_asc() needs the most space at ~90 bytes.
112+ */
113+#define MAXDATELEN 128
114+/* maximum possible number of fields in a date string */
115+#define MAXDATEFIELDS 25
116+/* only this many chars are stored in datetktbl */
117+#define TOKMAXLEN 10
118
119 /* keep this struct small; it gets used a lot */
120 typedef struct
121diff --git a/src/interfaces/ecpg/pgtypeslib/dt_common.c b/src/interfaces/ecpg/pgtypeslib/dt_common.c
122index 6b89e4a..18178dd 100644
123--- a/src/interfaces/ecpg/pgtypeslib/dt_common.c
124+++ b/src/interfaces/ecpg/pgtypeslib/dt_common.c
125@@ -1171,15 +1171,22 @@ DecodeNumberField(int len, char *str, int fmask,
126 if ((cp = strchr(str, '.')) != NULL)
127 {
128 #ifdef HAVE_INT64_TIMESTAMP
129- char fstr[MAXDATELEN + 1];
130+ char fstr[7];
131+ int i;
132+
133+ cp++;
134
135 /*
136 * OK, we have at most six digits to care about. Let's construct a
137- * string and then do the conversion to an integer.
138+ * string with those digits, zero-padded on the right, and then do
139+ * the conversion to an integer.
140+ *
141+ * XXX This truncates the seventh digit, unlike rounding it as do
142+ * the backend and the !HAVE_INT64_TIMESTAMP case.
143 */
144- strcpy(fstr, (cp + 1));
145- strcpy(fstr + strlen(fstr), "000000");
146- *(fstr + 6) = '\0';
147+ for (i = 0; i < 6; i++)
148+ fstr[i] = *cp != '\0' ? *cp++ : '0';
149+ fstr[i] = '\0';
150 *fsec = strtol(fstr, NULL, 10);
151 #else
152 *fsec = strtod(cp, NULL);
153@@ -1531,15 +1538,22 @@ DecodeTime(char *str, int *tmask, struct tm * tm, fsec_t *fsec)
154 else if (*cp == '.')
155 {
156 #ifdef HAVE_INT64_TIMESTAMP
157- char fstr[MAXDATELEN + 1];
158+ char fstr[7];
159+ int i;
160+
161+ cp++;
162
163 /*
164- * OK, we have at most six digits to work with. Let's construct a
165- * string and then do the conversion to an integer.
166+ * OK, we have at most six digits to care about. Let's construct a
167+ * string with those digits, zero-padded on the right, and then do
168+ * the conversion to an integer.
169+ *
170+ * XXX This truncates the seventh digit, unlike rounding it as do
171+ * the backend and the !HAVE_INT64_TIMESTAMP case.
172 */
173- strncpy(fstr, (cp + 1), 7);
174- strcpy(fstr + strlen(fstr), "000000");
175- *(fstr + 6) = '\0';
176+ for (i = 0; i < 6; i++)
177+ fstr[i] = *cp != '\0' ? *cp++ : '0';
178+ fstr[i] = '\0';
179 *fsec = strtol(fstr, &cp, 10);
180 #else
181 str = cp;
182@@ -1665,6 +1679,9 @@ DecodePosixTimezone(char *str, int *tzp)
183 * DTK_NUMBER can hold date fields (yy.ddd)
184 * DTK_STRING can hold months (January) and time zones (PST)
185 * DTK_DATE can hold Posix time zones (GMT-8)
186+ *
187+ * The "lowstr" work buffer must have at least strlen(timestr) + MAXDATEFIELDS
188+ * bytes of space. On output, field[] entries will point into it.
189 */
190 int
191 ParseDateTime(char *timestr, char *lowstr,
192@@ -1677,7 +1694,10 @@ ParseDateTime(char *timestr, char *lowstr,
193 /* outer loop through fields */
194 while (*(*endstr) != '\0')
195 {
196+ /* Record start of current field */
197 field[nf] = lp;
198+ if (nf >= MAXDATEFIELDS)
199+ return -1;
200
201 /* leading digit? then date or time */
202 if (isdigit((unsigned char) *(*endstr)))
203@@ -1818,8 +1838,6 @@ ParseDateTime(char *timestr, char *lowstr,
204 /* force in a delimiter after each field */
205 *lp++ = '\0';
206 nf++;
207- if (nf > MAXDATEFIELDS)
208- return -1;
209 }
210
211 *numfields = nf;
212diff --git a/src/interfaces/ecpg/pgtypeslib/interval.c b/src/interfaces/ecpg/pgtypeslib/interval.c
213index bcc10ee..fdd8f49 100644
214--- a/src/interfaces/ecpg/pgtypeslib/interval.c
215+++ b/src/interfaces/ecpg/pgtypeslib/interval.c
216@@ -1092,7 +1092,7 @@ PGTYPESinterval_from_asc(char *str, char **endptr)
217 tm->tm_sec = 0;
218 fsec = 0;
219
220- if (strlen(str) >= sizeof(lowstr))
221+ if (strlen(str) > MAXDATELEN)
222 {
223 errno = PGTYPES_INTVL_BAD_INTERVAL;
224 return NULL;
225diff --git a/src/interfaces/ecpg/pgtypeslib/timestamp.c b/src/interfaces/ecpg/pgtypeslib/timestamp.c
226index 7d3f7c8..4f91e63 100644
227--- a/src/interfaces/ecpg/pgtypeslib/timestamp.c
228+++ b/src/interfaces/ecpg/pgtypeslib/timestamp.c
229@@ -297,7 +297,7 @@ PGTYPEStimestamp_from_asc(char *str, char **endptr)
230 char *realptr;
231 char **ptr = (endptr != NULL) ? endptr : &realptr;
232
233- if (strlen(str) >= sizeof(lowstr))
234+ if (strlen(str) > MAXDATELEN)
235 {
236 errno = PGTYPES_TS_BAD_TIMESTAMP;
237 return (noresult);
238diff --git a/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.c b/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.c
239index d3ebb0e..0ba1936 100644
240--- a/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.c
241+++ b/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.c
242@@ -45,6 +45,15 @@ char *dates[] = { "19990108foobar",
243 "1999.008",
244 "J2451187",
245 "January 8, 99 BC",
246+ /*
247+ * Maximize space usage in ParseDateTime() with 25
248+ * (MAXDATEFIELDS) fields and 128 (MAXDATELEN) total length.
249+ */
250+ "........................Xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
251+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
252+ /* 26 fields */
253+ ".........................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
254+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
255 NULL };
256
257 /* do not conflict with libc "times" symbol */
258@@ -52,6 +61,7 @@ static char *times[] = { "0:04",
259 "1:59 PDT",
260 "13:24:40 -8:00",
261 "13:24:40.495+3",
262+ "13:24:40.123456789+3",
263 NULL };
264
265 char *intervals[] = { "1 minute",
266@@ -73,22 +83,22 @@ main(void)
267
268
269
270-#line 52 "dt_test2.pgc"
271+#line 62 "dt_test2.pgc"
272 date date1 ;
273
274-#line 53 "dt_test2.pgc"
275+#line 63 "dt_test2.pgc"
276 timestamp ts1 , ts2 ;
277
278-#line 54 "dt_test2.pgc"
279+#line 64 "dt_test2.pgc"
280 char * text ;
281
282-#line 55 "dt_test2.pgc"
283+#line 65 "dt_test2.pgc"
284 interval * i1 ;
285
286-#line 56 "dt_test2.pgc"
287+#line 66 "dt_test2.pgc"
288 date * dc ;
289 /* exec sql end declare section */
290-#line 57 "dt_test2.pgc"
291+#line 67 "dt_test2.pgc"
292
293
294 int i, j;
295diff --git a/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.stdout b/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.stdout
296index 24e9d26..9a4587b 100644
297--- a/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.stdout
298+++ b/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.stdout
299@@ -8,85 +8,104 @@ TS[3,0]: 1999-01-08 00:04:00
300 TS[3,1]: 1999-01-08 01:59:00
301 TS[3,2]: 1999-01-08 13:24:40
302 TS[3,3]: 1999-01-08 13:24:40.495
303+TS[3,4]: 1999-01-08 13:24:40.123456
304 Date[4]: 1999-01-08 (N - F)
305 TS[4,0]: 1999-01-08 00:04:00
306 TS[4,1]: 1999-01-08 01:59:00
307 TS[4,2]: 1999-01-08 13:24:40
308 TS[4,3]: 1999-01-08 13:24:40.495
309+TS[4,4]: 1999-01-08 13:24:40.123456
310 Date[5]: 1999-01-08 (N - F)
311 TS[5,0]: 1999-01-08 00:04:00
312 TS[5,1]: 1999-01-08 01:59:00
313 TS[5,2]: 1999-01-08 13:24:40
314 TS[5,3]: 1999-01-08 13:24:40.495
315+TS[5,4]: 1999-01-08 13:24:40.123456
316 Date[6]: 1999-01-18 (N - F)
317 TS[6,0]: 1999-01-18 00:04:00
318 TS[6,1]: 1999-01-18 01:59:00
319 TS[6,2]: 1999-01-18 13:24:40
320 TS[6,3]: 1999-01-18 13:24:40.495
321+TS[6,4]: 1999-01-18 13:24:40.123456
322 Date[7]: 2003-01-02 (N - F)
323 TS[7,0]: 2003-01-02 00:04:00
324 TS[7,1]: 2003-01-02 01:59:00
325 TS[7,2]: 2003-01-02 13:24:40
326 TS[7,3]: 2003-01-02 13:24:40.495
327+TS[7,4]: 2003-01-02 13:24:40.123456
328 Date[8]: 1999-01-08 (N - F)
329 TS[8,0]: 1999-01-08 00:04:00
330 TS[8,1]: 1999-01-08 01:59:00
331 TS[8,2]: 1999-01-08 13:24:40
332 TS[8,3]: 1999-01-08 13:24:40.495
333+TS[8,4]: 1999-01-08 13:24:40.123456
334 Date[9]: 1999-01-08 (N - F)
335 TS[9,0]: 1999-01-08 00:04:00
336 TS[9,1]: 1999-01-08 01:59:00
337 TS[9,2]: 1999-01-08 13:24:40
338 TS[9,3]: 1999-01-08 13:24:40.495
339+TS[9,4]: 1999-01-08 13:24:40.123456
340 Date[10]: 1999-01-08 (N - F)
341 TS[10,0]: 1999-01-08 00:04:00
342 TS[10,1]: 1999-01-08 01:59:00
343 TS[10,2]: 1999-01-08 13:24:40
344 TS[10,3]: 1999-01-08 13:24:40.495
345+TS[10,4]: 1999-01-08 13:24:40.123456
346 Date[11]: 1999-01-08 (N - F)
347 TS[11,0]: 1999-01-08 00:04:00
348 TS[11,1]: 1999-01-08 01:59:00
349 TS[11,2]: 1999-01-08 13:24:40
350 TS[11,3]: 1999-01-08 13:24:40.495
351+TS[11,4]: 1999-01-08 13:24:40.123456
352 Date[12]: 1999-01-08 (N - F)
353 TS[12,0]: 1999-01-08 00:04:00
354 TS[12,1]: 1999-01-08 01:59:00
355 TS[12,2]: 1999-01-08 13:24:40
356 TS[12,3]: 1999-01-08 13:24:40.495
357+TS[12,4]: 1999-01-08 13:24:40.123456
358 Date[13]: 2006-01-08 (N - F)
359 TS[13,0]: 2006-01-08 00:04:00
360 TS[13,1]: 2006-01-08 01:59:00
361 TS[13,2]: 2006-01-08 13:24:40
362 TS[13,3]: 2006-01-08 13:24:40.495
363+TS[13,4]: 2006-01-08 13:24:40.123456
364 Date[14]: 1999-01-08 (N - F)
365 TS[14,0]: 1999-01-08 00:04:00
366 TS[14,1]: 1999-01-08 01:59:00
367 TS[14,2]: 1999-01-08 13:24:40
368 TS[14,3]: 1999-01-08 13:24:40.495
369+TS[14,4]: 1999-01-08 13:24:40.123456
370 Date[15]: 1999-01-08 (N - F)
371 TS[15,0]: 1999-01-08 00:04:00
372 TS[15,1]: 1999-01-08 01:59:00
373 TS[15,2]: 1999-01-08 13:24:40
374 TS[15,3]: 1999-01-08 13:24:40.495
375+TS[15,4]: 1999-01-08 13:24:40.123456
376 Date[16]: 1999-01-08 (N - F)
377 TS[16,0]: 1999-01-08 00:04:00
378 TS[16,1]: 1999-01-08 01:59:00
379 TS[16,2]: 1999-01-08 13:24:40
380 TS[16,3]: 1999-01-08 13:24:40.495
381+TS[16,4]: 1999-01-08 13:24:40.123456
382 Date[17]: 1999-01-08 (N - F)
383 TS[17,0]: 1999-01-08 00:04:00
384 TS[17,1]: 1999-01-08 01:59:00
385 TS[17,2]: 1999-01-08 13:24:40
386 TS[17,3]: 1999-01-08 13:24:40.495
387+TS[17,4]: 1999-01-08 13:24:40.123456
388 Date[18]: 1999-01-08 (N - F)
389 TS[18,0]: 1999-01-08 00:04:00
390 TS[18,1]: 1999-01-08 01:59:00
391 TS[18,2]: 1999-01-08 13:24:40
392 TS[18,3]: 1999-01-08 13:24:40.495
393+TS[18,4]: 1999-01-08 13:24:40.123456
394 Date[19]: 0099-01-08 BC (N - F)
395 TS[19,0]: 0099-01-08 00:04:00 BC
396 TS[19,1]: 0099-01-08 01:59:00 BC
397 TS[19,2]: 0099-01-08 13:24:40 BC
398+TS[19,4]: 0099-01-08 13:24:40.123456 BC
399+Date[20]: - (N - T)
400+Date[21]: - (N - T)
401 interval[0]: @ 1 min
402 interval_copy[0]: @ 1 min
403 interval[1]: @ 1 day 12 hours 59 mins 10 secs
404diff --git a/src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc b/src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc
405index 0edf012..a127dd9 100644
406--- a/src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc
407+++ b/src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc
408@@ -27,6 +27,15 @@ char *dates[] = { "19990108foobar",
409 "1999.008",
410 "J2451187",
411 "January 8, 99 BC",
412+ /*
413+ * Maximize space usage in ParseDateTime() with 25
414+ * (MAXDATEFIELDS) fields and 128 (MAXDATELEN) total length.
415+ */
416+ "........................Xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
417+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
418+ /* 26 fields */
419+ ".........................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
420+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
421 NULL };
422
423 /* do not conflict with libc "times" symbol */
424@@ -34,6 +43,7 @@ static char *times[] = { "0:04",
425 "1:59 PDT",
426 "13:24:40 -8:00",
427 "13:24:40.495+3",
428+ "13:24:40.123456789+3",
429 NULL };
430
431 char *intervals[] = { "1 minute",
432diff --git a/src/test/regress/expected/interval.out b/src/test/regress/expected/interval.out
433index 3bf2211..99fd0ca 100644
434--- a/src/test/regress/expected/interval.out
435+++ b/src/test/regress/expected/interval.out
436@@ -306,6 +306,13 @@ select '4 millenniums 5 centuries 4 decades 1 year 4 months 4 days 17 minutes 31
437 @ 4541 years 4 mons 4 days 17 mins 31 secs
438 (1 row)
439
440+-- test long interval output
441+select '100000000y 10mon -1000000000d -1000000000h -10min -10.000001s ago'::interval;
442+ interval
443+-------------------------------------------------------------------------------------------
444+ @ 100000000 years 10 mons -1000000000 days -1000000000 hours -10 mins -10.000001 secs ago
445+(1 row)
446+
447 -- test justify_hours() and justify_days()
448 SELECT justify_hours(interval '6 months 3 days 52 hours 3 minutes 2 seconds') as "6 mons 5 days 4 hours 3 mins 2 seconds";
449 6 mons 5 days 4 hours 3 mins 2 seconds
450diff --git a/src/test/regress/sql/interval.sql b/src/test/regress/sql/interval.sql
451index f1da4c2..7cee286 100644
452--- a/src/test/regress/sql/interval.sql
453+++ b/src/test/regress/sql/interval.sql
454@@ -108,6 +108,8 @@ select avg(f1) from interval_tbl;
455 -- test long interval input
456 select '4 millenniums 5 centuries 4 decades 1 year 4 months 4 days 17 minutes 31 seconds'::interval;
457
458+-- test long interval output
459+select '100000000y 10mon -1000000000d -1000000000h -10min -10.000001s ago'::interval;
460
461 -- test justify_hours() and justify_days()
462
463--
4641.7.5.4
465