Commit 69036aaf authored by Tom Lane's avatar Tom Lane

Simplify jsonfuncs.c code by using strtoint() not strtol().

Explicitly testing for INT_MIN and INT_MAX isn't particularly good
style; it's tedious and may draw useless compiler warnings on
machines where int and long are the same width.  We invented
strtoint() precisely for this usage, so use that instead.

While here, remove gratuitous variations in the way the tests for
did-strtoint-succeed were spelled.  Also, avoid attempting to
negate INT_MIN; that would probably work given that the result
is implicitly cast to uint32, but I think it's nominally undefined
behavior.

Per gripe from Ranier Vilela, though this isn't his proposed patch.

Discussion: https://postgr.es/m/CAEudQAqge3QfzoBRhe59QrB_5g+NmQUj2QpzqZ9Nc7QepXGAEw@mail.gmail.com
parent d4c74651
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "access/htup_details.h" #include "access/htup_details.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "common/jsonapi.h" #include "common/jsonapi.h"
#include "common/string.h"
#include "fmgr.h" #include "fmgr.h"
#include "funcapi.h" #include "funcapi.h"
#include "lib/stringinfo.h" #include "lib/stringinfo.h"
...@@ -1026,15 +1027,15 @@ get_path_all(FunctionCallInfo fcinfo, bool as_text) ...@@ -1026,15 +1027,15 @@ get_path_all(FunctionCallInfo fcinfo, bool as_text)
*/ */
if (*tpath[i] != '\0') if (*tpath[i] != '\0')
{ {
long ind; int ind;
char *endptr; char *endptr;
errno = 0; errno = 0;
ind = strtol(tpath[i], &endptr, 10); ind = strtoint(tpath[i], &endptr, 10);
if (*endptr == '\0' && errno == 0 && ind <= INT_MAX && ind >= INT_MIN) if (endptr == tpath[i] || *endptr != '\0' || errno != 0)
ipath[i] = (int) ind;
else
ipath[i] = INT_MIN; ipath[i] = INT_MIN;
else
ipath[i] = ind;
} }
else else
ipath[i] = INT_MIN; ipath[i] = INT_MIN;
...@@ -1533,15 +1534,14 @@ jsonb_get_element(Jsonb *jb, Datum *path, int npath, bool *isnull, bool as_text) ...@@ -1533,15 +1534,14 @@ jsonb_get_element(Jsonb *jb, Datum *path, int npath, bool *isnull, bool as_text)
} }
else if (have_array) else if (have_array)
{ {
long lindex; int lindex;
uint32 index; uint32 index;
char *indextext = TextDatumGetCString(path[i]); char *indextext = TextDatumGetCString(path[i]);
char *endptr; char *endptr;
errno = 0; errno = 0;
lindex = strtol(indextext, &endptr, 10); lindex = strtoint(indextext, &endptr, 10);
if (endptr == indextext || *endptr != '\0' || errno != 0 || if (endptr == indextext || *endptr != '\0' || errno != 0)
lindex > INT_MAX || lindex < INT_MIN)
{ {
*isnull = true; *isnull = true;
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
...@@ -1562,7 +1562,7 @@ jsonb_get_element(Jsonb *jb, Datum *path, int npath, bool *isnull, bool as_text) ...@@ -1562,7 +1562,7 @@ jsonb_get_element(Jsonb *jb, Datum *path, int npath, bool *isnull, bool as_text)
nelements = JsonContainerSize(container); nelements = JsonContainerSize(container);
if (-lindex > nelements) if (lindex == INT_MIN || -lindex > nelements)
{ {
*isnull = true; *isnull = true;
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
...@@ -1675,7 +1675,6 @@ push_path(JsonbParseState **st, int level, Datum *path_elems, ...@@ -1675,7 +1675,6 @@ push_path(JsonbParseState **st, int level, Datum *path_elems,
* end, the access index must be normalized by level. * end, the access index must be normalized by level.
*/ */
enum jbvType *tpath = palloc0((path_len - level) * sizeof(enum jbvType)); enum jbvType *tpath = palloc0((path_len - level) * sizeof(enum jbvType));
long lindex;
JsonbValue newkey; JsonbValue newkey;
/* /*
...@@ -1687,6 +1686,7 @@ push_path(JsonbParseState **st, int level, Datum *path_elems, ...@@ -1687,6 +1686,7 @@ push_path(JsonbParseState **st, int level, Datum *path_elems,
{ {
char *c, char *c,
*badp; *badp;
int lindex;
if (path_nulls[i]) if (path_nulls[i])
break; break;
...@@ -1697,9 +1697,8 @@ push_path(JsonbParseState **st, int level, Datum *path_elems, ...@@ -1697,9 +1697,8 @@ push_path(JsonbParseState **st, int level, Datum *path_elems,
*/ */
c = TextDatumGetCString(path_elems[i]); c = TextDatumGetCString(path_elems[i]);
errno = 0; errno = 0;
lindex = strtol(c, &badp, 10); lindex = strtoint(c, &badp, 10);
if (errno != 0 || badp == c || *badp != '\0' || lindex > INT_MAX || if (badp == c || *badp != '\0' || errno != 0)
lindex < INT_MIN)
{ {
/* text, an object is expected */ /* text, an object is expected */
newkey.type = jbvString; newkey.type = jbvString;
...@@ -1720,7 +1719,6 @@ push_path(JsonbParseState **st, int level, Datum *path_elems, ...@@ -1720,7 +1719,6 @@ push_path(JsonbParseState **st, int level, Datum *path_elems,
tpath[i - level] = jbvArray; tpath[i - level] = jbvArray;
} }
} }
/* Insert an actual value for either an object or array */ /* Insert an actual value for either an object or array */
...@@ -5138,18 +5136,15 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls, ...@@ -5138,18 +5136,15 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
if (level < path_len && !path_nulls[level]) if (level < path_len && !path_nulls[level])
{ {
char *c = TextDatumGetCString(path_elems[level]); char *c = TextDatumGetCString(path_elems[level]);
long lindex;
char *badp; char *badp;
errno = 0; errno = 0;
lindex = strtol(c, &badp, 10); idx = strtoint(c, &badp, 10);
if (errno != 0 || badp == c || *badp != '\0' || lindex > INT_MAX || if (badp == c || *badp != '\0' || errno != 0)
lindex < INT_MIN)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("path element at position %d is not an integer: \"%s\"", errmsg("path element at position %d is not an integer: \"%s\"",
level + 1, c))); level + 1, c)));
idx = lindex;
} }
else else
idx = nelems; idx = nelems;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment