1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-21 00:42:43 +03:00

Convert jsonpath's input function to report errors softly

Reviewed by Tom Lane

Discussion: https://postgr.es/m/a8dc5700-c341-3ba8-0507-cc09881e6200@dunslane.net
This commit is contained in:
Andrew Dunstan
2022-12-24 15:19:14 -05:00
parent 780ec9f1b2
commit e37fe1db6e
8 changed files with 323 additions and 126 deletions

View File

@@ -66,16 +66,19 @@
#include "funcapi.h"
#include "lib/stringinfo.h"
#include "libpq/pqformat.h"
#include "nodes/miscnodes.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/json.h"
#include "utils/jsonpath.h"
static Datum jsonPathFromCstring(char *in, int len);
static Datum jsonPathFromCstring(char *in, int len, struct Node *escontext);
static char *jsonPathToCstring(StringInfo out, JsonPath *in,
int estimated_len);
static int flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
static bool flattenJsonPathParseItem(StringInfo buf, int *result,
struct Node *escontext,
JsonPathParseItem *item,
int nestingLevel, bool insideArraySubscript);
static void alignStringInfoInt(StringInfo buf);
static int32 reserveSpaceForItemPointer(StringInfo buf);
@@ -95,7 +98,7 @@ jsonpath_in(PG_FUNCTION_ARGS)
char *in = PG_GETARG_CSTRING(0);
int len = strlen(in);
return jsonPathFromCstring(in, len);
return jsonPathFromCstring(in, len, fcinfo->context);
}
/*
@@ -119,7 +122,7 @@ jsonpath_recv(PG_FUNCTION_ARGS)
else
elog(ERROR, "unsupported jsonpath version number: %d", version);
return jsonPathFromCstring(str, nbytes);
return jsonPathFromCstring(str, nbytes, NULL);
}
/*
@@ -165,24 +168,29 @@ jsonpath_send(PG_FUNCTION_ARGS)
* representation of jsonpath.
*/
static Datum
jsonPathFromCstring(char *in, int len)
jsonPathFromCstring(char *in, int len, struct Node *escontext)
{
JsonPathParseResult *jsonpath = parsejsonpath(in, len);
JsonPathParseResult *jsonpath = parsejsonpath(in, len, escontext);
JsonPath *res;
StringInfoData buf;
if (SOFT_ERROR_OCCURRED(escontext))
return (Datum) 0;
if (!jsonpath)
ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"", "jsonpath",
in)));
initStringInfo(&buf);
enlargeStringInfo(&buf, 4 * len /* estimation */ );
appendStringInfoSpaces(&buf, JSONPATH_HDRSZ);
if (!jsonpath)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"", "jsonpath",
in)));
flattenJsonPathParseItem(&buf, jsonpath->expr, 0, false);
if (!flattenJsonPathParseItem(&buf, NULL, escontext,
jsonpath->expr, 0, false))
return (Datum) 0;
res = (JsonPath *) buf.data;
SET_VARSIZE(res, buf.len);
@@ -225,9 +233,10 @@ jsonPathToCstring(StringInfo out, JsonPath *in, int estimated_len)
* Recursive function converting given jsonpath parse item and all its
* children into a binary representation.
*/
static int
flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
int nestingLevel, bool insideArraySubscript)
static bool
flattenJsonPathParseItem(StringInfo buf, int *result, struct Node *escontext,
JsonPathParseItem *item, int nestingLevel,
bool insideArraySubscript)
{
/* position from beginning of jsonpath data */
int32 pos = buf->len - JSONPATH_HDRSZ;
@@ -295,16 +304,22 @@ flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
int32 left = reserveSpaceForItemPointer(buf);
int32 right = reserveSpaceForItemPointer(buf);
chld = !item->value.args.left ? pos :
flattenJsonPathParseItem(buf, item->value.args.left,
nestingLevel + argNestingLevel,
insideArraySubscript);
if (!item->value.args.left)
chld = pos;
else if (! flattenJsonPathParseItem(buf, &chld, escontext,
item->value.args.left,
nestingLevel + argNestingLevel,
insideArraySubscript))
return false;
*(int32 *) (buf->data + left) = chld - pos;
chld = !item->value.args.right ? pos :
flattenJsonPathParseItem(buf, item->value.args.right,
nestingLevel + argNestingLevel,
insideArraySubscript);
if (!item->value.args.right)
chld = pos;
else if (! flattenJsonPathParseItem(buf, &chld, escontext,
item->value.args.right,
nestingLevel + argNestingLevel,
insideArraySubscript))
return false;
*(int32 *) (buf->data + right) = chld - pos;
}
break;
@@ -323,9 +338,11 @@ flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
item->value.like_regex.patternlen);
appendStringInfoChar(buf, '\0');
chld = flattenJsonPathParseItem(buf, item->value.like_regex.expr,
nestingLevel,
insideArraySubscript);
if (! flattenJsonPathParseItem(buf, &chld, escontext,
item->value.like_regex.expr,
nestingLevel,
insideArraySubscript))
return false;
*(int32 *) (buf->data + offs) = chld - pos;
}
break;
@@ -341,10 +358,13 @@ flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
{
int32 arg = reserveSpaceForItemPointer(buf);
chld = !item->value.arg ? pos :
flattenJsonPathParseItem(buf, item->value.arg,
nestingLevel + argNestingLevel,
insideArraySubscript);
if (!item->value.arg)
chld = pos;
else if (! flattenJsonPathParseItem(buf, &chld, escontext,
item->value.arg,
nestingLevel + argNestingLevel,
insideArraySubscript))
return false;
*(int32 *) (buf->data + arg) = chld - pos;
}
break;
@@ -357,13 +377,13 @@ flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
break;
case jpiCurrent:
if (nestingLevel <= 0)
ereport(ERROR,
ereturn(escontext, false,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("@ is not allowed in root expressions")));
break;
case jpiLast:
if (!insideArraySubscript)
ereport(ERROR,
ereturn(escontext, false,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("LAST is allowed only in array subscripts")));
break;
@@ -383,15 +403,22 @@ flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
{
int32 *ppos;
int32 topos;
int32 frompos =
flattenJsonPathParseItem(buf,
item->value.array.elems[i].from,
nestingLevel, true) - pos;
int32 frompos;
if (! flattenJsonPathParseItem(buf, &frompos, escontext,
item->value.array.elems[i].from,
nestingLevel, true))
return false;
frompos -= pos;
if (item->value.array.elems[i].to)
topos = flattenJsonPathParseItem(buf,
item->value.array.elems[i].to,
nestingLevel, true) - pos;
{
if (! flattenJsonPathParseItem(buf, &topos, escontext,
item->value.array.elems[i].to,
nestingLevel, true))
return false;
topos -= pos;
}
else
topos = 0;
@@ -424,12 +451,17 @@ flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
if (item->next)
{
chld = flattenJsonPathParseItem(buf, item->next, nestingLevel,
insideArraySubscript) - pos;
if (! flattenJsonPathParseItem(buf, &chld, escontext,
item->next, nestingLevel,
insideArraySubscript))
return false;
chld -= pos;
*(int32 *) (buf->data + next) = chld;
}
return pos;
if (result)
*result = pos;
return true;
}
/*