Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit16d489b

Browse files
committed
Numeric error suppression in jsonpath
Add support of numeric error suppression to jsonpath as it's required bystandard. This commit doesn't use PG_TRY()/PG_CATCH() in order to implementthat. Instead, it provides internal versions of numeric functions used, whichsupport error suppression.Discussion:https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.comAuthor: Alexander Korotkov, Nikita GlukhovReviewed-by: Tomas Vondra
1 parent72b6460 commit16d489b

File tree

7 files changed

+353
-97
lines changed

7 files changed

+353
-97
lines changed

‎doc/src/sgml/func.sgml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12209,7 +12209,7 @@ table2-mapping
1220912209
<para>
1221012210
The <literal>@?</literal> and <literal>@@</literal> operators suppress
1221112211
errors including: lacking object field or array element, unexpected JSON
12212-
item type.
12212+
item type and numeric errors.
1221312213
This behavior might be helpful while searching over JSON document
1221412214
collections of varying structure.
1221512215
</para>

‎src/backend/utils/adt/float.c

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -336,8 +336,19 @@ float8in(PG_FUNCTION_ARGS)
336336
PG_RETURN_FLOAT8(float8in_internal(num,NULL,"double precision",num));
337337
}
338338

339+
/* Convenience macro: set *have_error flag (if provided) or throw error */
340+
#defineRETURN_ERROR(throw_error) \
341+
do { \
342+
if (have_error) { \
343+
*have_error = true; \
344+
return 0.0; \
345+
} else { \
346+
throw_error; \
347+
} \
348+
} while (0)
349+
339350
/*
340-
*float8in_internal - guts of float8in()
351+
*float8in_internal_opt_error - guts of float8in()
341352
*
342353
* This is exposed for use by functions that want a reasonably
343354
* platform-independent way of inputting doubles. The behavior is
@@ -353,10 +364,14 @@ float8in(PG_FUNCTION_ARGS)
353364
*
354365
* "num" could validly be declared "const char *", but that results in an
355366
* unreasonable amount of extra casting both here and in callers, so we don't.
367+
*
368+
* When "*have_error" flag is provided, it's set instead of throwing an
369+
* error. This is helpful when caller need to handle errors by itself.
356370
*/
357371
double
358-
float8in_internal(char*num,char**endptr_p,
359-
constchar*type_name,constchar*orig_string)
372+
float8in_internal_opt_error(char*num,char**endptr_p,
373+
constchar*type_name,constchar*orig_string,
374+
bool*have_error)
360375
{
361376
doubleval;
362377
char*endptr;
@@ -370,10 +385,10 @@ float8in_internal(char *num, char **endptr_p,
370385
* strtod() on different platforms.
371386
*/
372387
if (*num=='\0')
373-
ereport(ERROR,
374-
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
375-
errmsg("invalid input syntax for type %s: \"%s\"",
376-
type_name,orig_string)));
388+
RETURN_ERROR(ereport(ERROR,
389+
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
390+
errmsg("invalid input syntax for type %s: \"%s\"",
391+
type_name,orig_string))));
377392

378393
errno=0;
379394
val=strtod(num,&endptr);
@@ -446,17 +461,19 @@ float8in_internal(char *num, char **endptr_p,
446461
char*errnumber=pstrdup(num);
447462

448463
errnumber[endptr-num]='\0';
449-
ereport(ERROR,
450-
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
451-
errmsg("\"%s\" is out of range for type double precision",
452-
errnumber)));
464+
RETURN_ERROR(ereport(ERROR,
465+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
466+
errmsg("\"%s\" is out of range for "
467+
"type double precision",
468+
errnumber))));
453469
}
454470
}
455471
else
456-
ereport(ERROR,
457-
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
458-
errmsg("invalid input syntax for type %s: \"%s\"",
459-
type_name,orig_string)));
472+
RETURN_ERROR(ereport(ERROR,
473+
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
474+
errmsg("invalid input syntax for type "
475+
"%s: \"%s\"",
476+
type_name,orig_string))));
460477
}
461478
#ifdefHAVE_BUGGY_SOLARIS_STRTOD
462479
else
@@ -479,14 +496,27 @@ float8in_internal(char *num, char **endptr_p,
479496
if (endptr_p)
480497
*endptr_p=endptr;
481498
elseif (*endptr!='\0')
482-
ereport(ERROR,
483-
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
484-
errmsg("invalid input syntax for type %s: \"%s\"",
485-
type_name,orig_string)));
499+
RETURN_ERROR(ereport(ERROR,
500+
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
501+
errmsg("invalid input syntax for type "
502+
"%s: \"%s\"",
503+
type_name,orig_string))));
486504

