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

Commit c755a7f

Browse files
author
Nikita Glukhov
committed
Fix jsonpath timestamptz encoding
1 parent d7ad180 commit c755a7f

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
@@ -3748,8 +3748,8 @@ to_date(PG_FUNCTION_ARGS)
37483748
* presence of date/time/zone components in the format string.
37493749
*/
37503750
Datum
3751-
to_datetime(text *date_txt, const char *fmt, int fmt_len, bool strict,
3752-
Oid *typid, int32 *typmod)
3751+
to_datetime(text *date_txt, const char *fmt, int fmt_len, char *tzname,
3752+
bool strict, Oid *typid, int32 *typmod, int *tz)
37533753
{
37543754
struct pg_tm tm;
37553755
fsec_t fsec;
@@ -3758,6 +3758,7 @@ to_datetime(text *date_txt, const char *fmt, int fmt_len, bool strict,
37583758
do_to_timestamp(date_txt, fmt, fmt_len, strict, &tm, &fsec, &flags);
37593759

37603760
*typmod = -1; /* TODO implement FF1, ..., FF9 */
3761+
*tz = 0;
37613762

37623763
if (flags & DCH_DATED)
37633764
{
@@ -3766,20 +3767,27 @@ to_datetime(text *date_txt, const char *fmt, int fmt_len, bool strict,
37663767
if (flags & DCH_ZONED)
37673768
{
37683769
TimestampTz result;
3769-
int tz;
37703770

37713771
if (tm.tm_zone)
3772+
tzname = (char *) tm.tm_zone;
3773+
3774+
if (tzname)
37723775
{
3773-
int dterr = DecodeTimezone((char *) tm.tm_zone, &tz);
3776+
int dterr = DecodeTimezone(tzname, tz);
37743777

37753778
if (dterr)
3776-
DateTimeParseError(dterr, text_to_cstring(date_txt),
3777-
"timestamptz");
3779+
DateTimeParseError(dterr, tzname, "timestamptz");
37783780
}
37793781
else
3780-
tz = DetermineTimeZoneOffset(&tm, session_timezone);
3782+
{
3783+
ereport(ERROR,
3784+
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3785+
errmsg("missing time-zone in timestamptz input string")));
37813786

3782-
if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
3787+
*tz = DetermineTimeZoneOffset(&tm, session_timezone);
3788+
}
3789+
3790+
if (tm2timestamp(&tm, fsec, tz, &result) != 0)
37833791
ereport(ERROR,
37843792
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
37853793
errmsg("timestamptz out of range")));
@@ -3843,20 +3851,27 @@ to_datetime(text *date_txt, const char *fmt, int fmt_len, bool strict,
38433851
if (flags & DCH_ZONED)
38443852
{
38453853
TimeTzADT *result = palloc(sizeof(TimeTzADT));
3846-
int tz;
38473854

38483855
if (tm.tm_zone)
3856+
tzname = (char *) tm.tm_zone;
3857+
3858+
if (tzname)
38493859
{
3850-
int dterr = DecodeTimezone((char *) tm.tm_zone, &tz);
3860+
int dterr = DecodeTimezone(tzname, tz);
38513861

38523862
if (dterr)
3853-
DateTimeParseError(dterr, text_to_cstring(date_txt),
3854-
"timetz");
3863+
DateTimeParseError(dterr, tzname, "timetz");
38553864
}
38563865
else
3857-
tz = DetermineTimeZoneOffset(&tm, session_timezone);
3866+
{
3867+
ereport(ERROR,
3868+
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3869+
errmsg("missing time-zone in timestamptz input string")));
3870+
3871+
*tz = DetermineTimeZoneOffset(&tm, session_timezone);
3872+
}
38583873

3859-
if (tm2timetz(&tm, fsec, tz, result) != 0)
3874+
if (tm2timetz(&tm, fsec, *tz, result) != 0)
38603875
ereport(ERROR,
38613876
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
38623877
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
@@ -76,6 +76,7 @@ flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
7676
case jpiDiv:
7777
case jpiMod:
7878
case jpiStartsWith:
79+
case jpiDatetime:
7980
{
8081
int32 left, right;
8182

@@ -89,13 +90,16 @@ flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
8990
right = buf->len;
9091
appendBinaryStringInfo(buf, (char*)&right /* fake value */, sizeof(right));
9192

92-
chld = flattenJsonPathParseItem(buf, item->value.args.left,
93-
allowCurrent,
94-
insideArraySubscript);
93+
chld = !item->value.args.left ? 0 :
94+
flattenJsonPathParseItem(buf, item->value.args.left,
95+
allowCurrent,
96+
insideArraySubscript);
9597
*(int32*)(buf->data + left) = chld;
96-
chld = flattenJsonPathParseItem(buf, item->value.args.right,
97-
allowCurrent,
98-
insideArraySubscript);
98+
99+
chld = !item->value.args.right ? 0 :
100+
flattenJsonPathParseItem(buf, item->value.args.right,
101+
allowCurrent,
102+
insideArraySubscript);
99103
*(int32*)(buf->data + right) = chld;
100104
}
101105
break;
@@ -122,15 +126,6 @@ flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
122126
*(int32 *)(buf->data + offs) = chld;
123127
}
124128
break;
125-
case jpiDatetime:
126-
if (!item->value.arg)
127-
{
128-
int32 arg = 0;
129-
130-
appendBinaryStringInfo(buf, (char *) &arg, sizeof(arg));
131-
break;
132-
}
133-
/* fall through */
134129
case jpiFilter:
135130
case jpiIsUnknown:
136131
case jpiNot:
@@ -541,10 +536,17 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey, bool printBracket
541536
break;
542537
case jpiDatetime:
543538
appendBinaryStringInfo(buf, ".datetime(", 10);
544-
if (v->content.arg)
539+
if (v->content.args.left)
545540
{
546-
jspGetArg(v, &elem);
541+
jspGetLeftArg(v, &elem);
547542
printJsonPathItem(buf, &elem, false, false);
543+
544+
if (v->content.args.right)
545+
{
546+
appendBinaryStringInfo(buf, ", ", 2);
547+
jspGetRightArg(v, &elem);
548+
printJsonPathItem(buf, &elem, false, false);
549+
}
548550
}
549551
appendStringInfoChar(buf, ')');
550552
break;
@@ -668,6 +670,7 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
668670
case jpiLessOrEqual:
669671
case jpiGreaterOrEqual:
670672
case jpiStartsWith:
673+
case jpiDatetime:
671674
read_int32(v->content.args.left, base, pos);
672675
read_int32(v->content.args.right, base, pos);
673676
break;
@@ -683,7 +686,6 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
683686
case jpiPlus:
684687
case jpiMinus:
685688
case jpiFilter:
686-
case jpiDatetime:
687689
read_int32(v->content.arg, base, pos);
688690
break;
689691
case jpiIndexArray:
@@ -709,8 +711,7 @@ jspGetArg(JsonPathItem *v, JsonPathItem *a)
709711
v->type == jpiIsUnknown ||
710712
v->type == jpiExists ||
711713
v->type == jpiPlus ||
712-
v->type == jpiMinus ||
713-
v->type == jpiDatetime
714+
v->type == jpiMinus
714715
);
715716

716717
jspInitByBuffer(a, v->base, v->content.arg);
@@ -790,6 +791,7 @@ jspGetLeftArg(JsonPathItem *v, JsonPathItem *a)
790791
v->type == jpiMul ||
791792
v->type == jpiDiv ||
792793
v->type == jpiMod ||
794+
v->type == jpiDatetime ||
793795
v->type == jpiStartsWith
794796
);
795797

@@ -813,6 +815,7 @@ jspGetRightArg(JsonPathItem *v, JsonPathItem *a)
813815
v->type == jpiMul ||
814816
v->type == jpiDiv ||
815817
v->type == jpiMod ||
818+
v->type == jpiDatetime ||
816819
v->type == jpiStartsWith
817820
);
818821

0 commit comments

Comments
 (0)