Skip to content

Commit 4f33572

Browse files
committed
Fix incorrect translation of minus-infinity datetimes for json/jsonb.
Commit bda76c1 caused both plus and minus infinity to be rendered as "infinity", which is not only wrong but inconsistent with the pre-9.4 behavior of to_json(). Fix that by duplicating the coding in date_out/timestamp_out/timestamptz_out more closely. Per bug #13687 from Stepan Perlov. Back-patch to 9.4, like the previous commit. In passing, also re-pgindent json.c, since it had gotten a bit messed up by recent patches (and I was already annoyed by indentation-related problems in back-patching this fix ...)
1 parent 7fc7125 commit 4f33572

File tree

7 files changed

+35
-30
lines changed

7 files changed

+35
-30
lines changed

src/backend/utils/adt/date.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
#endif
4141

4242

43-
static void EncodeSpecialDate(DateADT dt, char *str);
4443
static int time2tm(TimeADT time, struct pg_tm * tm, fsec_t *fsec);
4544
static int timetz2tm(TimeTzADT *time, struct pg_tm * tm, fsec_t *fsec, int *tzp);
4645
static int tm2time(struct pg_tm * tm, fsec_t fsec, TimeADT *result);
@@ -273,7 +272,7 @@ make_date(PG_FUNCTION_ARGS)
273272
/*
274273
* Convert reserved date values to string.
275274
*/
276-
static void
275+
void
277276
EncodeSpecialDate(DateADT dt, char *str)
278277
{
279278
if (DATE_IS_NOBEGIN(dt))

src/backend/utils/adt/json.c

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@
3333
#include "utils/typcache.h"
3434
#include "utils/syscache.h"
3535

36-
/* String to output for infinite dates and timestamps */
37-
#define DT_INFINITY "\"infinity\""
38-
3936
/*
4037
* The context of the parser is maintained by the recursive descent
4138
* mechanism, but is passed explicitly to the error reporting routine
@@ -1435,19 +1432,16 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
14351432
char buf[MAXDATELEN + 1];
14361433

14371434
date = DatumGetDateADT(val);
1438-
1435+
/* Same as date_out(), but forcing DateStyle */
14391436
if (DATE_NOT_FINITE(date))
1440-
{
1441-
/* we have to format infinity ourselves */
1442-
appendStringInfoString(result,DT_INFINITY);
1443-
}
1437+
EncodeSpecialDate(date, buf);
14441438
else
14451439
{
14461440
j2date(date + POSTGRES_EPOCH_JDATE,
14471441
&(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
14481442
EncodeDateOnly(&tm, USE_XSD_DATES, buf);
1449-
appendStringInfo(result, "\"%s\"", buf);
14501443
}
1444+
appendStringInfo(result, "\"%s\"", buf);
14511445
}
14521446
break;
14531447
case JSONTYPE_TIMESTAMP:
@@ -1458,21 +1452,16 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
14581452
char buf[MAXDATELEN + 1];
14591453

14601454
timestamp = DatumGetTimestamp(val);
1461-
1455+
/* Same as timestamp_out(), but forcing DateStyle */
14621456
if (TIMESTAMP_NOT_FINITE(timestamp))
1463-
{
1464-
/* we have to format infinity ourselves */
1465-
appendStringInfoString(result,DT_INFINITY);
1466-
}
1457+
EncodeSpecialTimestamp(timestamp, buf);
14671458
else if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, NULL) == 0)
1468-
{
14691459
EncodeDateTime(&tm, fsec, false, 0, NULL, USE_XSD_DATES, buf);
1470-
appendStringInfo(result, "\"%s\"", buf);
1471-
}
14721460
else
14731461
ereport(ERROR,
14741462
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
14751463
errmsg("timestamp out of range")));
1464+
appendStringInfo(result, "\"%s\"", buf);
14761465
}
14771466
break;
14781467
case JSONTYPE_TIMESTAMPTZ:
@@ -1484,22 +1473,17 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
14841473
const char *tzn = NULL;
14851474
char buf[MAXDATELEN + 1];
14861475