487505
returnval;
488506
}
489507

508+
/*
509+
* Interfact to float8in_internal_opt_error() without "have_error" argument.
510+
*/
511+
double
512+
float8in_internal(char*num,char**endptr_p,
513+
constchar*type_name,constchar*orig_string)
514+
{
515+
returnfloat8in_internal_opt_error(num,endptr_p,type_name,
516+
orig_string,NULL);
517+
}
518+
519+
490520
/*
491521
*float8out- converts float8 number to a string
492522
* using a standard output format

‎src/backend/utils/adt/jsonpath_exec.c

Lines changed: 55 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ typedef JsonPathBool (*JsonPathPredicateCallback) (JsonPathItem *jsp,
179179
JsonbValue*larg,
180180
JsonbValue*rarg,
181181
void*param);
182+
typedefNumeric (*BinaryArithmFunc) (Numericnum1,Numericnum2,bool*error);
182183

183184
staticJsonPathExecResultexecuteJsonPath(JsonPath*path,Jsonb*vars,
184185
Jsonb*json,boolthrowErrors,JsonValueList*result);
@@ -212,8 +213,8 @@ static JsonPathBool executePredicate(JsonPathExecContext *cxt,
212213
JsonbValue*jb,boolunwrapRightArg,
213214
JsonPathPredicateCallbackexec,void*param);
214215
staticJsonPathExecResultexecuteBinaryArithmExpr(JsonPathExecContext*cxt,
215-
JsonPathItem*jsp,JsonbValue*jb,PGFunctionfunc,
216-
JsonValueList*found);
216+
JsonPathItem*jsp,JsonbValue*jb,
217+
BinaryArithmFuncfunc,JsonValueList*found);
217218
staticJsonPathExecResultexecuteUnaryArithmExpr(JsonPathExecContext*cxt,
218219
JsonPathItem*jsp,JsonbValue*jb,PGFunctionfunc,
219220
JsonValueList*found);
@@ -830,23 +831,23 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
830831

831832
casejpiAdd:
832833
returnexecuteBinaryArithmExpr(cxt,jsp,jb,
833-
numeric_add,found);
834+
numeric_add_opt_error,found);
834835

835836
casejpiSub:
836837
returnexecuteBinaryArithmExpr(cxt,jsp,jb,
837-
numeric_sub,found);
838+
numeric_sub_opt_error,found);
838839

839840
casejpiMul:
840841
returnexecuteBinaryArithmExpr(cxt,jsp,jb,
841-
numeric_mul,found);
842+
numeric_mul_opt_error,found);
842843

843844
casejpiDiv:
844845
returnexecuteBinaryArithmExpr(cxt,jsp,jb,
845-
numeric_div,found);
846+
numeric_div_opt_error,found);
846847

847848
casejpiMod:
848849
returnexecuteBinaryArithmExpr(cxt,jsp,jb,
849-
numeric_mod,found);
850+
numeric_mod_opt_error,found);
850851

851852
casejpiPlus:
852853
returnexecuteUnaryArithmExpr(cxt,jsp,jb,NULL,found);
@@ -999,12 +1000,22 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
9991000
{
10001001
char*tmp=DatumGetCString(DirectFunctionCall1(numeric_out,
10011002
NumericGetDatum(jb->val.numeric)));
1003+
boolhave_error= false;
10021004

1003-
(void)float8in_internal(tmp,
1004-
NULL,
1005-
"double precision",
1006-
tmp);
1005+
(void)float8in_internal_opt_error(tmp,
1006+
NULL,
1007+
"double precision",
1008+
tmp,
1009+
&have_error);
10071010

1011+
if (have_error)
1012+
RETURN_ERROR(ereport(ERROR,
1013+
(errcode(ERRCODE_NON_NUMERIC_JSON_ITEM),
1014+
errmsg(ERRMSG_NON_NUMERIC_JSON_ITEM),
1015+
errdetail("jsonpath item method .%s() "
1016+
"can only be applied to "
1017+
"a numeric value",
1018+
jspOperationName(jsp->type)))));
10081019
res=jperOk;
10091020
}
10101021
elseif (jb->type==jbvString)
@@ -1013,13 +1024,15 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
10131024
doubleval;
10141025
char*tmp=pnstrdup(jb->val.string.val,
10151026
jb->val.string.len);
1027+
boolhave_error= false;
10161028

1017-
val=float8in_internal(tmp,
1018-
NULL,
1019-
"double precision",
1020-
tmp);
1029+
val=float8in_internal_opt_error(tmp,
1030+
NULL,
1031+
"double precision",
1032+
tmp,
1033+
&have_error);
10211034

1022-
if (isinf(val))
1035+
if (have_error||isinf(val))
10231036
RETURN_ERROR(ereport(ERROR,
10241037
(errcode(ERRCODE_NON_NUMERIC_JSON_ITEM),
10251038
errmsg(ERRMSG_NON_NUMERIC_JSON_ITEM),
@@ -1497,7 +1510,7 @@ executePredicate(JsonPathExecContext *cxt, JsonPathItem *pred,
14971510
*/
14981511
staticJsonPathExecResult
14991512
executeBinaryArithmExpr(JsonPathExecContext*cxt,JsonPathItem*jsp,
1500-
JsonbValue*jb,PGFunctionfunc,
1513+
JsonbValue*jb,BinaryArithmFuncfunc,
15011514
JsonValueList*found)
15021515
{
15031516
JsonPathExecResultjper;
@@ -1506,7 +1519,7 @@ executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
15061519
JsonValueListrseq= {0};
15071520
JsonbValue*lval;
15081521
JsonbValue*rval;
1509-
Datumres;
1522+
Numericres;
15101523

15111524
jspGetLeftArg(jsp,&elem);
15121525

@@ -1542,16 +1555,26 @@ executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
15421555
"is not a singleton numeric value",
15431556
jspOperationName(jsp->type)))));
15441557

1545-
res=DirectFunctionCall2(func,
1546-
NumericGetDatum(lval->val.numeric),
1547-
NumericGetDatum(rval->val.numeric));
1558+
if (jspThrowErrors(cxt))
1559+
{
1560+
res=func(lval->val.numeric,rval->val.numeric,NULL);
1561+
}
1562+
else
1563+
{
1564+
boolerror= false;
1565+
1566+
res=func(lval->val.numeric,rval->val.numeric,&error);
1567+
1568+
if (error)
1569+
returnjperError;
1570+
}
15481571

15491572
if (!jspGetNext(jsp,&elem)&& !found)
15501573
returnjperOk;
15511574

15521575
lval=palloc(sizeof(*lval));
15531576
lval->type=jbvNumeric;
1554-
lval->val.numeric=DatumGetNumeric(res);
1577+
lval->val.numeric=res;
15551578

15561579
returnexecuteNextItem(cxt,jsp,&elem,lval,found, false);
15571580
}
@@ -2108,6 +2131,7 @@ getArrayIndex(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
21082131
JsonValueListfound= {0};
21092132
JsonPathExecResultres=executeItem(cxt,jsp,jb,&found);
21102133
Datumnumeric_index;
2134+
boolhave_error= false;
21112135

21122136
if (jperIsError(res))
21132137
returnres;
@@ -2124,7 +2148,15 @@ getArrayIndex(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
21242148
NumericGetDatum(jbv->val.numeric),
21252149
Int32GetDatum(0));
21262150

2127-
*index=DatumGetInt32(DirectFunctionCall1(numeric_int4,numeric_index));
2151+
*index=numeric_int4_opt_error(DatumGetNumeric(numeric_index),
2152+
&have_error);
2153+
2154+
if (have_error)
2155+
RETURN_ERROR(ereport(ERROR,
2156+
(errcode(ERRCODE_INVALID_JSON_SUBSCRIPT),
2157+
errmsg(ERRMSG_INVALID_JSON_SUBSCRIPT),
2158+
errdetail("jsonpath array subscript is "
2159+
"out of integer range"))));
21282160

21292161
returnjperOk;
21302162
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp