Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd435542

Browse files
committed
Fix incorrect translation of minus-infinity datetimes for json/jsonb.
Commitbda76c1 caused both plus andminus infinity to be rendered as "infinity", which is not only wrongbut inconsistent with the pre-9.4 behavior of to_json(). Fix that byduplicating the coding in date_out/timestamp_out/timestamptz_out moreclosely. Per bug #13687 from Stepan Perlov. Back-patch to 9.4, likethe previous commit.In passing, also re-pgindent json.c, since it had gotten a bit messed up byrecent patches (and I was already annoyed by indentation-related problemsin back-patching this fix ...)
1 parent984ae04 commitd435542

File tree

10 files changed

+90
-86
lines changed

10 files changed

+90
-86
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-
staticvoidEncodeSpecialDate(DateADTdt,char*str);
4443
staticinttime2tm(TimeADTtime,structpg_tm*tm,fsec_t*fsec);
4544
staticinttimetz2tm(TimeTzADT*time,structpg_tm*tm,fsec_t*fsec,int*tzp);
4645
staticinttm2time(structpg_tm*tm,fsec_tfsec,TimeADT*result);
@@ -273,7 +272,7 @@ make_date(PG_FUNCTION_ARGS)
273272
/*
274273
* Convert reserved date values to string.
275274
*/
276-
staticvoid
275+
void
277276
EncodeSpecialDate(DateADTdt,char*str)
278277
{
279278
if (DATE_IS_NOBEGIN(dt))

‎src/backend/utils/adt/json.c

Lines changed: 28 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,6 @@
3232
#include"utils/typcache.h"
3333
#include"utils/syscache.h"
3434

35-
/* String to output for infinite dates and timestamps */
36-
#defineDT_INFINITY "\"infinity\""
37-
3835
/*
3936
* The context of the parser is maintained by the recursive descent
4037
* mechanism, but is passed explicitly to the error reporting routine
@@ -70,11 +67,11 @@ typedef enum/* type categories for datum_to_json */
7067

7168
typedefstructJsonAggState
7269
{
73-
StringInfostr;
74-
JsonTypeCategorykey_category;
75-
Oidkey_output_func;
76-
JsonTypeCategoryval_category;
77-
Oidval_output_func;
70+
StringInfostr;
71+
JsonTypeCategorykey_category;
72+
Oidkey_output_func;
73+
JsonTypeCategoryval_category;
74+
Oidval_output_func;
7875
}JsonAggState;
7976

8077
staticinlinevoidjson_lex(JsonLexContext*lex);
@@ -360,16 +357,16 @@ pg_parse_json(JsonLexContext *lex, JsonSemAction *sem)
360357
int
361358
json_count_array_elements(JsonLexContext*lex)
362359
{
363-
JsonLexContextcopylex;
364-
intcount;
360+
JsonLexContextcopylex;
361+
intcount;
365362

366363
/*
367364
* It's safe to do this with a shallow copy because the lexical routines
368-
* don't scribble on the input. They do scribble on the other pointers etc,
369-
* so doing this with a copy makes that safe.
365+
* don't scribble on the input. They do scribble on the other pointers
366+
*etc,so doing this with a copy makes that safe.
370367
*/
371368
memcpy(&copylex,lex,sizeof(JsonLexContext));
372-
copylex.strval=NULL;/* not interested in values here */
369+
copylex.strval=NULL;/* not interested in values here */
373370
copylex.lex_level++;
374371

375372
count=0;
@@ -1492,19 +1489,16 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
14921489
charbuf[MAXDATELEN+1];
14931490

14941491
date=DatumGetDateADT(val);
1495-
1492+
/* Same as date_out(), but forcing DateStyle */
14961493
if (DATE_NOT_FINITE(date))
1497-
{
1498-
/* we have to format infinity ourselves */
1499-
appendStringInfoString(result,DT_INFINITY);
1500-
}
1494+
EncodeSpecialDate(date,buf);
15011495
else
15021496
{
15031497
j2date(date+POSTGRES_EPOCH_JDATE,
15041498
&(tm.tm_year),&(tm.tm_mon),&(tm.tm_mday));
15051499
EncodeDateOnly(&tm,USE_XSD_DATES,buf);
1506-
appendStringInfo(result,"\"%s\"",buf);
15071500
}
1501+
appendStringInfo(result,"\"%s\"",buf);
15081502
}
15091503
break;
15101504
caseJSONTYPE_TIMESTAMP:
@@ -1515,21 +1509,16 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
15151509
charbuf[MAXDATELEN+1];
15161510

15171511
timestamp=DatumGetTimestamp(val);
1518-
1512+
/* Same as timestamp_out(), but forcing DateStyle */
15191513
if (TIMESTAMP_NOT_FINITE(timestamp))
1520-
{
1521-
/* we have to format infinity ourselves */
1522-
appendStringInfoString(result,DT_INFINITY);
1523-
}
1514+
EncodeSpecialTimestamp(timestamp,buf);
15241515
elseif (timestamp2tm(timestamp,NULL,&tm,&fsec,NULL,NULL)==0)
1525-
{
15261516
EncodeDateTime(&tm,fsec, false,0,NULL,USE_XSD_DATES,buf);
1527-
appendStringInfo(result,"\"%s\"",buf);
1528-
}
15291517
else
15301518
ereport(ERROR,
15311519
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
15321520
errmsg("timestamp out of range")));
1521+
appendStringInfo(result,"\"%s\"",buf);
15331522
}
15341523
break;
15351524
caseJSONTYPE_TIMESTAMPTZ:
@@ -1541,22 +1530,17 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
15411530
constchar*tzn=NULL;
15421531
charbuf[MAXDATELEN+1];
15431532

