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

Commit 7c6a989

Browse files
author
Nikita Glukhov
committed
Add jsonpath datetime() extension: UNIX epoch time to timestamptz
1 parent 7c1dd5f commit 7c6a989

File tree

3 files changed

+111
-62
lines changed

3 files changed

+111
-62
lines changed

src/backend/utils/adt/jsonpath_exec.c

Lines changed: 87 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2042,7 +2042,6 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
20422042
{
20432043
JsonbValue jbvbuf;
20442044
Datum value;
2045-
text *datetime;
20462045
Oid typid;
20472046
int32 typmod = -1;
20482047
int tz;
@@ -2053,84 +2052,113 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
20532052

20542053
res = jperMakeError(ERRCODE_INVALID_ARGUMENT_FOR_JSON_DATETIME_FUNCTION);
20552054

2056-
if (jb->type != jbvString)
2057-
break;
2055+
if (jb->type == jbvNumeric && !jsp->content.args.left)
2056+
{
2057+
/* Standard extension: unix epoch to timestamptz */
2058+
MemoryContext mcxt = CurrentMemoryContext;
20582059

2059-
datetime = cstring_to_text_with_len(jb->val.string.val,
2060-
jb->val.string.len);
2060+
PG_TRY();
2061+
{
2062+
Datum unix_epoch =
2063+
DirectFunctionCall1(numeric_float8,
2064+
NumericGetDatum(jb->val.numeric));
2065+
2066+
value = DirectFunctionCall1(float8_timestamptz,
2067+
unix_epoch);
2068+
typid = TIMESTAMPTZOID;
2069+
tz = 0;
2070+
res = jperOk;
2071+
}
2072+
PG_CATCH();
2073+
{
2074+
if (ERRCODE_TO_CATEGORY(geterrcode()) !=
2075+
ERRCODE_DATA_EXCEPTION)
2076+
PG_RE_THROW();
20612077

2062-
if (jsp->content.args.left)
2078+
FlushErrorState();
2079+
MemoryContextSwitchTo(mcxt);
2080+
}
2081+
PG_END_TRY();
2082+
}
2083+
else if (jb->type == jbvString)
20632084
{
2064-
char *template_str;
2065-
int template_len;
2066-
char *tzname = NULL;
2085+
text *datetime =
2086+
cstring_to_text_with_len(jb->val.string.val,
2087+
jb->val.string.len);
20672088

2068-
jspGetLeftArg(jsp, &elem);
2089+
if (jsp->content.args.left)
2090+
{
2091+
char *template_str;
2092+
int template_len;
2093+
char *tzname = NULL;
20692094

2070-
if (elem.type != jpiString)
2071-
elog(ERROR, "invalid jsonpath item type for .datetime() argument");
2095+
jspGetLeftArg(jsp, &elem);
20722096

2073-
template_str = jspGetString(&elem, &template_len);
2097+
if (elem.type != jpiString)
2098+
elog(ERROR, "invalid jsonpath item type for .datetime() argument");
20742099

2075-
if (jsp->content.args.right)
2076-
{
2077-
JsonValueList tzlist = { 0 };
2078-
JsonPathExecResult tzres;
2079-
JsonbValue *tzjbv;
2100+
template_str = jspGetString(&elem, &template_len);
20802101

2081-
jspGetRightArg(jsp, &elem);
2082-
tzres = recursiveExecuteNoUnwrap(cxt, &elem, jb,
2083-
&tzlist);
2102+
if (jsp->content.args.right)
2103+
{
2104+
JsonValueList tzlist = { 0 };
2105+
JsonPathExecResult tzres;
2106+
JsonbValue *tzjbv;
20842107

2085-
if (jperIsError(tzres))
2086-
return tzres;
2108+
jspGetRightArg(jsp, &elem);
2109+
tzres = recursiveExecuteNoUnwrap(cxt, &elem, jb,
2110+
&tzlist);
20872111

2088-
if (JsonValueListLength(&tzlist) != 1)
2089-
break;
2112+
if (jperIsError(tzres))
2113+
return tzres;
20902114

2091-
tzjbv = JsonValueListHead(&tzlist);
2115+
if (JsonValueListLength(&tzlist) != 1)
2116+
break;
20922117

2093-
if (tzjbv->type != jbvString)
2094-
break;
2118+
tzjbv = JsonValueListHead(&tzlist);
20952119

2096-
tzname = pnstrdup(tzjbv->val.string.val,
2097-
tzjbv->val.string.len);
2098-
}
2120+
if (tzjbv->type != jbvString)
2121+
break;
20992122

2100-
if (tryToParseDatetime(template_str, template_len, datetime,
2101-
tzname, false,
2102-
&value, &typid, &typmod, &tz))
2103-
res = jperOk;
2123+
tzname = pnstrdup(tzjbv->val.string.val,
2124+
tzjbv->val.string.len);
2125+
}
21042126

2105-
if (tzname)
2106-
pfree(tzname);
2107-
}
2108-
else
2109-
{
2110-
const char *templates[] = {
2111-
"yyyy-mm-dd HH24:MI:SS TZH:TZM",
2112-
"yyyy-mm-dd HH24:MI:SS TZH",
2113-
"yyyy-mm-dd HH24:MI:SS",
2114-
"yyyy-mm-dd",
2115-
"HH24:MI:SS TZH:TZM",
2116-
"HH24:MI:SS TZH",
2117-
"HH24:MI:SS"
2118-
};
2119-
int i;
2120-
2121-
for (i = 0; i < sizeof(templates) / sizeof(*templates); i++)
2127+
if (tryToParseDatetime(template_str, template_len,
2128+
datetime, tzname, false,
2129+
&value, &typid, &typmod, &tz))
2130+
res = jperOk;
2131+
2132+
if (tzname)
2133+
pfree(tzname);
2134+
}
2135+
else
21222136
{
2123-
if (tryToParseDatetime(templates[i], -1, datetime,
2124-
NULL, true, &value, &typid,
2125-
&typmod, &tz))
2137+
const char *templates[] = {
2138+
"yyyy-mm-dd HH24:MI:SS TZH:TZM",
2139+
"yyyy-mm-dd HH24:MI:SS TZH",
2140+
"yyyy-mm-dd HH24:MI:SS",
2141+
"yyyy-mm-dd",
2142+
"HH24:MI:SS TZH:TZM",
2143+
"HH24:MI:SS TZH",
2144+
"HH24:MI:SS"
2145+
};
2146+
int i;
2147+
2148+
for (i = 0; i < sizeof(templates) / sizeof(*templates); i++)
21262149
{
2127-
res = jperOk;
2128-
break;
2150+
if (tryToParseDatetime(templates[i], -1, datetime,
2151+
NULL, true, &value, &typid,
2152+
&typmod, &tz))
2153+
{
2154+
res = jperOk;
2155+
break;
2156+
}
21292157
}
21302158
}
2131-
}
21322159

2133-
pfree(datetime);
2160+
pfree(datetime);
2161+
}
21342162

21352163
if (jperIsError(res))
21362164
break;

src/test/regress/expected/jsonb_jsonpath.out

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,8 +1179,6 @@ select jsonb 'null' @* '$.datetime()';
11791179
ERROR: Invalid argument for SQL/JSON datetime function
11801180
select jsonb 'true' @* '$.datetime()';
11811181
ERROR: Invalid argument for SQL/JSON datetime function
1182-
select jsonb '1' @* '$.datetime()';
1183-
ERROR: Invalid argument for SQL/JSON datetime function
11841182
select jsonb '[]' @* '$.datetime()';
11851183
?column?
11861184
----------
@@ -1192,6 +1190,25 @@ select jsonb '{}' @* '$.datetime()';
11921190
ERROR: Invalid argument for SQL/JSON datetime function
11931191
select jsonb '""' @* '$.datetime()';
11941192
ERROR: Invalid argument for SQL/JSON datetime function
1193+
-- Standard extension: UNIX epoch to timestamptz
1194+
select jsonb '0' @* '$.datetime()';
1195+
?column?
1196+
-----------------------------
1197+
"1970-01-01T00:00:00+00:00"
1198+
(1 row)
1199+
1200+
select jsonb '0' @* '$.datetime().type()';
1201+
?column?
1202+
----------------------------
1203+
"timestamp with time zone"
1204+
(1 row)
1205+
1206+
select jsonb '1490216035.5' @* '$.datetime()';
1207+
?column?
1208+
-------------------------------
1209+
"2017-03-22T20:53:55.5+00:00"
1210+
(1 row)
1211+
11951212
select jsonb '"10-03-2017"' @* '$.datetime("dd-mm-yyyy")';
11961213
?column?
11971214
--------------

src/test/regress/sql/jsonb_jsonpath.sql

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,12 +240,16 @@ select jsonb '[null, 1, "abc", "abd", "aBdC", "abdacb", "babc"]' @* 'lax $[*] ?
240240

241241
select jsonb 'null' @* '$.datetime()';
242242
select jsonb 'true' @* '$.datetime()';
243-
select jsonb '1' @* '$.datetime()';
244243
select jsonb '[]' @* '$.datetime()';
245244
select jsonb '[]' @* 'strict $.datetime()';
246245
select jsonb '{}' @* '$.datetime()';
247246
select jsonb '""' @* '$.datetime()';
248247

248+
-- Standard extension: UNIX epoch to timestamptz
249+
select jsonb '0' @* '$.datetime()';
250+
select jsonb '0' @* '$.datetime().type()';
251+
select jsonb '1490216035.5' @* '$.datetime()';
252+
249253
select jsonb '"10-03-2017"' @* '$.datetime("dd-mm-yyyy")';
250254
select jsonb '"10-03-2017"' @* '$.datetime("dd-mm-yyyy").type()';
251255
select jsonb '"10-03-2017 12:34"' @* '$.datetime("dd-mm-yyyy")';

0 commit comments

Comments
 (0)