Commit 16d489b0 authored by Alexander Korotkov's avatar Alexander Korotkov

Numeric error suppression in jsonpath

Add support of numeric error suppression to jsonpath as it's required by
standard.  This commit doesn't use PG_TRY()/PG_CATCH() in order to implement
that.  Instead, it provides internal versions of numeric functions used, which
support error suppression.

Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com
Author: Alexander Korotkov, Nikita Glukhov
Reviewed-by: Tomas Vondra
parent 72b64603
......@@ -12209,7 +12209,7 @@ table2-mapping
<para>
The <literal>@?</literal> and <literal>@@</literal> operators suppress
errors including: lacking object field or array element, unexpected JSON
item type.
item type and numeric errors.
This behavior might be helpful while searching over JSON document
collections of varying structure.
</para>
......
......@@ -336,8 +336,19 @@ float8in(PG_FUNCTION_ARGS)
PG_RETURN_FLOAT8(float8in_internal(num, NULL, "double precision", num));
}
/* Convenience macro: set *have_error flag (if provided) or throw error */
#define RETURN_ERROR(throw_error) \
do { \
if (have_error) { \
*have_error = true; \
return 0.0; \
} else { \
throw_error; \
} \
} while (0)
/*
* float8in_internal - guts of float8in()
* float8in_internal_opt_error - guts of float8in()
*
* This is exposed for use by functions that want a reasonably
* platform-independent way of inputting doubles. The behavior is
......@@ -353,10 +364,14 @@ float8in(PG_FUNCTION_ARGS)
*
* "num" could validly be declared "const char *", but that results in an
* unreasonable amount of extra casting both here and in callers, so we don't.
*
* When "*have_error" flag is provided, it's set instead of throwing an
* error. This is helpful when caller need to handle errors by itself.
*/
double
float8in_internal(char *num, char **endptr_p,
const char *type_name, const char *orig_string)
float8in_internal_opt_error(char *num, char **endptr_p,
const char *type_name, const char *orig_string,
bool *have_error)
{
double val;
char *endptr;
......@@ -370,10 +385,10 @@ float8in_internal(char *num, char **endptr_p,
* strtod() on different platforms.
*/
if (*num == '\0')
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
type_name, orig_string)));
RETURN_ERROR(ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
type_name, orig_string))));
errno = 0;
val = strtod(num, &endptr);
......@@ -446,17 +461,19 @@ float8in_internal(char *num, char **endptr_p,
char *errnumber = pstrdup(num);
errnumber[endptr - num] = '\0';
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("\"%s\" is out of range for type double precision",
errnumber)));
RETURN_ERROR(ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("\"%s\" is out of range for "
"type double precision",
errnumber))));
}
}
else
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
type_name, orig_string)));
RETURN_ERROR(ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type "
"%s: \"%s\"",
type_name, orig_string))));
}
#ifdef HAVE_BUGGY_SOLARIS_STRTOD
else
......@@ -479,14 +496,27 @@ float8in_internal(char *num, char **endptr_p,
if (endptr_p)
*endptr_p = endptr;
else if (*endptr != '\0')
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
type_name, orig_string)));
RETURN_ERROR(ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type "
"%s: \"%s\"",
type_name, orig_string))));
return val;
}
/*
* Interfact to float8in_internal_opt_error() without "have_error" argument.
*/
double
float8in_internal(char *num, char **endptr_p,
const char *type_name, const char *orig_string)
{
return float8in_internal_opt_error(num, endptr_p, type_name,
orig_string, NULL);
}
/*
* float8out - converts float8 number to a string
* using a standard output format
......
......@@ -179,6 +179,7 @@ typedef JsonPathBool (*JsonPathPredicateCallback) (JsonPathItem *jsp,
JsonbValue *larg,
JsonbValue *rarg,
void *param);
typedef Numeric (*BinaryArithmFunc) (Numeric num1, Numeric num2, bool *error);
static JsonPathExecResult executeJsonPath(JsonPath *path, Jsonb *vars,
Jsonb *json, bool throwErrors, JsonValueList *result);
......@@ -212,8 +213,8 @@ static JsonPathBool executePredicate(JsonPathExecContext *cxt,
JsonbValue *jb, bool unwrapRightArg,
JsonPathPredicateCallback exec, void *param);
static JsonPathExecResult executeBinaryArithmExpr(JsonPathExecContext *cxt,
JsonPathItem *jsp, JsonbValue *jb, PGFunction func,
JsonValueList *found);
JsonPathItem *jsp, JsonbValue *jb,
BinaryArithmFunc func, JsonValueList *found);
static JsonPathExecResult executeUnaryArithmExpr(JsonPathExecContext *cxt,
JsonPathItem *jsp, JsonbValue *jb, PGFunction func,
JsonValueList *found);
......@@ -830,23 +831,23 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
case jpiAdd:
return executeBinaryArithmExpr(cxt, jsp, jb,
numeric_add, found);
numeric_add_opt_error, found);
case jpiSub:
return executeBinaryArithmExpr(cxt, jsp, jb,
numeric_sub, found);
numeric_sub_opt_error, found);
case jpiMul:
return executeBinaryArithmExpr(cxt, jsp, jb,
numeric_mul, found);
numeric_mul_opt_error, found);
case jpiDiv:
return executeBinaryArithmExpr(cxt, jsp, jb,
numeric_div, found);
numeric_div_opt_error, found);
case jpiMod:
return executeBinaryArithmExpr(cxt, jsp, jb,
numeric_mod, found);
numeric_mod_opt_error, found);
case jpiPlus:
return executeUnaryArithmExpr(cxt, jsp, jb, NULL, found);
......@@ -999,12 +1000,22 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
{
char *tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
NumericGetDatum(jb->val.numeric)));
bool have_error = false;
(void) float8in_internal(tmp,
NULL,
"double precision",
tmp);
(void) float8in_internal_opt_error(tmp,
NULL,
"double precision",
tmp,
&have_error);
if (have_error)
RETURN_ERROR(ereport(ERROR,
(errcode(ERRCODE_NON_NUMERIC_JSON_ITEM),
errmsg(ERRMSG_NON_NUMERIC_JSON_ITEM),
errdetail("jsonpath item method .%s() "
"can only be applied to "
"a numeric value",
jspOperationName(jsp->type)))));
res = jperOk;
}
else if (jb->type == jbvString)
......@@ -1013,13 +1024,15 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
double val;
char *tmp = pnstrdup(jb->val.string.val,
jb->val.string.len);
bool have_error = false;
val = float8in_internal(tmp,
NULL,
"double precision",
tmp);
val = float8in_internal_opt_error(tmp,
NULL,
"double precision",
tmp,
&have_error);
if (isinf(val))
if (have_error || isinf(val))
RETURN_ERROR(ereport(ERROR,
(errcode(ERRCODE_NON_NUMERIC_JSON_ITEM),
errmsg(ERRMSG_NON_NUMERIC_JSON_ITEM),
......@@ -1497,7 +1510,7 @@ executePredicate(JsonPathExecContext *cxt, JsonPathItem *pred,
*/
static JsonPathExecResult
executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
JsonbValue *jb, PGFunction func,
JsonbValue *jb, BinaryArithmFunc func,
JsonValueList *found)
{
JsonPathExecResult jper;
......@@ -1506,7 +1519,7 @@ executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
JsonValueList rseq = {0};
JsonbValue *lval;
JsonbValue *rval;
Datum res;
Numeric res;
jspGetLeftArg(jsp, &elem);
......@@ -1542,16 +1555,26 @@ executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
"is not a singleton numeric value",
jspOperationName(jsp->type)))));
res = DirectFunctionCall2(func,
NumericGetDatum(lval->val.numeric),
NumericGetDatum(rval->val.numeric));
if (jspThrowErrors(cxt))
{
res = func(lval->val.numeric, rval->val.numeric, NULL);
}
else
{
bool error = false;
res = func(lval->val.numeric, rval->val.numeric, &error);
if (error)
return jperError;
}
if (!jspGetNext(jsp, &elem) && !found)
return jperOk;
lval = palloc(sizeof(*lval));
lval->type = jbvNumeric;
lval->val.numeric = DatumGetNumeric(res);
lval->val.numeric = res;
return executeNextItem(cxt, jsp, &elem, lval, found, false);
}
......@@ -2108,6 +2131,7 @@ getArrayIndex(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
JsonValueList found = {0};
JsonPathExecResult res = executeItem(cxt, jsp, jb, &found);
Datum numeric_index;
bool have_error = false;
if (jperIsError(res))
return res;
......@@ -2124,7 +2148,15 @@ getArrayIndex(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
NumericGetDatum(jbv->val.numeric),
Int32GetDatum(0));
*index = DatumGetInt32(DirectFunctionCall1(numeric_int4, numeric_index));
*index = numeric_int4_opt_error(DatumGetNumeric(numeric_index),
&have_error);
if (have_error)
RETURN_ERROR(ereport(ERROR,
(errcode(ERRCODE_INVALID_JSON_SUBSCRIPT),
errmsg(ERRMSG_INVALID_JSON_SUBSCRIPT),
errdetail("jsonpath array subscript is "
"out of integer range"))));
return jperOk;
}
......
......@@ -475,10 +475,11 @@ static char *get_str_from_var(const NumericVar *var);
static char *get_str_from_var_sci(const NumericVar *var, int rscale);
static Numeric make_result(const NumericVar *var);
static Numeric make_result_opt_error(const NumericVar *var, bool *error);
static void apply_typmod(NumericVar *var, int32 typmod);
static int32 numericvar_to_int32(const NumericVar *var);
static bool numericvar_to_int32(const NumericVar *var, int32 *result);
static bool numericvar_to_int64(const NumericVar *var, int64 *result);
static void int64_to_numericvar(int64 val, NumericVar *var);
#ifdef HAVE_INT128
......@@ -1558,7 +1559,10 @@ width_bucket_numeric(PG_FUNCTION_ARGS)
}
/* if result exceeds the range of a legal int4, we ereport here */
result = numericvar_to_int32(&result_var);
if (!numericvar_to_int32(&result_var, &result))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
free_var(&count_var);
free_var(&result_var);
......@@ -2406,6 +2410,23 @@ numeric_add(PG_FUNCTION_ARGS)
{
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
Numeric res;
res = numeric_add_opt_error(num1, num2, NULL);
PG_RETURN_NUMERIC(res);
}
/*
* numeric_add_opt_error() -
*
* Internal version of numeric_add(). If "*have_error" flag is provided,
* on error it's set to true, NULL returned. This is helpful when caller
* need to handle errors by itself.
*/
Numeric
numeric_add_opt_error(Numeric num1, Numeric num2, bool *have_error)
{
NumericVar arg1;
NumericVar arg2;
NumericVar result;
......@@ -2415,7 +2436,7 @@ numeric_add(PG_FUNCTION_ARGS)
* Handle NaN
*/
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
PG_RETURN_NUMERIC(make_result(&const_nan));
return make_result(&const_nan);
/*
* Unpack the values, let add_var() compute the result and return it.
......@@ -2426,11 +2447,11 @@ numeric_add(PG_FUNCTION_ARGS)
init_var(&result);
add_var(&arg1, &arg2, &result);
res = make_result(&result);
res = make_result_opt_error(&result, have_error);
free_var(&result);
PG_RETURN_NUMERIC(res);
return res;
}
......@@ -2444,6 +2465,24 @@ numeric_sub(PG_FUNCTION_ARGS)
{
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
Numeric res;
res = numeric_sub_opt_error(num1, num2, NULL);
PG_RETURN_NUMERIC(res);
}
/*
* numeric_sub_opt_error() -
*
* Internal version of numeric_sub(). If "*have_error" flag is provided,
* on error it's set to true, NULL returned. This is helpful when caller
* need to handle errors by itself.
*/
Numeric
numeric_sub_opt_error(Numeric num1, Numeric num2, bool *have_error)
{
NumericVar arg1;
NumericVar arg2;
NumericVar result;
......@@ -2453,7 +2492,7 @@ numeric_sub(PG_FUNCTION_ARGS)
* Handle NaN
*/
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
PG_RETURN_NUMERIC(make_result(&const_nan));
return make_result(&const_nan);
/*
* Unpack the values, let sub_var() compute the result and return it.
......@@ -2464,11 +2503,11 @@ numeric_sub(PG_FUNCTION_ARGS)
init_var(&result);
sub_var(&arg1, &arg2, &result);
res = make_result(&result);
res = make_result_opt_error(&result, have_error);
free_var(&result);
PG_RETURN_NUMERIC(res);
return res;
}
......@@ -2482,6 +2521,24 @@ numeric_mul(PG_FUNCTION_ARGS)
{
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
Numeric res;
res = numeric_mul_opt_error(num1, num2, NULL);
PG_RETURN_NUMERIC(res);
}
/*
* numeric_mul_opt_error() -
*
* Internal version of numeric_mul(). If "*have_error" flag is provided,
* on error it's set to true, NULL returned. This is helpful when caller
* need to handle errors by itself.
*/
Numeric
numeric_mul_opt_error(Numeric num1, Numeric num2, bool *have_error)
{
NumericVar arg1;
NumericVar arg2;
NumericVar result;
......@@ -2491,7 +2548,7 @@ numeric_mul(PG_FUNCTION_ARGS)
* Handle NaN
*/
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
PG_RETURN_NUMERIC(make_result(&const_nan));
return make_result(&const_nan);
/*
* Unpack the values, let mul_var() compute the result and return it.
......@@ -2506,11 +2563,11 @@ numeric_mul(PG_FUNCTION_ARGS)
init_var(&result);
mul_var(&arg1, &arg2, &result, arg1.dscale + arg2.dscale);
res = make_result(&result);
res = make_result_opt_error(&result, have_error);
free_var(&result);
PG_RETURN_NUMERIC(res);
return res;
}
......@@ -2524,6 +2581,24 @@ numeric_div(PG_FUNCTION_ARGS)
{
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
Numeric res;
res = numeric_div_opt_error(num1, num2, NULL);
PG_RETURN_NUMERIC(res);
}
/*
* numeric_div_opt_error() -
*
* Internal version of numeric_div(). If "*have_error" flag is provided,
* on error it's set to true, NULL returned. This is helpful when caller
* need to handle errors by itself.
*/
Numeric
numeric_div_opt_error(Numeric num1, Numeric num2, bool *have_error)
{
NumericVar arg1;
NumericVar arg2;
NumericVar result;
......@@ -2534,7 +2609,7 @@ numeric_div(PG_FUNCTION_ARGS)
* Handle NaN
*/
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
PG_RETURN_NUMERIC(make_result(&const_nan));
return make_result(&const_nan);
/*
* Unpack the arguments
......@@ -2549,16 +2624,25 @@ numeric_div(PG_FUNCTION_ARGS)
*/
rscale = select_div_scale(&arg1, &arg2);
/*
* If "have_error" is provided, check for division by zero here
*/
if (have_error && (arg2.ndigits == 0 || arg2.digits[0] == 0))
{
*have_error = true;
return NULL;
}
/*
* Do the divide and return the result
*/
div_var(&arg1, &arg2, &result, rscale, true);
res = make_result(&result);
res = make_result_opt_error(&result, have_error);
free_var(&result);
PG_RETURN_NUMERIC(res);
return res;
}
......@@ -2615,25 +2699,52 @@ numeric_mod(PG_FUNCTION_ARGS)
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
Numeric res;
res = numeric_mod_opt_error(num1, num2, NULL);
PG_RETURN_NUMERIC(res);
}
/*
* numeric_mod_opt_error() -
*
* Internal version of numeric_mod(). If "*have_error" flag is provided,
* on error it's set to true, NULL returned. This is helpful when caller
* need to handle errors by itself.
*/
Numeric
numeric_mod_opt_error(Numeric num1, Numeric num2, bool *have_error)
{
Numeric res;
NumericVar arg1;
NumericVar arg2;
NumericVar result;
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
PG_RETURN_NUMERIC(make_result(&const_nan));
return make_result(&const_nan);
init_var_from_num(num1, &arg1);
init_var_from_num(num2, &arg2);
init_var(&result);
/*
* If "have_error" is provided, check for division by zero here
*/
if (have_error && (arg2.ndigits == 0 || arg2.digits[0] == 0))
{
*have_error = true;
return NULL;
}
mod_var(&arg1, &arg2, &result);
res = make_result(&result);
res = make_result_opt_error(&result, NULL);
free_var(&result);
PG_RETURN_NUMERIC(res);
return res;
}
......@@ -3090,52 +3201,75 @@ int4_numeric(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(res);
}
Datum
numeric_int4(PG_FUNCTION_ARGS)
int32
numeric_int4_opt_error(Numeric num, bool *have_error)
{
Numeric num = PG_GETARG_NUMERIC(0);
NumericVar x;
int32 result;
/* XXX would it be better to return NULL? */
if (NUMERIC_IS_NAN(num))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot convert NaN to integer")));
{
if (have_error)
{
*have_error = true;
return 0;
}
else
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot convert NaN to integer")));
}
}
/* Convert to variable format, then convert to int4 */
init_var_from_num(num, &x);
result = numericvar_to_int32(&x);
PG_RETURN_INT32(result);
if (!numericvar_to_int32(&x, &result))
{
if (have_error)
{
*have_error = true;
return 0;
}
else
{
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
}
}
return result;
}
Datum
numeric_int4(PG_FUNCTION_ARGS)
{
Numeric num = PG_GETARG_NUMERIC(0);
PG_RETURN_INT32(numeric_int4_opt_error(num, NULL));
}
/*
* Given a NumericVar, convert it to an int32. If the NumericVar
* exceeds the range of an int32, raise the appropriate error via
* ereport(). The input NumericVar is *not* free'd.
* exceeds the range of an int32, false is returned, otherwise true is returned.
* The input NumericVar is *not* free'd.
*/
static int32
numericvar_to_int32(const NumericVar *var)
static bool
numericvar_to_int32(const NumericVar *var, int32 *result)
{
int32 result;
int64 val;
if (!numericvar_to_int64(var, &val))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
return false;
/* Down-convert to int4 */
result = (int32) val;
*result = (int32) val;
/* Test for overflow by reverse-conversion. */
if ((int64) result != val)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
return result;
return ((int64) *result == val);
}
Datum
......@@ -6098,13 +6232,15 @@ get_str_from_var_sci(const NumericVar *var, int rscale)
/*
* make_result() -
* make_result_opt_error() -
*
* Create the packed db numeric format in palloc()'d memory from
* a variable.
* a variable. If "*have_error" flag is provided, on error it's set to
* true, NULL returned. This is helpful when caller need to handle errors
* by itself.
*/
static Numeric
make_result(const NumericVar *var)
make_result_opt_error(const NumericVar *var, bool *have_error)
{
Numeric result;
NumericDigit *digits = var->digits;
......@@ -6175,15 +6311,37 @@ make_result(const NumericVar *var)
/* Check for overflow of int16 fields */
if (NUMERIC_WEIGHT(result) != weight ||
NUMERIC_DSCALE(result) != var->dscale)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value overflows numeric format")));
{
if (have_error)
{
*have_error = true;
return NULL;
}
else
{
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value overflows numeric format")));
}
}
dump_numeric("make_result()", result);
return result;
}
/*
* make_result() -
*
* An interface to make_result_opt_error() without "have_error" argument.
*/
static Numeric
make_result(const NumericVar *var)
{
return make_result_opt_error(var, NULL);
}
/*
* apply_typmod() -
*
......
......@@ -40,6 +40,9 @@ extern PGDLLIMPORT int extra_float_digits;
extern int is_infinite(float8 val);
extern float8 float8in_internal(char *num, char **endptr_p,
const char *type_name, const char *orig_string);
extern float8 float8in_internal_opt_error(char *num, char **endptr_p,
const char *type_name, const char *orig_string,
bool *have_error);
extern char *float8out_internal(float8 num);
extern int float4_cmp_internal(float4 a, float4 b);
extern int float8_cmp_internal(float8 a, float8 b);
......
......@@ -61,4 +61,16 @@ int32 numeric_maximum_size(int32 typmod);
extern char *numeric_out_sci(Numeric num, int scale);
extern char *numeric_normalize(Numeric num);
extern Numeric numeric_add_opt_error(Numeric num1, Numeric num2,
bool *have_error);
extern Numeric numeric_sub_opt_error(Numeric num1, Numeric num2,
bool *have_error);
extern Numeric numeric_mul_opt_error(Numeric num1, Numeric num2,
bool *have_error);
extern Numeric numeric_div_opt_error(Numeric num1, Numeric num2,
bool *have_error);
extern Numeric numeric_mod_opt_error(Numeric num1, Numeric num2,
bool *have_error);
extern int32 numeric_int4_opt_error(Numeric num, bool *error);
#endif /* _PG_NUMERIC_H_ */
......@@ -127,13 +127,23 @@ select jsonb_path_query('[1]', 'strict $[1]', silent => true);
(0 rows)
select jsonb '[1]' @? 'lax $[10000000000000000]';
ERROR: integer out of range
?column?
----------
(1 row)
select jsonb '[1]' @? 'strict $[10000000000000000]';
ERROR: integer out of range
?column?
----------
(1 row)
select jsonb_path_query('[1]', 'lax $[10000000000000000]');
ERROR: integer out of range
ERROR: invalid SQL/JSON subscript
DETAIL: jsonpath array subscript is out of integer range
select jsonb_path_query('[1]', 'strict $[10000000000000000]');
ERROR: integer out of range
ERROR: invalid SQL/JSON subscript
DETAIL: jsonpath array subscript is out of integer range
select jsonb '[1]' @? '$[0]';
?column?
----------
......@@ -1037,9 +1047,19 @@ select jsonb '1' @? '$ ? ($ > 0)';
-- arithmetic errors
select jsonb_path_query('[1,2,0,3]', '$[*] ? (2 / @ > 0)');
ERROR: division by zero
jsonb_path_query
------------------
1
2
3
(3 rows)
select jsonb_path_query('[1,2,0,3]', '$[*] ? ((2 / @ > 0) is unknown)');
ERROR: division by zero
jsonb_path_query
------------------
0
(1 row)
select jsonb_path_query('0', '1 / $');
ERROR: division by zero
select jsonb_path_query('0', '1 / $ + 2');
......@@ -1502,7 +1522,8 @@ select jsonb_path_query('"1.23"', '$.double()');
(1 row)
select jsonb_path_query('"1.23aaa"', '$.double()');
ERROR: invalid input syntax for type double precision: "1.23aaa"
ERROR: non-numeric SQL/JSON item
DETAIL: jsonpath item method .double() can only be applied to a numeric value
select jsonb_path_query('"nan"', '$.double()');
jsonb_path_query
------------------
......
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