1487-
timestamp = DatumGetTimestamp(val);
1488-
1476+
timestamp = DatumGetTimestampTz(val);
1477+
/* Same as timestamptz_out(), but forcing DateStyle */
14891478
if (TIMESTAMP_NOT_FINITE(timestamp))
1490-
{
1491-
/* we have to format infinity ourselves */
1492-
appendStringInfoString(result,DT_INFINITY);
1493-
}
1479+
EncodeSpecialTimestamp(timestamp, buf);
14941480
else if (timestamp2tm(timestamp, &tz, &tm, &fsec, &tzn, NULL) == 0)
1495-
{
14961481
EncodeDateTime(&tm, fsec, true, tz, tzn, USE_XSD_DATES, buf);
1497-
appendStringInfo(result, "\"%s\"", buf);
1498-
}
14991482
else
15001483
ereport(ERROR,
15011484
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
15021485
errmsg("timestamp out of range")));
1486+
appendStringInfo(result, "\"%s\"", buf);
15031487
}
15041488
break;
15051489
case JSONTYPE_JSON:

src/backend/utils/adt/timestamp.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ typedef struct
7575

7676

7777
static TimeOffset time2t(const int hour, const int min, const int sec, const fsec_t fsec);
78-
static void EncodeSpecialTimestamp(Timestamp dt, char *str);
7978
static Timestamp dt2local(Timestamp dt, int timezone);
8079
static void AdjustTimestampForTypmod(Timestamp *time, int32 typmod);
8180
static void AdjustIntervalForTypmod(Interval *interval, int32 typmod);
@@ -1507,7 +1506,7 @@ make_interval(PG_FUNCTION_ARGS)
15071506
/* EncodeSpecialTimestamp()
15081507
* Convert reserved timestamp data type to string.
15091508
*/
1510-
static void
1509+
void
15111510
EncodeSpecialTimestamp(Timestamp dt, char *str)
15121511
{
15131512
if (TIMESTAMP_IS_NOBEGIN(dt))

src/include/utils/date.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ typedef struct
9292

9393
/* date.c */
9494
extern double date2timestamp_no_overflow(DateADT dateVal);
95+
extern void EncodeSpecialDate(DateADT dt, char *str);
9596

9697
extern Datum date_in(PG_FUNCTION_ARGS);
9798
extern Datum date_out(PG_FUNCTION_ARGS);

src/include/utils/datetime.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ extern void EncodeDateOnly(struct pg_tm * tm, int style, char *str);
319319
extern void EncodeTimeOnly(struct pg_tm * tm, fsec_t fsec, bool print_tz, int tz, int style, char *str);
320320
extern void EncodeDateTime(struct pg_tm * tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str);
321321
extern void EncodeInterval(struct pg_tm * tm, fsec_t fsec, int style, char *str);
322+
extern void EncodeSpecialTimestamp(Timestamp dt, char *str);
322323

323324
extern int ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc,
324325
struct pg_tm * tm);

src/test/regress/expected/json.out

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,18 +418,36 @@ select to_json(date 'Infinity');
418418
"infinity"
419419
(1 row)
420420

421+
select to_json(date '-Infinity');
422+
to_json
423+
-------------
424+
"-infinity"
425+
(1 row)
426+
421427
select to_json(timestamp 'Infinity');
422428
to_json
423429
------------
424430
"infinity"
425431
(1 row)
426432

433+
select to_json(timestamp '-Infinity');
434+
to_json
435+
-------------
436+
"-infinity"
437+
(1 row)
438+
427439
select to_json(timestamptz 'Infinity');
428440
to_json
429441
------------
430442
"infinity"
431443
(1 row)
432444

445+
select to_json(timestamptz '-Infinity');
446+
to_json
447+
-------------
448+
"-infinity"
449+
(1 row)
450+
433451
--json_agg
434452
SELECT json_agg(q)
435453
FROM ( SELECT $$a$$ || x AS b, y AS c,

src/test/regress/sql/json.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,11 @@ COMMIT;
116116
select to_json(date '2014-05-28');
117117

118118
select to_json(date 'Infinity');
119+
select to_json(date '-Infinity');
119120
select to_json(timestamp 'Infinity');
121+
select to_json(timestamp '-Infinity');
120122
select to_json(timestamptz 'Infinity');
123+
select to_json(timestamptz '-Infinity');
121124

122125
--json_agg
123126

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy