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

Commit eafa131

Browse files
author
Nikita Glukhov
committed
Add jsonpath datetime() extension: UNIX epoch time to timestamptz
1 parent 27c4a39 commit eafa131

File tree

5 files changed

+104
-19
lines changed

5 files changed

+104
-19
lines changed

src/backend/utils/adt/jsonpath_exec.c

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1413,10 +1413,41 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
14131413
return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
14141414
false);
14151415

1416-
if (!(jb = getScalar(jb, jbvString)))
1416+
if (JsonItemIsNumeric(jb))
1417+
{
1418+
bool error = false;
1419+
float8 unix_epoch =
1420+
DatumGetFloat8(DirectFunctionCall1(numeric_float8_no_overflow,
1421+
JsonItemNumericDatum(jb)));
1422+
TimestampTz tstz = float8_timestamptz_internal(unix_epoch,
1423+
&error);
1424+
1425+
if (error)
1426+
RETURN_ERROR(ereport(ERROR,
1427+
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_JSON_DATETIME_FUNCTION),
1428+
errmsg("UNIX epoch is out ouf timestamptz range"))));
1429+
1430+
value = TimestampTzGetDatum(tstz);
1431+
typid = TIMESTAMPTZOID;
1432+
tz = 0;
1433+
res = jperOk;
1434+
1435+
hasNext = jspGetNext(jsp, &elem);
1436+
1437+
if (!hasNext && !found)
1438+
break;
1439+
1440+
jb = hasNext ? &jbvbuf : palloc(sizeof(*jb));
1441+
1442+
JsonItemInitDatetime(jb, value, typid, typmod, tz);
1443+
1444+
res = executeNextItem(cxt, jsp, &elem, jb, found, hasNext);
1445+
break;
1446+
}
1447+
else if (!JsonItemIsString(jb))
14171448
RETURN_ERROR(ereport(ERROR,
14181449
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_JSON_DATETIME_FUNCTION),
1419-
errmsg("jsonpath item method .%s() can only be applied to a string value",
1450+
errmsg("jsonpath item method .%s() can only be applied to a string or number",
14201451
jspOperationName(jsp->type)))));
14211452

14221453
datetime = cstring_to_text_with_len(JsonItemString(jb).val,

src/backend/utils/adt/timestamp.c

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -728,21 +728,25 @@ make_timestamptz_at_timezone(PG_FUNCTION_ARGS)
728728
PG_RETURN_TIMESTAMPTZ(result);
729729
}
730730

731-
/*
732-
* to_timestamp(double precision)
733-
* Convert UNIX epoch to timestamptz.
734-
*/
735-
Datum
736-
float8_timestamptz(PG_FUNCTION_ARGS)
731+
TimestampTz
732+
float8_timestamptz_internal(float8 seconds, bool *error)
737733
{
738-
float8 seconds = PG_GETARG_FLOAT8(0);
734+
float8 saved_seconds = seconds;
739735
TimestampTz result;
740736

741737
/* Deal with NaN and infinite inputs ... */
742738
if (isnan(seconds))
739+
{
740+
if (error)
741+
{
742+
*error = true;
743+
return 0;
744+
}
745+
743746
ereport(ERROR,
744747
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
745748
errmsg("timestamp cannot be NaN")));
749+
}
746750

747751
if (isinf(seconds))
748752
{
@@ -758,9 +762,17 @@ float8_timestamptz(PG_FUNCTION_ARGS)
758762
(float8) SECS_PER_DAY * (DATETIME_MIN_JULIAN - UNIX_EPOCH_JDATE)
759763
|| seconds >=
760764
(float8) SECS_PER_DAY * (TIMESTAMP_END_JULIAN - UNIX_EPOCH_JDATE))
765+
{
766+
if (error)
767+
{
768+
*error = true;
769+
return 0;
770+
}
771+
761772
ereport(ERROR,
762773
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
763774
errmsg("timestamp out of range: \"%g\"", seconds)));
775+
}
764776

765777
/* Convert UNIX epoch to Postgres epoch */
766778
seconds -= ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
@@ -770,13 +782,32 @@ float8_timestamptz(PG_FUNCTION_ARGS)
770782

771783
/* Recheck in case roundoff produces something just out of range */
772784
if (!IS_VALID_TIMESTAMP(result))
785+
{
786+
if (error)
787+
{
788+
*error = true;
789+
return 0;
790+
}
791+
773792
ereport(ERROR,
774793
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
775-
errmsg("timestamp out of range: \"%g\"",
776-
PG_GETARG_FLOAT8(0))));
794+
errmsg("timestamp out of range: \"%g\"", saved_seconds)));
795+
}
777796
}
778797

779-
PG_RETURN_TIMESTAMP(result);
798+
return result;
799+
}
800+
801+
/*
802+
* to_timestamp(double precision)
803+
* Convert UNIX epoch to timestamptz.
804+
*/
805+
Datum
806+
float8_timestamptz(PG_FUNCTION_ARGS)
807+
{
808+
float8 seconds = PG_GETARG_FLOAT8(0);
809+
810+
PG_RETURN_TIMESTAMP(float8_timestamptz_internal(seconds, NULL));
780811
}
781812

782813
/* timestamptz_out()

src/include/utils/timestamp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ extern int timestamp_cmp_internal(Timestamp dt1, Timestamp dt2);
100100
extern TimestampTz timestamp2timestamptz_internal(Timestamp timestamp,
101101
int *tzp, bool *error);
102102

103+
extern TimestampTz float8_timestamptz_internal(float8 seconds, bool *error);
104+
103105
extern int isoweek2j(int year, int week);
104106
extern void isoweek2date(int woy, int *year, int *mon, int *mday);
105107
extern void isoweekdate2date(int isoweek, int wday, int *year, int *mon, int *mday);

src/test/regress/expected/jsonb_jsonpath.out

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1659,20 +1659,18 @@ select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ lik
16591659
(1 row)
16601660

16611661
select jsonb_path_query('null', '$.datetime()');
1662-
ERROR: jsonpath item method .datetime() can only be applied to a string value
1662+
ERROR: jsonpath item method .datetime() can only be applied to a string or number
16631663
select jsonb_path_query('true', '$.datetime()');
1664-
ERROR: jsonpath item method .datetime() can only be applied to a string value
1665-
select jsonb_path_query('1', '$.datetime()');
1666-
ERROR: jsonpath item method .datetime() can only be applied to a string value
1664+
ERROR: jsonpath item method .datetime() can only be applied to a string or number
16671665
select jsonb_path_query('[]', '$.datetime()');
16681666
jsonb_path_query
16691667
------------------
16701668
(0 rows)
16711669

16721670
select jsonb_path_query('[]', 'strict $.datetime()');
1673-
ERROR: jsonpath item method .datetime() can only be applied to a string value
1671+
ERROR: jsonpath item method .datetime() can only be applied to a string or number
16741672
select jsonb_path_query('{}', '$.datetime()');
1675-
ERROR: jsonpath item method .datetime() can only be applied to a string value
1673+
ERROR: jsonpath item method .datetime() can only be applied to a string or number
16761674
select jsonb_path_query('""', '$.datetime()');
16771675
ERROR: unrecognized datetime format
16781676
HINT: use datetime template argument for explicit format specification
@@ -1709,6 +1707,25 @@ ERROR: timezone argument of jsonpath item method .datetime() is out of integer
17091707
select jsonb_path_query('"aaaa"', '$.datetime("HH24")');
17101708
ERROR: invalid value "aa" for "HH24"
17111709
DETAIL: Value must be an integer.
1710+
-- Standard extension: UNIX epoch to timestamptz
1711+
select jsonb_path_query('0', '$.datetime()');
1712+
jsonb_path_query
1713+
-----------------------------
1714+
"1970-01-01T00:00:00+00:00"
1715+
(1 row)
1716+
1717+
select jsonb_path_query('0', '$.datetime().type()');
1718+
jsonb_path_query
1719+
----------------------------
1720+
"timestamp with time zone"
1721+
(1 row)
1722+
1723+
select jsonb_path_query('1490216035.5', '$.datetime()');
1724+
jsonb_path_query
1725+
-------------------------------
1726+
"2017-03-22T20:53:55.5+00:00"
1727+
(1 row)
1728+
17121729
select jsonb '"10-03-2017"' @? '$.datetime("dd-mm-yyyy")';
17131730
?column?
17141731
----------

src/test/regress/sql/jsonb_jsonpath.sql

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,6 @@ select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ lik
348348

349349
select jsonb_path_query('null', '$.datetime()');
350350
select jsonb_path_query('true', '$.datetime()');
351-
select jsonb_path_query('1', '$.datetime()');
352351
select jsonb_path_query('[]', '$.datetime()');
353352
select jsonb_path_query('[]', 'strict $.datetime()');
354353
select jsonb_path_query('{}', '$.datetime()');
@@ -364,6 +363,11 @@ select jsonb_path_query('"12:34"', '$.datetime("HH24:MI TZH", -2147483647)');
364363
select jsonb_path_query('"12:34"', '$.datetime("HH24:MI TZH", -2147483648)');
365364
select jsonb_path_query('"aaaa"', '$.datetime("HH24")');
366365

366+
-- Standard extension: UNIX epoch to timestamptz
367+
select jsonb_path_query('0', '$.datetime()');
368+
select jsonb_path_query('0', '$.datetime().type()');
369+
select jsonb_path_query('1490216035.5', '$.datetime()');
370+
367371
select jsonb '"10-03-2017"' @? '$.datetime("dd-mm-yyyy")';
368372
select jsonb_path_query('"10-03-2017"', '$.datetime("dd-mm-yyyy")');
369373
select jsonb_path_query('"10-03-2017"', '$.datetime("dd-mm-yyyy").type()');

0 commit comments

Comments
 (0)