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

Commit b1767c4

Browse files
author
Nikita Glukhov
committed
Add extended jsonpath errors
1 parent 4d8130a commit b1767c4

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
@@ -24,6 +24,10 @@
2424
#include "utils/jsonpath.h"
2525
#include "utils/varlena.h"
2626

27+
/* Special pseudo-ErrorData with zero sqlerrcode for existence queries. */
28+
ErrorData jperNotFound[1];
29+
30+
2731
typedef struct JsonPathExecContext
2832
{
2933
List *vars;
@@ -755,12 +759,12 @@ executeComparison(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb)
755759
jspGetLeftArg(jsp, &elem);
756760
res = recursiveExecuteAndUnwrap(cxt, &elem, jb, &lseq);
757761
if (jperIsError(res))
758-
return jpbUnknown;
762+
return jperReplace(res, jpbUnknown);
759763

760764
jspGetRightArg(jsp, &elem);
761765
res = recursiveExecuteAndUnwrap(cxt, &elem, jb, &rseq);
762766
if (jperIsError(res))
763-
return jpbUnknown;
767+
return jperReplace(res, jpbUnknown);
764768

765769
while ((lval = JsonValueListNext(&lseq, &lseqit)))
766770
{
@@ -906,14 +910,16 @@ executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
906910
PG_CATCH();
907911
{
908912
int errcode = geterrcode();
913+
ErrorData *edata;
909914

910915
if (ERRCODE_TO_CATEGORY(errcode) != ERRCODE_DATA_EXCEPTION)
911916
PG_RE_THROW();
912917

913-
FlushErrorState();
914918
MemoryContextSwitchTo(mcxt);
919+
edata = CopyErrorData();
920+
FlushErrorState();
915921

916-
return jperMakeError(errcode);
922+
return jperMakeErrorData(edata);
917923
}
918924
PG_END_TRY();
919925

@@ -940,7 +946,7 @@ executeUnaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
940946
jper = recursiveExecuteAndUnwrap(cxt, &elem, jb, &seq);
941947

942948
if (jperIsError(jper))
943-
return jperMakeError(ERRCODE_JSON_NUMBER_NOT_FOUND);
949+
return jperReplace(jper, jperMakeError(ERRCODE_JSON_NUMBER_NOT_FOUND));
944950

945951
jper = jperNotFound;
946952

@@ -1107,7 +1113,7 @@ executeStartsWithPredicate(JsonPathExecContext *cxt, JsonPathItem *jsp,
11071113
jspGetRightArg(jsp, &elem);
11081114
res = recursiveExecute(cxt, &elem, jb, &rseq);
11091115
if (jperIsError(res))
1110-
return jpbUnknown;
1116+
return jperReplace(res, jpbUnknown);
11111117

11121118
if (JsonValueListLength(&rseq) != 1)
11131119
return jpbUnknown;
@@ -1123,7 +1129,7 @@ executeStartsWithPredicate(JsonPathExecContext *cxt, JsonPathItem *jsp,
11231129
jspGetLeftArg(jsp, &elem);
11241130
res = recursiveExecuteAndUnwrap(cxt, &elem, jb, &lseq);
11251131
if (jperIsError(res))
1126-
return jpbUnknown;
1132+
return jperReplace(res, jpbUnknown);
11271133

11281134
while ((whole = JsonValueListNext(&lseq, &lit)))
11291135
{
@@ -1190,7 +1196,7 @@ executeLikeRegexPredicate(JsonPathExecContext *cxt, JsonPathItem *jsp,
11901196
jspInitByBuffer(&elem, jsp->base, jsp->content.like_regex.expr);
11911197
res = recursiveExecuteAndUnwrap(cxt, &elem, jb, &seq);
11921198
if (jperIsError(res))
1193-
return jpbUnknown;
1199+
return jperReplace(res, jpbUnknown);
11941200

11951201
while ((str = JsonValueListNext(&seq, &it)))
11961202
{
@@ -1371,7 +1377,7 @@ recursiveExecuteBool(JsonPathExecContext *cxt, JsonPathItem *jsp,
13711377
recursiveExecute(cxt, &arg, jb, &vals);
13721378

13731379
if (jperIsError(res))
1374-
return jpbUnknown;
1380+
return jperReplace(res, jpbUnknown);
13751381

13761382
return JsonValueListIsEmpty(&vals) ? jpbFalse : jpbTrue;
13771383
}
@@ -1380,7 +1386,7 @@ recursiveExecuteBool(JsonPathExecContext *cxt, JsonPathItem *jsp,
13801386
JsonPathExecResult res = recursiveExecute(cxt, &arg, jb, NULL);
13811387

13821388
if (jperIsError(res))
1383-
return jpbUnknown;
1389+
return jperReplace(res, jpbUnknown);
13841390

13851391
return res == jperOk ? jpbTrue : jpbFalse;
13861392
}
@@ -2353,59 +2359,65 @@ makePassingVars(Jsonb *jb)
23532359
static void
23542360
throwJsonPathError(JsonPathExecResult res)
23552361
{
2362+
int err;
23562363
if (!jperIsError(res))
23572364
return;
23582365

2359-
switch (jperGetError(res))
2366+
if (jperIsErrorData(res))
2367+
ThrowErrorData(jperGetErrorData(res));
2368+
2369+
err = jperGetError(res);
2370+
2371+
switch (err)
23602372
{
23612373
case ERRCODE_JSON_ARRAY_NOT_FOUND:
23622374
ereport(ERROR,
2363-
(errcode(jperGetError(res)),
2375+
(errcode(err),
23642376
errmsg("SQL/JSON array not found")));
23652377
break;
23662378
case ERRCODE_JSON_OBJECT_NOT_FOUND:
23672379
ereport(ERROR,
2368-
(errcode(jperGetError(res)),
2380+
(errcode(err),
23692381
errmsg("SQL/JSON object not found")));
23702382
break;
23712383
case ERRCODE_JSON_MEMBER_NOT_FOUND:
23722384
ereport(ERROR,
2373-
(errcode(jperGetError(res)),
2385+
(errcode(err),
23742386
errmsg("SQL/JSON member not found")));
23752387
break;
23762388
case ERRCODE_JSON_NUMBER_NOT_FOUND:
23772389
ereport(ERROR,
2378-
(errcode(jperGetError(res)),
2390+
(errcode(err),
23792391
errmsg("SQL/JSON number not found")));
23802392
break;
23812393
case ERRCODE_JSON_SCALAR_REQUIRED:
23822394
ereport(ERROR,
2383-
(errcode(jperGetError(res)),
2395+
(errcode(err),
23842396
errmsg("SQL/JSON scalar required")));
23852397
break;
23862398
case ERRCODE_SINGLETON_JSON_ITEM_REQUIRED:
23872399
ereport(ERROR,
2388-
(errcode(jperGetError(res)),
2400+
(errcode(err),
23892401
errmsg("Singleton SQL/JSON item required")));
23902402
break;
23912403
case ERRCODE_NON_NUMERIC_JSON_ITEM:
23922404
ereport(ERROR,
2393-
(errcode(jperGetError(res)),
2405+
(errcode(err),
23942406
errmsg("Non-numeric SQL/JSON item")));
23952407
break;
23962408
case ERRCODE_INVALID_JSON_SUBSCRIPT:
23972409
ereport(ERROR,
2398-
(errcode(jperGetError(res)),
2410+
(errcode(err),
23992411
errmsg("Invalid SQL/JSON subscript")));
24002412
break;
24012413
case ERRCODE_INVALID_ARGUMENT_FOR_JSON_DATETIME_FUNCTION:
24022414
ereport(ERROR,
2403-
(errcode(jperGetError(res)),
2415+
(errcode(err),
24042416
errmsg("Invalid argument for SQL/JSON datetime function")));
24052417
break;
24062418
default:
24072419
ereport(ERROR,
2408-
(errcode(jperGetError(res)),
2420+
(errcode(err),
24092421
errmsg("Unknown SQL/JSON error")));
24102422
break;
24112423
}
@@ -2428,7 +2440,10 @@ jsonb_jsonpath_exists(PG_FUNCTION_ARGS)
24282440
PG_FREE_IF_COPY(jp, 1);
24292441

24302442
if (jperIsError(res))
2443+
{
2444+
jperFree(res);
24312445
PG_RETURN_NULL();
2446+
}
24322447

24332448
PG_RETURN_BOOL(res == jperOk);
24342449
}

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)