1544-
timestamp=DatumGetTimestamp(val);
1545-
1533+
timestamp=DatumGetTimestampTz(val);
1534+
/* Same as timestamptz_out(), but forcing DateStyle */
15461535
if (TIMESTAMP_NOT_FINITE(timestamp))
1547-
{
1548-
/* we have to format infinity ourselves */
1549-
appendStringInfoString(result,DT_INFINITY);
1550-
}
1536+
EncodeSpecialTimestamp(timestamp,buf);
15511537
elseif (timestamp2tm(timestamp,&tz,&tm,&fsec,&tzn,NULL)==0)
1552-
{
15531538
EncodeDateTime(&tm,fsec, true,tz,tzn,USE_XSD_DATES,buf);
1554-
appendStringInfo(result,"\"%s\"",buf);
1555-
}
15561539
else
15571540
ereport(ERROR,
15581541
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
15591542
errmsg("timestamp out of range")));
1543+
appendStringInfo(result,"\"%s\"",buf);
15601544
}
15611545
break;
15621546
caseJSONTYPE_JSON:
@@ -1875,7 +1859,7 @@ json_agg_transfn(PG_FUNCTION_ARGS)
18751859
{
18761860
MemoryContextaggcontext,
18771861
oldcontext;
1878-
JsonAggState*state;
1862+
JsonAggState*state;
18791863
Datumval;
18801864

18811865
if (!AggCheckCallContext(fcinfo,&aggcontext))
@@ -1886,7 +1870,7 @@ json_agg_transfn(PG_FUNCTION_ARGS)
18861870

18871871
if (PG_ARGISNULL(0))
18881872
{
1889-
Oidarg_type=get_fn_expr_argtype(fcinfo->flinfo,1);
1873+
Oidarg_type=get_fn_expr_argtype(fcinfo->flinfo,1);
18901874

18911875
if (arg_type==InvalidOid)
18921876
ereport(ERROR,
@@ -1905,7 +1889,7 @@ json_agg_transfn(PG_FUNCTION_ARGS)
19051889
MemoryContextSwitchTo(oldcontext);
19061890

19071891
appendStringInfoChar(state->str,'[');
1908-
json_categorize_type(arg_type,&state->val_category,
1892+
json_categorize_type(arg_type,&state->val_category,
19091893
&state->val_output_func);
19101894
}
19111895
else
@@ -1949,7 +1933,7 @@ json_agg_transfn(PG_FUNCTION_ARGS)
19491933
Datum
19501934
json_agg_finalfn(PG_FUNCTION_ARGS)
19511935
{
1952-
JsonAggState*state;
1936+
JsonAggState*state;
19531937

19541938
/* cannot be called directly because of internal-type argument */
19551939
Assert(AggCheckCallContext(fcinfo,NULL));
@@ -1976,7 +1960,7 @@ json_object_agg_transfn(PG_FUNCTION_ARGS)
19761960
{
19771961
MemoryContextaggcontext,
19781962
oldcontext;
1979-
JsonAggState*state;
1963+
JsonAggState*state;
19801964
Datumarg;
19811965

19821966
if (!AggCheckCallContext(fcinfo,&aggcontext))
@@ -2007,7 +1991,7 @@ json_object_agg_transfn(PG_FUNCTION_ARGS)
20071991
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
20081992
errmsg("could not determine data type for argument 1")));
20091993

2010-
json_categorize_type(arg_type,&state->key_category,
1994+
json_categorize_type(arg_type,&state->key_category,
20111995
&state->key_output_func);
20121996

20131997
arg_type=get_fn_expr_argtype(fcinfo->flinfo,2);
@@ -2017,7 +2001,7 @@ json_object_agg_transfn(PG_FUNCTION_ARGS)
20172001
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
20182002
errmsg("could not determine data type for argument 2")));
20192003

2020-
json_categorize_type(arg_type,&state->val_category,
2004+
json_categorize_type(arg_type,&state->val_category,
20212005
&state->val_output_func);
20222006

20232007
appendStringInfoString(state->str,"{ ");
@@ -2065,7 +2049,7 @@ json_object_agg_transfn(PG_FUNCTION_ARGS)
20652049
Datum
20662050
json_object_agg_finalfn(PG_FUNCTION_ARGS)
20672051
{
2068-
JsonAggState*state;
2052+
JsonAggState*state;
20692053

20702054
/* cannot be called directly because of internal-type argument */
20712055
Assert(AggCheckCallContext(fcinfo,NULL));

‎src/backend/utils/adt/jsonb.c

Lines changed: 16 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,6 @@
2828
#include"utils/syscache.h"
2929
#include"utils/typcache.h"
3030

31-
/*
32-
* String to output for infinite dates and timestamps.
33-
* Note the we don't use embedded quotes, unlike for json, because
34-
* we store jsonb strings dequoted.
35-
*/
36-
37-
#defineDT_INFINITY "infinity"
38-
3931
typedefstructJsonbInState
4032
{
4133
JsonbParseState*parseState;
@@ -798,21 +790,18 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
798790
charbuf[MAXDATELEN+1];
799791

800792
date=DatumGetDateADT(val);
801-
jb.type=jbvString;
802-
793+
/* Same as date_out(), but forcing DateStyle */
803794
if (DATE_NOT_FINITE(date))
804-
{
805-
jb.val.string.len=strlen(DT_INFINITY);
806-
jb.val.string.val=pstrdup(DT_INFINITY);
807-
}
795+
EncodeSpecialDate(date,buf);
808796
else
809797
{
810798
j2date(date+POSTGRES_EPOCH_JDATE,
811799
&(tm.tm_year),&(tm.tm_mon),&(tm.tm_mday));
812800
EncodeDateOnly(&tm,USE_XSD_DATES,buf);
813-
jb.val.string.len=strlen(buf);
814-
jb.val.string.val=pstrdup(buf);
815801
}
802+
jb.type=jbvString;
803+
jb.val.string.len=strlen(buf);
804+
jb.val.string.val=pstrdup(buf);
816805
}
817806
break;
818807
caseJSONBTYPE_TIMESTAMP:
@@ -823,24 +812,18 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
823812
charbuf[MAXDATELEN+1];
824813

825814
timestamp=DatumGetTimestamp(val);
826-
jb.type=jbvString;
827-
815+
/* Same as timestamp_out(), but forcing DateStyle */
828816
if (TIMESTAMP_NOT_FINITE(timestamp))
829-
{
830-
jb.val.string.len=strlen(DT_INFINITY);
831-
jb.val.string.val=pstrdup(DT_INFINITY);
832-
}
817+
EncodeSpecialTimestamp(timestamp,buf);
833818
elseif (timestamp2tm(timestamp,NULL,&tm,&fsec,NULL,NULL)==0)
834-
{
835-
836819
EncodeDateTime(&tm,fsec, false,0,NULL,USE_XSD_DATES,buf);
837-
jb.val.string.len=strlen(buf);
838-
jb.val.string.val=pstrdup(buf);
839-
}
840820
else
841821
ereport(ERROR,
842822
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
843823
errmsg("timestamp out of range")));
824+
jb.type=jbvString;
825+
jb.val.string.len=strlen(buf);
826+
jb.val.string.val=pstrdup(buf);
844827
}
845828
break;
846829
caseJSONBTYPE_TIMESTAMPTZ:
@@ -852,24 +835,19 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
852835
constchar*tzn=NULL;
853836
charbuf[MAXDATELEN+1];
854837

855-
timestamp=DatumGetTimestamp(val);
856-
jb.type=jbvString;
857-
838+
timestamp=DatumGetTimestampTz(val);
839+
/* Same as timestamptz_out(), but forcing DateStyle */
858840
if (TIMESTAMP_NOT_FINITE(timestamp))
859-
{
860-
jb.val.string.len=strlen(DT_INFINITY);
861-
jb.val.string.val=pstrdup(DT_INFINITY);
862-
}
841+
EncodeSpecialTimestamp(timestamp,buf);
863842
elseif (timestamp2tm(timestamp,&tz,&tm,&fsec,&tzn,NULL)==0)
864-
{
865843
EncodeDateTime(&tm,fsec, true,tz,tzn,USE_XSD_DATES,buf);
866-
jb.val.string.len=strlen(buf);
867-
jb.val.string.val=pstrdup(buf);
868-
}
869844
else
870845
ereport(ERROR,
871846
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
872847
errmsg("timestamp out of range")));
848+
jb.type=jbvString;
849+
jb.val.string.len=strlen(buf);
850+
jb.val.string.val=pstrdup(buf);
873851
}
874852
break;
875853
caseJSONBTYPE_JSONCAST:

‎src/backend/utils/adt/timestamp.c

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

6969

7070
staticTimeOffsettime2t(constinthour,constintmin,constintsec,constfsec_tfsec);
71-
staticvoidEncodeSpecialTimestamp(Timestampdt,char*str);
7271
staticTimestampdt2local(Timestampdt,inttimezone);
7372
staticvoidAdjustTimestampForTypmod(Timestamp*time,int32typmod);
7473
staticvoidAdjustIntervalForTypmod(Interval*interval,int32typmod);
@@ -1500,7 +1499,7 @@ make_interval(PG_FUNCTION_ARGS)
15001499
/* EncodeSpecialTimestamp()
15011500
* Convert reserved timestamp data type to string.
15021501
*/
1503-
staticvoid
1502+
void
15041503
EncodeSpecialTimestamp(Timestampdt,char*str)
15051504
{
15061505
if (TIMESTAMP_IS_NOBEGIN(dt))

‎src/include/utils/date.h

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

9191
/* date.c */
9292
externdoubledate2timestamp_no_overflow(DateADTdateVal);
93+
externvoidEncodeSpecialDate(DateADTdt,char*str);
9394

9495
externDatumdate_in(PG_FUNCTION_ARGS);
9596
externDatumdate_out(PG_FUNCTION_ARGS);

‎src/include/utils/datetime.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ extern void EncodeDateOnly(struct pg_tm * tm, int style, char *str);
326326
externvoidEncodeTimeOnly(structpg_tm*tm,fsec_tfsec,boolprint_tz,inttz,intstyle,char*str);
327327
externvoidEncodeDateTime(structpg_tm*tm,fsec_tfsec,boolprint_tz,inttz,constchar*tzn,intstyle,char*str);
328328
externvoidEncodeInterval(structpg_tm*tm,fsec_tfsec,intstyle,char*str);
329+
externvoidEncodeSpecialTimestamp(Timestampdt,char*str);
329330

330331
externintValidateDate(intfmask,boolisjulian,boolis2digits,boolbc,
331332
structpg_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,

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp