Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 8cba26d

Browse files
author
Nikita Glukhov
committed
Fix jsonpath timestamptz encoding
1 parent 485bc16 commit 8cba26d

File tree

12 files changed

+215
-121
lines changed

12 files changed

+215
-121
lines changed

src/backend/utils/adt/formatting.c

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3960,8 +3960,8 @@ to_date(PG_FUNCTION_ARGS)
39603960
* presence of date/time/zone components in the format string.
39613961
*/
39623962
Datum
3963-
to_datetime(text *date_txt, const char *fmt, int fmt_len, bool strict,
3964-
Oid *typid, int32 *typmod)
3963+
to_datetime(text *date_txt, const char *fmt, int fmt_len, char *tzname,
3964+
bool strict, Oid *typid, int32 *typmod, int *tz)
39653965
{
39663966
struct pg_tm tm;
39673967
fsec_t fsec;
@@ -3971,6 +3971,7 @@ to_datetime(text *date_txt, const char *fmt, int fmt_len, bool strict,
39713971
do_to_timestamp(date_txt, fmt, fmt_len, strict, &tm, &fsec, &fprec, &flags);
39723972

39733973
*typmod = fprec ? fprec : -1; /* fractional part precision */
3974+
*tz = 0;
39743975

39753976
if (flags & DCH_DATED)
39763977
{
@@ -3979,20 +3980,27 @@ to_datetime(text *date_txt, const char *fmt, int fmt_len, bool strict,
39793980
if (flags & DCH_ZONED)
39803981
{
39813982
TimestampTz result;
3982-
int tz;
39833983

39843984
if (tm.tm_zone)
3985+
tzname = (char *) tm.tm_zone;
3986+
3987+
if (tzname)
39853988
{
3986-
int dterr = DecodeTimezone((char *) tm.tm_zone, &tz);
3989+
int dterr = DecodeTimezone(tzname, tz);
39873990

39883991
if (dterr)
3989-
DateTimeParseError(dterr, text_to_cstring(date_txt),
3990-
"timestamptz");
3992+
DateTimeParseError(dterr, tzname, "timestamptz");
39913993
}
39923994
else
3993-
tz = DetermineTimeZoneOffset(&tm, session_timezone);
3995+
{
3996+
ereport(ERROR,
3997+
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3998+
errmsg("missing time-zone in timestamptz input string")));
39943999

3995-
if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
4000+
*tz = DetermineTimeZoneOffset(&tm, session_timezone);
4001+
}
4002+
4003+
if (tm2timestamp(&tm, fsec, tz, &result) != 0)
39964004
ereport(ERROR,
39974005
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
39984006
errmsg("timestamptz out of range")));
@@ -4056,20 +4064,27 @@ to_datetime(text *date_txt, const char *fmt, int fmt_len, bool strict,
40564064
if (flags & DCH_ZONED)
40574065
{
40584066
TimeTzADT *result = palloc(sizeof(TimeTzADT));
4059-
int tz;
40604067

40614068
if (tm.tm_zone)
4069+
tzname = (char *) tm.tm_zone;
4070+
4071+
if (tzname)
40624072
{
4063-
int dterr = DecodeTimezone((char *) tm.tm_zone, &tz);
4073+
int dterr = DecodeTimezone(tzname, tz);
40644074

40654075
if (dterr)
4066-
DateTimeParseError(dterr, text_to_cstring(date_txt),
4067-
"timetz");
4076+
DateTimeParseError(dterr, tzname, "timetz");
40684077
}
40694078
else
4070-
tz = DetermineTimeZoneOffset(&tm, session_timezone);
4079+
{
4080+
ereport(ERROR,
4081+
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4082+
errmsg("missing time-zone in timestamptz input string")));
4083+
4084+
*tz = DetermineTimeZoneOffset(&tm, session_timezone);
4085+
}
40714086

4072-
if (tm2timetz(&tm, fsec, tz, result) != 0)
4087+
if (tm2timetz(&tm, fsec, *tz, result) != 0)
40734088
ereport(ERROR,
40744089
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
40754090
errmsg("timetz out of range")));

src/backend/utils/adt/json.c

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,23 +1506,23 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
15061506
{
15071507
char buf[MAXDATELEN + 1];
15081508

1509-
JsonEncodeDateTime(buf, val, DATEOID);
1509+
JsonEncodeDateTime(buf, val, DATEOID, NULL);
15101510
appendStringInfo(result, "\"%s\"", buf);
15111511
}
15121512
break;
15131513
case JSONTYPE_TIMESTAMP:
15141514
{
15151515
char buf[MAXDATELEN + 1];
15161516

1517-
JsonEncodeDateTime(buf, val, TIMESTAMPOID);
1517+
JsonEncodeDateTime(buf, val, TIMESTAMPOID, NULL);
15181518
appendStringInfo(result, "\"%s\"", buf);
15191519
}
15201520
break;
15211521
case JSONTYPE_TIMESTAMPTZ:
15221522
{
15231523
char buf[MAXDATELEN + 1];
15241524

1525-
JsonEncodeDateTime(buf, val, TIMESTAMPTZOID);
1525+
JsonEncodeDateTime(buf, val, TIMESTAMPTZOID, NULL);
15261526
appendStringInfo(result, "\"%s\"", buf);
15271527
}
15281528
break;
@@ -1553,7 +1553,7 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
15531553
* optionally preallocated buffer 'buf'.
15541554
*/
15551555
char *
1556-
JsonEncodeDateTime(char *buf, Datum value, Oid typid)
1556+
JsonEncodeDateTime(char *buf, Datum value, Oid typid, int *tzp)
15571557
{
15581558
if (!buf)
15591559
buf = palloc(MAXDATELEN + 1);
@@ -1630,11 +1630,30 @@ JsonEncodeDateTime(char *buf, Datum value, Oid typid)
16301630
const char *tzn = NULL;
16311631

16321632
timestamp = DatumGetTimestampTz(value);
1633+
1634+
/*
1635+
* If time-zone is specified, we apply a time-zone shift,
1636+
* convert timestamptz to pg_tm as if it was without time-zone,
1637+
* and then use specified time-zone for encoding timestamp
1638+
* into a string.
1639+
*/
1640+
if (tzp)
1641+
{
1642+
tz = *tzp;
1643+
timestamp -= (TimestampTz) tz * USECS_PER_SEC;
1644+
}
1645+
16331646
/* Same as timestamptz_out(), but forcing DateStyle */
16341647
if (TIMESTAMP_NOT_FINITE(timestamp))
16351648
EncodeSpecialTimestamp(timestamp, buf);
1636-
else if (timestamp2tm(timestamp, &tz, &tm, &fsec, &tzn, NULL) == 0)
1649+
else if (timestamp2tm(timestamp, tzp ? NULL : &tz, &tm, &fsec,
1650+
tzp ? NULL : &tzn, NULL) == 0)
1651+
{
1652+
if (tzp)
1653+
tm.tm_isdst = 1; /* set time-zone presence flag */
1654+
16371655
EncodeDateTime(&tm, fsec, true, tz, tzn, USE_XSD_DATES, buf);
1656+
}
16381657
else
16391658
ereport(ERROR,
16401659
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),

src/backend/utils/adt/jsonb.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -794,17 +794,17 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
794794
break;
795795
case JSONBTYPE_DATE:
796796
jb.type = jbvString;
797-
jb.val.string.val = JsonEncodeDateTime(NULL, val, DATEOID);
797+
jb.val.string.val = JsonEncodeDateTime(NULL, val, DATEOID, NULL);
798798
jb.val.string.len = strlen(jb.val.string.val);
799799
break;
800800
case JSONBTYPE_TIMESTAMP:
801801
jb.type = jbvString;
802-
jb.val.string.val = JsonEncodeDateTime(NULL, val, TIMESTAMPOID);
802+
jb.val.string.val = JsonEncodeDateTime(NULL, val, TIMESTAMPOID, NULL);
803803
jb.val.string.len = strlen(jb.val.string.val);
804804
break;
805805
case JSONBTYPE_TIMESTAMPTZ:
806806
jb.type = jbvString;
807-
jb.val.string.val = JsonEncodeDateTime(NULL, val, TIMESTAMPTZOID);
807+
jb.val.string.val = JsonEncodeDateTime(NULL, val, TIMESTAMPTZOID, NULL);
808808
jb.val.string.len = strlen(jb.val.string.val);
809809
break;
810810
case JSONBTYPE_JSONCAST:

src/backend/utils/adt/jsonb_util.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1752,7 +1752,8 @@ convertJsonbScalar(StringInfo buffer, JEntry *jentry, JsonbValue *scalarVal)
17521752

17531753
JsonEncodeDateTime(buf,
17541754
scalarVal->val.datetime.value,
1755-
scalarVal->val.datetime.typid);
1755+
scalarVal->val.datetime.typid,
1756+
&scalarVal->val.datetime.tz);
17561757
len = strlen(buf);
17571758
appendToBuffer(buffer, buf, len);
17581759

src/backend/utils/adt/jsonpath.c

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
7878
case jpiDiv:
7979
case jpiMod:
8080
case jpiStartsWith:
81+
case jpiDatetime:
8182
{
8283
int32 left, right;
8384

@@ -91,13 +92,16 @@ flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
9192
right = buf->len;
9293
appendBinaryStringInfo(buf, (char*)&right /* fake value */, sizeof(right));
9394

94-
chld = flattenJsonPathParseItem(buf, item->value.args.left,
95-
allowCurrent,
96-
insideArraySubscript);
95+
chld = !item->value.args.left ? 0 :
96+
flattenJsonPathParseItem(buf, item->value.args.left,
97+
allowCurrent,
98+
insideArraySubscript);
9799
*(int32*)(buf->data + left) = chld;
98-
chld = flattenJsonPathParseItem(buf, item->value.args.right,
99-
allowCurrent,
100-
insideArraySubscript);
100+
101+
chld = !item->value.args.right ? 0 :
102+
flattenJsonPathParseItem(buf, item->value.args.right,
103+
allowCurrent,
104+
insideArraySubscript);
101105
*(int32*)(buf->data + right) = chld;
102106
}
103107
break;
@@ -124,15 +128,6 @@ flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
124128
*(int32 *)(buf->data + offs) = chld;
125129
}
126130
break;
127-
case jpiDatetime:
128-
if (!item->value.arg)
129-
{
130-
int32 arg = 0;
131-
132-
appendBinaryStringInfo(buf, (char *) &arg, sizeof(arg));
133-
break;
134-
}
135-
/* fall through */
136131
case jpiFilter:
137132
case jpiIsUnknown:
138133
case jpiNot:
@@ -545,10 +540,17 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey, bool printBracket
545540
break;
546541
case jpiDatetime:
547542
appendBinaryStringInfo(buf, ".datetime(", 10);
548-
if (v->content.arg)
543+
if (v->content.args.left)
549544
{
550-
jspGetArg(v, &elem);
545+
jspGetLeftArg(v, &elem);
551546
printJsonPathItem(buf, &elem, false, false);
547+
548+
if (v->content.args.right)
549+
{
550+
appendBinaryStringInfo(buf, ", ", 2);
551+
jspGetRightArg(v, &elem);
552+
printJsonPathItem(buf, &elem, false, false);
553+
}
552554
}
553555
appendStringInfoChar(buf, ')');
554556
break;
@@ -672,6 +674,7 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
672674
case jpiLessOrEqual:
673675
case jpiGreaterOrEqual:
674676
case jpiStartsWith:
677+
case jpiDatetime:
675678
read_int32(v->content.args.left, base, pos);
676679
read_int32(v->content.args.right, base, pos);
677680
break;
@@ -687,7 +690,6 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
687690
case jpiPlus:
688691
case jpiMinus:
689692
case jpiFilter:
690-
case jpiDatetime:
691693
read_int32(v->content.arg, base, pos);
692694
break;
693695
case jpiIndexArray:
@@ -713,8 +715,7 @@ jspGetArg(JsonPathItem *v, JsonPathItem *a)
713715
v->type == jpiIsUnknown ||
714716
v->type == jpiExists ||
715717
v->type == jpiPlus ||
716-
v->type == jpiMinus ||
717-
v->type == jpiDatetime
718+
v->type == jpiMinus
718719
);
719720

720721
jspInitByBuffer(a, v->base, v->content.arg);
@@ -794,6 +795,7 @@ jspGetLeftArg(JsonPathItem *v, JsonPathItem *a)
794795
v->type == jpiMul ||
795796
v->type == jpiDiv ||
796797
v->type == jpiMod ||
798+
v->type == jpiDatetime ||
797799
v->type == jpiStartsWith
798800
);
799801

@@ -817,6 +819,7 @@ jspGetRightArg(JsonPathItem *v, JsonPathItem *a)
817819
v->type == jpiMul ||
818820
v->type == jpiDiv ||
819821
v->type == jpiMod ||
822+
v->type == jpiDatetime ||
820823
v->type == jpiStartsWith
821824
);
822825

0 commit comments

Comments
 (0)