diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index a13b3d63581..3a99e209a2b 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -12209,7 +12209,7 @@ table2-mapping The @? and @@ 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. diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c index 8e16d755b04..23649c10000 100644 --- a/src/backend/utils/adt/float.c +++ b/src/backend/utils/adt/float.c @@ -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 diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c index 0717071188f..4fc441f11e7 100644 --- a/src/backend/utils/adt/jsonpath_exec.c +++ b/src/backend/utils/adt/jsonpath_exec.c @@ -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; } diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 0765f2cdb59..fbc2863622e 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -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() - * diff --git a/src/include/utils/float.h b/src/include/utils/float.h index 0f82a25edea..5d935bb032d 100644 --- a/src/include/utils/float.h +++ b/src/include/utils/float.h @@ -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); diff --git a/src/include/utils/numeric.h b/src/include/utils/numeric.h index 9109cff98eb..b475c93e047 100644 --- a/src/include/utils/numeric.h +++ b/src/include/utils/numeric.h @@ -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_ */ diff --git a/src/test/regress/expected/jsonb_jsonpath.out b/src/test/regress/expected/jsonb_jsonpath.out index c12dfd6b924..0e2e2c474c0 100644 --- a/src/test/regress/expected/jsonb_jsonpath.out +++ b/src/test/regress/expected/jsonb_jsonpath.out @@ -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 ------------------