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

Commit d680b24

Browse files
author
Nikita Glukhov
committed
Add extended jsonpath errors
1 parent 33a290c commit d680b24

File tree

3 files changed

+62
-36
lines changed

3 files changed

+62
-36
lines changed

src/backend/utils/adt/jsonpath_exec.c

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
#include "utils/jsonpath.h"
2424
#include "utils/varlena.h"
2525

26+
/* Special pseudo-ErrorData with zero sqlerrcode for existence queries. */
27+
ErrorData jperNotFound[1];
28+
29+
2630
typedef struct JsonPathExecContext
2731
{
2832
List *vars;
@@ -786,12 +790,12 @@ executeComparison(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb)
786790
jspGetLeftArg(jsp, &elem);
787791
res = recursiveExecuteAndUnwrap(cxt, &elem, jb, &lseq);
788792
if (jperIsError(res))
789-
return jpbUnknown;
793+
return jperReplace(res, jpbUnknown);
790794

791795
jspGetRightArg(jsp, &elem);
792796
res = recursiveExecuteAndUnwrap(cxt, &elem, jb, &rseq);
793797
if (jperIsError(res))
794-
return jpbUnknown;
798+
return jperReplace(res, jpbUnknown);
795799

796800
while ((lval = JsonValueListNext(&lseq, &lseqit)))
797801
{
@@ -937,14 +941,16 @@ executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
937941
PG_CATCH();
938942
{
939943
int errcode = geterrcode();
944+
ErrorData *edata;
940945

941946
if (ERRCODE_TO_CATEGORY(errcode) != ERRCODE_DATA_EXCEPTION)
942947
PG_RE_THROW();
943948

944-
FlushErrorState();
945949
MemoryContextSwitchTo(mcxt);
950+
edata = CopyErrorData();
951+
FlushErrorState();
946952

947-
return jperMakeError(errcode);
953+
return jperMakeErrorData(edata);
948954
}
949955
PG_END_TRY();
950956

@@ -971,7 +977,7 @@ executeUnaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
971977
jper = recursiveExecuteAndUnwrap(cxt, &elem, jb, &seq);
972978

973979
if (jperIsError(jper))
974-
return jperMakeError(ERRCODE_JSON_NUMBER_NOT_FOUND);
980+
return jperReplace(jper, jperMakeError(ERRCODE_JSON_NUMBER_NOT_FOUND));
975981

976982
jper = jperNotFound;
977983

@@ -1138,7 +1144,7 @@ executeStartsWithPredicate(JsonPathExecContext *cxt, JsonPathItem *jsp,
11381144
jspGetRightArg(jsp, &elem);
11391145
res = recursiveExecute(cxt, &elem, jb, &rseq);
11401146
if (jperIsError(res))
1141-
return jpbUnknown;
1147+
return jperReplace(res, jpbUnknown);
11421148

11431149
if (JsonValueListLength(&rseq) != 1)
11441150
return jpbUnknown;
@@ -1154,7 +1160,7 @@ executeStartsWithPredicate(JsonPathExecContext *cxt, JsonPathItem *jsp,
11541160
jspGetLeftArg(jsp, &elem);
11551161
res = recursiveExecuteAndUnwrap(cxt, &elem, jb, &lseq);
11561162
if (jperIsError(res))
1157-
return jpbUnknown;
1163+
return jperReplace(res, jpbUnknown);
11581164

11591165
while ((whole = JsonValueListNext(&lseq, &lit)))
11601166
{
@@ -1221,7 +1227,7 @@ executeLikeRegexPredicate(JsonPathExecContext *cxt, JsonPathItem *jsp,
12211227
jspInitByBuffer(&elem, jsp->base, jsp->content.like_regex.expr);
12221228
res = recursiveExecuteAndUnwrap(cxt, &elem, jb, &seq);
12231229
if (jperIsError(res))
1224-
return jpbUnknown;
1230+
return jperReplace(res, jpbUnknown);
12251231

12261232
while ((str = JsonValueListNext(&seq, &it)))
12271233
{
@@ -1402,7 +1408,7 @@ recursiveExecuteBool(JsonPathExecContext *cxt, JsonPathItem *jsp,
14021408
recursiveExecute(cxt, &arg, jb, &vals);
14031409

14041410
if (jperIsError(res))
1405-
return jpbUnknown;
1411+
return jperReplace(res, jpbUnknown);
14061412

14071413
return JsonValueListIsEmpty(&vals) ? jpbFalse : jpbTrue;
14081414
}
@@ -1411,7 +1417,7 @@ recursiveExecuteBool(JsonPathExecContext *cxt, JsonPathItem *jsp,
14111417
JsonPathExecResult res = recursiveExecute(cxt, &arg, jb, NULL);
14121418

14131419
if (jperIsError(res))
1414-
return jpbUnknown;
1420+
return jperReplace(res, jpbUnknown);
14151421

14161422
return res == jperOk ? jpbTrue : jpbFalse;
14171423
}
@@ -2381,59 +2387,65 @@ makePassingVars(Jsonb *jb)
23812387
static void
23822388
throwJsonPathError(JsonPathExecResult res)
23832389
{
2390+
int err;
23842391
if (!jperIsError(res))
23852392
return;
23862393

2387-
switch (jperGetError(res))
2394+
if (jperIsErrorData(res))
2395+
ThrowErrorData(jperGetErrorData(res));
2396+
2397+
err = jperGetError(res);
2398+
2399+
switch (err)
23882400
{
23892401
case ERRCODE_JSON_ARRAY_NOT_FOUND:
23902402
ereport(ERROR,
2391-
(errcode(jperGetError(res)),
2403+
(errcode(err),
23922404
errmsg("SQL/JSON array not found")));
23932405
break;
23942406
case ERRCODE_JSON_OBJECT_NOT_FOUND:
23952407
ereport(ERROR,
2396-
(errcode(jperGetError(res)),
2408+
(errcode(err),
23972409
errmsg("SQL/JSON object not found")));
23982410
break;
23992411
case ERRCODE_JSON_MEMBER_NOT_FOUND:
24002412
ereport(ERROR,
2401-
(errcode(jperGetError(res)),
2413+
(errcode(err),
24022414
errmsg("SQL/JSON member not found")));
24032415
break;
24042416
case ERRCODE_JSON_NUMBER_NOT_FOUND:
24052417
ereport(ERROR,
2406-
(errcode(jperGetError(res)),
2418+
(errcode(err),
24072419
errmsg("SQL/JSON number not found")));
24082420
break;
24092421
case ERRCODE_JSON_SCALAR_REQUIRED:
24102422
ereport(ERROR,
2411-
(errcode(jperGetError(res)),
2423+
(errcode(err),
24122424
errmsg("SQL/JSON scalar required")));
24132425
break;
24142426
case ERRCODE_SINGLETON_JSON_ITEM_REQUIRED:
24152427
ereport(ERROR,
2416-
(errcode(jperGetError(res)),
2428+
(errcode(err),
24172429
errmsg("Singleton SQL/JSON item required")));
24182430
break;
24192431
case ERRCODE_NON_NUMERIC_JSON_ITEM:
24202432
ereport(ERROR,
2421-
(errcode(jperGetError(res)),
2433+
(errcode(err),
24222434
errmsg("Non-numeric SQL/JSON item")));
24232435
break;
24242436
case ERRCODE_INVALID_JSON_SUBSCRIPT:
24252437
ereport(ERROR,
2426-
(errcode(jperGetError(res)),
2438+
(errcode(err),
24272439
errmsg("Invalid SQL/JSON subscript")));
24282440
break;
24292441
case ERRCODE_INVALID_ARGUMENT_FOR_JSON_DATETIME_FUNCTION:
24302442
ereport(ERROR,
2431-
(errcode(jperGetError(res)),
2443+
(errcode(err),
24322444
errmsg("Invalid argument for SQL/JSON datetime function")));
24332445
break;
24342446
default:
24352447
ereport(ERROR,
2436-
(errcode(jperGetError(res)),
2448+
(errcode(err),
24372449
errmsg("Unknown SQL/JSON error")));
24382450
break;
24392451
}
@@ -2456,7 +2468,10 @@ jsonb_jsonpath_exists(PG_FUNCTION_ARGS)
24562468
PG_FREE_IF_COPY(jp, 1);
24572469

24582470
if (jperIsError(res))
2471+
{
2472+
jperFree(res);
24592473
PG_RETURN_NULL();
2474+
}
24602475

24612476
PG_RETURN_BOOL(res == jperOk);
24622477
}

src/include/utils/jsonpath.h

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -237,21 +237,32 @@ typedef enum JsonPathBool
237237
jpbUnknown = 2
238238
} JsonPathBool;
239239

240-
typedef enum JsonPathExecStatus
240+
/* Result of jsonpath evaluation */
241+
typedef ErrorData *JsonPathExecResult;
242+
243+
/* Special pseudo-ErrorData with zero sqlerrcode for existence queries. */
244+
extern ErrorData jperNotFound[1];
245+
246+
#define jperOk NULL
247+
#define jperIsError(jper) ((jper) && (jper)->sqlerrcode)
248+
#define jperIsErrorData(jper) ((jper) && (jper)->elevel > 0)
249+
#define jperGetError(jper) ((jper)->sqlerrcode)
250+
#define jperMakeErrorData(edata) (edata)
251+
#define jperGetErrorData(jper) (jper)
252+
#define jperFree(jper) ((jper) && (jper)->sqlerrcode ? \
253+
(jper)->elevel > 0 ? FreeErrorData(jper) : pfree(jper) : (void) 0)
254+
#define jperReplace(jper1, jper2) (jperFree(jper1), (jper2))
255+
256+
/* Returns special SQL/JSON ErrorData with zero elevel */
257+
static inline JsonPathExecResult
258+
jperMakeError(int sqlerrcode)
241259
{
242-
jperOk = 0,
243-
jperError,
244-
jperFatalError,
245-
jperNotFound
246-
} JsonPathExecStatus;
247-
248-
typedef uint64 JsonPathExecResult;
249-
250-
#define jperStatus(jper) ((JsonPathExecStatus)(uint32)(jper))
251-
#define jperIsError(jper) (jperStatus(jper) == jperError)
252-
#define jperGetError(jper) ((uint32)((jper) >> 32))
253-
#define jperMakeError(err) (((uint64)(err) << 32) | jperError)
254-
#define jperFree(jper) ((void) 0)
260+
ErrorData *edata = palloc0(sizeof(*edata));
261+
262+
edata->sqlerrcode = sqlerrcode;
263+
264+
return edata;
265+
}
255266

256267
typedef Datum (*JsonPathVariable_cb)(void *, bool *);
257268

src/test/regress/expected/jsonb_jsonpath.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -807,7 +807,7 @@ select jsonb '[1,2,0,3]' @* '$[*] ? ((2 / @ > 0) is unknown)';
807807
(1 row)
808808

809809
select jsonb '0' @* '1 / $';
810-
ERROR: Unknown SQL/JSON error
810+
ERROR: division by zero
811811
-- unwrapping of operator arguments in lax mode
812812
select jsonb '{"a": [2]}' @* 'lax $.a * 3';
813813
?column?

0 commit comments

Comments
 (0)