postgresql/src/backend/utils/adt/jsonpath.c

1076 lines
26 KiB
C
Raw Normal View History

Partial implementation of SQL/JSON path language SQL 2016 standards among other things contains set of SQL/JSON features for JSON processing inside of relational database. The core of SQL/JSON is JSON path language, allowing access parts of JSON documents and make computations over them. This commit implements partial support JSON path language as separate datatype called "jsonpath". The implementation is partial because it's lacking datetime support and suppression of numeric errors. Missing features will be added later by separate commits. Support of SQL/JSON features requires implementation of separate nodes, and it will be considered in subsequent patches. This commit includes following set of plain functions, allowing to execute jsonpath over jsonb values: * jsonb_path_exists(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_match(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query_array(jsonb, jsonpath[, jsonb, bool]). * jsonb_path_query_first(jsonb, jsonpath[, jsonb, bool]). This commit also implements "jsonb @? jsonpath" and "jsonb @@ jsonpath", which are wrappers over jsonpath_exists(jsonb, jsonpath) and jsonpath_predicate(jsonb, jsonpath) correspondingly. These operators will have an index support (implemented in subsequent patches). Catversion bumped, to add new functions and operators. Code was written by Nikita Glukhov and Teodor Sigaev, revised by me. Documentation was written by Oleg Bartunov and Liudmila Mantrova. The work was inspired by Oleg Bartunov. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Author: Nikita Glukhov, Teodor Sigaev, Alexander Korotkov, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Tomas Vondra, Andrew Dunstan, Pavel Stehule, Alexander Korotkov
2019-03-16 10:15:37 +01:00
/*-------------------------------------------------------------------------
*
* jsonpath.c
* Input/output and supporting routines for jsonpath
*
* jsonpath expression is a chain of path items. First path item is $, $var,
* literal or arithmetic expression. Subsequent path items are accessors
* (.key, .*, [subscripts], [*]), filters (? (predicate)) and methods (.type(),
* .size() etc).
*
* For instance, structure of path items for simple expression:
*
* $.a[*].type()
*
* is pretty evident:
*
* $ => .a => [*] => .type()
*
* Some path items such as arithmetic operations, predicates or array
* subscripts may comprise subtrees. For instance, more complex expression
*
* ($.a + $[1 to 5, 7] ? (@ > 3).double()).type()
*
* have following structure of path items:
*
* + => .type()
* ___/ \___
* / \
* $ => .a $ => [] => ? => .double()
* _||_ |
* / \ >
* to to / \
* / \ / @ 3
* 1 5 7
*
* Binary encoding of jsonpath constitutes a sequence of 4-bytes aligned
* variable-length path items connected by links. Every item has a header
* consisting of item type (enum JsonPathItemType) and offset of next item
* (zero means no next item). After the header, item may have payload
* depending on item type. For instance, payload of '.key' accessor item is
* length of key name and key name itself. Payload of '>' arithmetic operator
* item is offsets of right and left operands.
*
* So, binary representation of sample expression above is:
* (bottom arrows are next links, top lines are argument links)
*
* _____
* _____ ___/____ \ __
* _ /_ \ _____/__/____ \ \ __ _ /_ \
* / / \ \ / / / \ \ \ / \ / / \ \
* +(LR) $ .a $ [](* to *, * to *) 1 5 7 ?(A) >(LR) @ 3 .double() .type()
* | | ^ | ^| ^| ^ ^
* | |__| |__||________________________||___________________| |
* |_______________________________________________________________________|
*
* Copyright (c) 2019-2020, PostgreSQL Global Development Group
Partial implementation of SQL/JSON path language SQL 2016 standards among other things contains set of SQL/JSON features for JSON processing inside of relational database. The core of SQL/JSON is JSON path language, allowing access parts of JSON documents and make computations over them. This commit implements partial support JSON path language as separate datatype called "jsonpath". The implementation is partial because it's lacking datetime support and suppression of numeric errors. Missing features will be added later by separate commits. Support of SQL/JSON features requires implementation of separate nodes, and it will be considered in subsequent patches. This commit includes following set of plain functions, allowing to execute jsonpath over jsonb values: * jsonb_path_exists(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_match(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query_array(jsonb, jsonpath[, jsonb, bool]). * jsonb_path_query_first(jsonb, jsonpath[, jsonb, bool]). This commit also implements "jsonb @? jsonpath" and "jsonb @@ jsonpath", which are wrappers over jsonpath_exists(jsonb, jsonpath) and jsonpath_predicate(jsonb, jsonpath) correspondingly. These operators will have an index support (implemented in subsequent patches). Catversion bumped, to add new functions and operators. Code was written by Nikita Glukhov and Teodor Sigaev, revised by me. Documentation was written by Oleg Bartunov and Liudmila Mantrova. The work was inspired by Oleg Bartunov. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Author: Nikita Glukhov, Teodor Sigaev, Alexander Korotkov, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Tomas Vondra, Andrew Dunstan, Pavel Stehule, Alexander Korotkov
2019-03-16 10:15:37 +01:00
*
* IDENTIFICATION
* src/backend/utils/adt/jsonpath.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "funcapi.h"
#include "lib/stringinfo.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/json.h"
#include "utils/jsonpath.h"
static Datum jsonPathFromCstring(char *in, int len);
static char *jsonPathToCstring(StringInfo out, JsonPath *in,
int estimated_len);
static int flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
int nestingLevel, bool insideArraySubscript);
Partial implementation of SQL/JSON path language SQL 2016 standards among other things contains set of SQL/JSON features for JSON processing inside of relational database. The core of SQL/JSON is JSON path language, allowing access parts of JSON documents and make computations over them. This commit implements partial support JSON path language as separate datatype called "jsonpath". The implementation is partial because it's lacking datetime support and suppression of numeric errors. Missing features will be added later by separate commits. Support of SQL/JSON features requires implementation of separate nodes, and it will be considered in subsequent patches. This commit includes following set of plain functions, allowing to execute jsonpath over jsonb values: * jsonb_path_exists(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_match(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query_array(jsonb, jsonpath[, jsonb, bool]). * jsonb_path_query_first(jsonb, jsonpath[, jsonb, bool]). This commit also implements "jsonb @? jsonpath" and "jsonb @@ jsonpath", which are wrappers over jsonpath_exists(jsonb, jsonpath) and jsonpath_predicate(jsonb, jsonpath) correspondingly. These operators will have an index support (implemented in subsequent patches). Catversion bumped, to add new functions and operators. Code was written by Nikita Glukhov and Teodor Sigaev, revised by me. Documentation was written by Oleg Bartunov and Liudmila Mantrova. The work was inspired by Oleg Bartunov. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Author: Nikita Glukhov, Teodor Sigaev, Alexander Korotkov, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Tomas Vondra, Andrew Dunstan, Pavel Stehule, Alexander Korotkov
2019-03-16 10:15:37 +01:00
static void alignStringInfoInt(StringInfo buf);
static int32 reserveSpaceForItemPointer(StringInfo buf);
static void printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey,
bool printBracketes);
Partial implementation of SQL/JSON path language SQL 2016 standards among other things contains set of SQL/JSON features for JSON processing inside of relational database. The core of SQL/JSON is JSON path language, allowing access parts of JSON documents and make computations over them. This commit implements partial support JSON path language as separate datatype called "jsonpath". The implementation is partial because it's lacking datetime support and suppression of numeric errors. Missing features will be added later by separate commits. Support of SQL/JSON features requires implementation of separate nodes, and it will be considered in subsequent patches. This commit includes following set of plain functions, allowing to execute jsonpath over jsonb values: * jsonb_path_exists(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_match(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query_array(jsonb, jsonpath[, jsonb, bool]). * jsonb_path_query_first(jsonb, jsonpath[, jsonb, bool]). This commit also implements "jsonb @? jsonpath" and "jsonb @@ jsonpath", which are wrappers over jsonpath_exists(jsonb, jsonpath) and jsonpath_predicate(jsonb, jsonpath) correspondingly. These operators will have an index support (implemented in subsequent patches). Catversion bumped, to add new functions and operators. Code was written by Nikita Glukhov and Teodor Sigaev, revised by me. Documentation was written by Oleg Bartunov and Liudmila Mantrova. The work was inspired by Oleg Bartunov. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Author: Nikita Glukhov, Teodor Sigaev, Alexander Korotkov, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Tomas Vondra, Andrew Dunstan, Pavel Stehule, Alexander Korotkov
2019-03-16 10:15:37 +01:00
static int operationPriority(JsonPathItemType op);
/**************************** INPUT/OUTPUT ********************************/
/*
* jsonpath type input function
*/
Datum
jsonpath_in(PG_FUNCTION_ARGS)
{
char *in = PG_GETARG_CSTRING(0);
int len = strlen(in);
return jsonPathFromCstring(in, len);
}
/*
* jsonpath type recv function
*
* The type is sent as text in binary mode, so this is almost the same
* as the input function, but it's prefixed with a version number so we
* can change the binary format sent in future if necessary. For now,
* only version 1 is supported.
*/
Datum
jsonpath_recv(PG_FUNCTION_ARGS)
{
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
int version = pq_getmsgint(buf, 1);
char *str;
int nbytes;
if (version == JSONPATH_VERSION)
str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
else
elog(ERROR, "unsupported jsonpath version number: %d", version);
return jsonPathFromCstring(str, nbytes);
}
/*
* jsonpath type output function
*/
Datum
jsonpath_out(PG_FUNCTION_ARGS)
{
JsonPath *in = PG_GETARG_JSONPATH_P(0);
PG_RETURN_CSTRING(jsonPathToCstring(NULL, in, VARSIZE(in)));
}
/*
* jsonpath type send function
*
* Just send jsonpath as a version number, then a string of text
*/
Datum
jsonpath_send(PG_FUNCTION_ARGS)
{
JsonPath *in = PG_GETARG_JSONPATH_P(0);
StringInfoData buf;
StringInfoData jtext;
int version = JSONPATH_VERSION;
initStringInfo(&jtext);
(void) jsonPathToCstring(&jtext, in, VARSIZE(in));
pq_begintypsend(&buf);
pq_sendint8(&buf, version);
pq_sendtext(&buf, jtext.data, jtext.len);
pfree(jtext.data);
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
/*
* Converts C-string to a jsonpath value.
*
* Uses jsonpath parser to turn string into an AST, then
* flattenJsonPathParseItem() does second pass turning AST into binary
* representation of jsonpath.
*/
static Datum
jsonPathFromCstring(char *in, int len)
{
JsonPathParseResult *jsonpath = parsejsonpath(in, len);
JsonPath *res;
StringInfoData buf;
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)));
Partial implementation of SQL/JSON path language SQL 2016 standards among other things contains set of SQL/JSON features for JSON processing inside of relational database. The core of SQL/JSON is JSON path language, allowing access parts of JSON documents and make computations over them. This commit implements partial support JSON path language as separate datatype called "jsonpath". The implementation is partial because it's lacking datetime support and suppression of numeric errors. Missing features will be added later by separate commits. Support of SQL/JSON features requires implementation of separate nodes, and it will be considered in subsequent patches. This commit includes following set of plain functions, allowing to execute jsonpath over jsonb values: * jsonb_path_exists(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_match(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query_array(jsonb, jsonpath[, jsonb, bool]). * jsonb_path_query_first(jsonb, jsonpath[, jsonb, bool]). This commit also implements "jsonb @? jsonpath" and "jsonb @@ jsonpath", which are wrappers over jsonpath_exists(jsonb, jsonpath) and jsonpath_predicate(jsonb, jsonpath) correspondingly. These operators will have an index support (implemented in subsequent patches). Catversion bumped, to add new functions and operators. Code was written by Nikita Glukhov and Teodor Sigaev, revised by me. Documentation was written by Oleg Bartunov and Liudmila Mantrova. The work was inspired by Oleg Bartunov. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Author: Nikita Glukhov, Teodor Sigaev, Alexander Korotkov, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Tomas Vondra, Andrew Dunstan, Pavel Stehule, Alexander Korotkov
2019-03-16 10:15:37 +01:00
flattenJsonPathParseItem(&buf, jsonpath->expr, 0, false);
res = (JsonPath *) buf.data;
SET_VARSIZE(res, buf.len);
res->header = JSONPATH_VERSION;
if (jsonpath->lax)
res->header |= JSONPATH_LAX;
PG_RETURN_JSONPATH_P(res);
}
/*
* Converts jsonpath value to a C-string.
*
* If 'out' argument is non-null, the resulting C-string is stored inside the
* StringBuffer. The resulting string is always returned.
*/
static char *
jsonPathToCstring(StringInfo out, JsonPath *in, int estimated_len)
{
StringInfoData buf;
JsonPathItem v;
if (!out)
{
out = &buf;
initStringInfo(out);
}
enlargeStringInfo(out, estimated_len);
if (!(in->header & JSONPATH_LAX))
appendBinaryStringInfo(out, "strict ", 7);
jspInit(&v, in);
printJsonPathItem(out, &v, false, true);
return out->data;
}
/*
* 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)
{
/* position from beginning of jsonpath data */
Partial implementation of SQL/JSON path language SQL 2016 standards among other things contains set of SQL/JSON features for JSON processing inside of relational database. The core of SQL/JSON is JSON path language, allowing access parts of JSON documents and make computations over them. This commit implements partial support JSON path language as separate datatype called "jsonpath". The implementation is partial because it's lacking datetime support and suppression of numeric errors. Missing features will be added later by separate commits. Support of SQL/JSON features requires implementation of separate nodes, and it will be considered in subsequent patches. This commit includes following set of plain functions, allowing to execute jsonpath over jsonb values: * jsonb_path_exists(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_match(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query_array(jsonb, jsonpath[, jsonb, bool]). * jsonb_path_query_first(jsonb, jsonpath[, jsonb, bool]). This commit also implements "jsonb @? jsonpath" and "jsonb @@ jsonpath", which are wrappers over jsonpath_exists(jsonb, jsonpath) and jsonpath_predicate(jsonb, jsonpath) correspondingly. These operators will have an index support (implemented in subsequent patches). Catversion bumped, to add new functions and operators. Code was written by Nikita Glukhov and Teodor Sigaev, revised by me. Documentation was written by Oleg Bartunov and Liudmila Mantrova. The work was inspired by Oleg Bartunov. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Author: Nikita Glukhov, Teodor Sigaev, Alexander Korotkov, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Tomas Vondra, Andrew Dunstan, Pavel Stehule, Alexander Korotkov
2019-03-16 10:15:37 +01:00
int32 pos = buf->len - JSONPATH_HDRSZ;
int32 chld;
int32 next;
int argNestingLevel = 0;
check_stack_depth();
CHECK_FOR_INTERRUPTS();
appendStringInfoChar(buf, (char) (item->type));
/*
* We align buffer to int32 because a series of int32 values often goes
* after the header, and we want to read them directly by dereferencing
* int32 pointer (see jspInitByBuffer()).
*/
alignStringInfoInt(buf);
/*
* Reserve space for next item pointer. Actual value will be recorded
* later, after next and children items processing.
*/
next = reserveSpaceForItemPointer(buf);
switch (item->type)
{
case jpiString:
case jpiVariable:
case jpiKey:
appendBinaryStringInfo(buf, (char *) &item->value.string.len,
sizeof(item->value.string.len));
appendBinaryStringInfo(buf, item->value.string.val,
item->value.string.len);
appendStringInfoChar(buf, '\0');
break;
case jpiNumeric:
appendBinaryStringInfo(buf, (char *) item->value.numeric,
VARSIZE(item->value.numeric));
break;
case jpiBool:
appendBinaryStringInfo(buf, (char *) &item->value.boolean,
sizeof(item->value.boolean));
break;
case jpiAnd:
case jpiOr:
case jpiEqual:
case jpiNotEqual:
case jpiLess:
case jpiGreater:
case jpiLessOrEqual:
case jpiGreaterOrEqual:
case jpiAdd:
case jpiSub:
case jpiMul:
case jpiDiv:
case jpiMod:
case jpiStartsWith:
{
/*
* First, reserve place for left/right arg's positions, then
* record both args and sets actual position in reserved
* places.
*/
int32 left = reserveSpaceForItemPointer(buf);
int32 right = reserveSpaceForItemPointer(buf);
chld = !item->value.args.left ? pos :
flattenJsonPathParseItem(buf, item->value.args.left,
nestingLevel + argNestingLevel,
insideArraySubscript);
*(int32 *) (buf->data + left) = chld - pos;
chld = !item->value.args.right ? pos :
flattenJsonPathParseItem(buf, item->value.args.right,
nestingLevel + argNestingLevel,
insideArraySubscript);
*(int32 *) (buf->data + right) = chld - pos;
}
break;
case jpiLikeRegex:
{
int32 offs;
appendBinaryStringInfo(buf,
(char *) &item->value.like_regex.flags,
sizeof(item->value.like_regex.flags));
offs = reserveSpaceForItemPointer(buf);
appendBinaryStringInfo(buf,
(char *) &item->value.like_regex.patternlen,
sizeof(item->value.like_regex.patternlen));
appendBinaryStringInfo(buf, item->value.like_regex.pattern,
item->value.like_regex.patternlen);
appendStringInfoChar(buf, '\0');
chld = flattenJsonPathParseItem(buf, item->value.like_regex.expr,
nestingLevel,
insideArraySubscript);
*(int32 *) (buf->data + offs) = chld - pos;
}
break;
case jpiFilter:
argNestingLevel++;
/* FALLTHROUGH */
Partial implementation of SQL/JSON path language SQL 2016 standards among other things contains set of SQL/JSON features for JSON processing inside of relational database. The core of SQL/JSON is JSON path language, allowing access parts of JSON documents and make computations over them. This commit implements partial support JSON path language as separate datatype called "jsonpath". The implementation is partial because it's lacking datetime support and suppression of numeric errors. Missing features will be added later by separate commits. Support of SQL/JSON features requires implementation of separate nodes, and it will be considered in subsequent patches. This commit includes following set of plain functions, allowing to execute jsonpath over jsonb values: * jsonb_path_exists(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_match(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query_array(jsonb, jsonpath[, jsonb, bool]). * jsonb_path_query_first(jsonb, jsonpath[, jsonb, bool]). This commit also implements "jsonb @? jsonpath" and "jsonb @@ jsonpath", which are wrappers over jsonpath_exists(jsonb, jsonpath) and jsonpath_predicate(jsonb, jsonpath) correspondingly. These operators will have an index support (implemented in subsequent patches). Catversion bumped, to add new functions and operators. Code was written by Nikita Glukhov and Teodor Sigaev, revised by me. Documentation was written by Oleg Bartunov and Liudmila Mantrova. The work was inspired by Oleg Bartunov. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Author: Nikita Glukhov, Teodor Sigaev, Alexander Korotkov, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Tomas Vondra, Andrew Dunstan, Pavel Stehule, Alexander Korotkov
2019-03-16 10:15:37 +01:00
case jpiIsUnknown:
case jpiNot:
case jpiPlus:
case jpiMinus:
case jpiExists:
Implement jsonpath .datetime() method This commit implements jsonpath .datetime() method as it's specified in SQL/JSON standard. There are no-argument and single-argument versions of this method. No-argument version selects first of ISO datetime formats matching input string. Single-argument version accepts template string as its argument. Additionally to .datetime() method itself this commit also implements comparison ability of resulting date and time values. There is some difficulty because exising jsonb_path_*() functions are immutable, while comparison of timezoned and non-timezoned types involves current timezone. At first, current timezone could be changes in session. Moreover, timezones themselves are not immutable and could be updated. This is why we let existing immutable functions throw errors on such non-immutable comparison. In the same time this commit provides jsonb_path_*_tz() functions which are stable and support operations involving timezones. As new functions are added to the system catalog, catversion is bumped. Support of .datetime() method was the only blocker prevents T832 from being marked as supported. sql_features.txt is updated correspondingly. Extracted from original patch by Nikita Glukhov, Teodor Sigaev, Oleg Bartunov. Heavily revised by me. Comments were adjusted by Liudmila Mantrova. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Discussion: https://postgr.es/m/CAPpHfdsZgYEra_PeCLGNoXOWYx6iU-S3wF8aX0ObQUcZU%2B4XTw%40mail.gmail.com Author: Alexander Korotkov, Nikita Glukhov, Teodor Sigaev, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Anastasia Lubennikova, Peter Eisentraut
2019-09-25 20:54:14 +02:00
case jpiDatetime:
Partial implementation of SQL/JSON path language SQL 2016 standards among other things contains set of SQL/JSON features for JSON processing inside of relational database. The core of SQL/JSON is JSON path language, allowing access parts of JSON documents and make computations over them. This commit implements partial support JSON path language as separate datatype called "jsonpath". The implementation is partial because it's lacking datetime support and suppression of numeric errors. Missing features will be added later by separate commits. Support of SQL/JSON features requires implementation of separate nodes, and it will be considered in subsequent patches. This commit includes following set of plain functions, allowing to execute jsonpath over jsonb values: * jsonb_path_exists(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_match(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query_array(jsonb, jsonpath[, jsonb, bool]). * jsonb_path_query_first(jsonb, jsonpath[, jsonb, bool]). This commit also implements "jsonb @? jsonpath" and "jsonb @@ jsonpath", which are wrappers over jsonpath_exists(jsonb, jsonpath) and jsonpath_predicate(jsonb, jsonpath) correspondingly. These operators will have an index support (implemented in subsequent patches). Catversion bumped, to add new functions and operators. Code was written by Nikita Glukhov and Teodor Sigaev, revised by me. Documentation was written by Oleg Bartunov and Liudmila Mantrova. The work was inspired by Oleg Bartunov. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Author: Nikita Glukhov, Teodor Sigaev, Alexander Korotkov, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Tomas Vondra, Andrew Dunstan, Pavel Stehule, Alexander Korotkov
2019-03-16 10:15:37 +01:00
{
int32 arg = reserveSpaceForItemPointer(buf);
Implement jsonpath .datetime() method This commit implements jsonpath .datetime() method as it's specified in SQL/JSON standard. There are no-argument and single-argument versions of this method. No-argument version selects first of ISO datetime formats matching input string. Single-argument version accepts template string as its argument. Additionally to .datetime() method itself this commit also implements comparison ability of resulting date and time values. There is some difficulty because exising jsonb_path_*() functions are immutable, while comparison of timezoned and non-timezoned types involves current timezone. At first, current timezone could be changes in session. Moreover, timezones themselves are not immutable and could be updated. This is why we let existing immutable functions throw errors on such non-immutable comparison. In the same time this commit provides jsonb_path_*_tz() functions which are stable and support operations involving timezones. As new functions are added to the system catalog, catversion is bumped. Support of .datetime() method was the only blocker prevents T832 from being marked as supported. sql_features.txt is updated correspondingly. Extracted from original patch by Nikita Glukhov, Teodor Sigaev, Oleg Bartunov. Heavily revised by me. Comments were adjusted by Liudmila Mantrova. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Discussion: https://postgr.es/m/CAPpHfdsZgYEra_PeCLGNoXOWYx6iU-S3wF8aX0ObQUcZU%2B4XTw%40mail.gmail.com Author: Alexander Korotkov, Nikita Glukhov, Teodor Sigaev, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Anastasia Lubennikova, Peter Eisentraut
2019-09-25 20:54:14 +02:00
chld = !item->value.arg ? pos :
flattenJsonPathParseItem(buf, item->value.arg,
nestingLevel + argNestingLevel,
insideArraySubscript);
Partial implementation of SQL/JSON path language SQL 2016 standards among other things contains set of SQL/JSON features for JSON processing inside of relational database. The core of SQL/JSON is JSON path language, allowing access parts of JSON documents and make computations over them. This commit implements partial support JSON path language as separate datatype called "jsonpath". The implementation is partial because it's lacking datetime support and suppression of numeric errors. Missing features will be added later by separate commits. Support of SQL/JSON features requires implementation of separate nodes, and it will be considered in subsequent patches. This commit includes following set of plain functions, allowing to execute jsonpath over jsonb values: * jsonb_path_exists(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_match(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query_array(jsonb, jsonpath[, jsonb, bool]). * jsonb_path_query_first(jsonb, jsonpath[, jsonb, bool]). This commit also implements "jsonb @? jsonpath" and "jsonb @@ jsonpath", which are wrappers over jsonpath_exists(jsonb, jsonpath) and jsonpath_predicate(jsonb, jsonpath) correspondingly. These operators will have an index support (implemented in subsequent patches). Catversion bumped, to add new functions and operators. Code was written by Nikita Glukhov and Teodor Sigaev, revised by me. Documentation was written by Oleg Bartunov and Liudmila Mantrova. The work was inspired by Oleg Bartunov. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Author: Nikita Glukhov, Teodor Sigaev, Alexander Korotkov, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Tomas Vondra, Andrew Dunstan, Pavel Stehule, Alexander Korotkov
2019-03-16 10:15:37 +01:00
*(int32 *) (buf->data + arg) = chld - pos;
}
break;
case jpiNull:
break;
case jpiRoot:
break;
case jpiAnyArray:
case jpiAnyKey:
break;
case jpiCurrent:
if (nestingLevel <= 0)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("@ is not allowed in root expressions")));
break;
case jpiLast:
if (!insideArraySubscript)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("LAST is allowed only in array subscripts")));
break;
case jpiIndexArray:
{
int32 nelems = item->value.array.nelems;
int offset;
int i;
appendBinaryStringInfo(buf, (char *) &nelems, sizeof(nelems));
offset = buf->len;
appendStringInfoSpaces(buf, sizeof(int32) * 2 * nelems);
for (i = 0; i < nelems; i++)
{
int32 *ppos;
int32 topos;
int32 frompos =
flattenJsonPathParseItem(buf,
item->value.array.elems[i].from,
nestingLevel, true) - pos;
if (item->value.array.elems[i].to)
topos = flattenJsonPathParseItem(buf,
item->value.array.elems[i].to,
nestingLevel, true) - pos;
else
topos = 0;
ppos = (int32 *) &buf->data[offset + i * 2 * sizeof(int32)];
ppos[0] = frompos;
ppos[1] = topos;
}
}
break;
case jpiAny:
appendBinaryStringInfo(buf,
(char *) &item->value.anybounds.first,
sizeof(item->value.anybounds.first));
appendBinaryStringInfo(buf,
(char *) &item->value.anybounds.last,
sizeof(item->value.anybounds.last));
break;
case jpiType:
case jpiSize:
case jpiAbs:
case jpiFloor:
case jpiCeiling:
case jpiDouble:
case jpiKeyValue:
break;
default:
elog(ERROR, "unrecognized jsonpath item type: %d", item->type);
}
if (item->next)
{
chld = flattenJsonPathParseItem(buf, item->next, nestingLevel,
insideArraySubscript) - pos;
*(int32 *) (buf->data + next) = chld;
}
return pos;
}
/*
* Align StringInfo to int by adding zero padding bytes
*/
static void
alignStringInfoInt(StringInfo buf)
{
switch (INTALIGN(buf->len) - buf->len)
{
case 3:
appendStringInfoCharMacro(buf, 0);
/* FALLTHROUGH */
Partial implementation of SQL/JSON path language SQL 2016 standards among other things contains set of SQL/JSON features for JSON processing inside of relational database. The core of SQL/JSON is JSON path language, allowing access parts of JSON documents and make computations over them. This commit implements partial support JSON path language as separate datatype called "jsonpath". The implementation is partial because it's lacking datetime support and suppression of numeric errors. Missing features will be added later by separate commits. Support of SQL/JSON features requires implementation of separate nodes, and it will be considered in subsequent patches. This commit includes following set of plain functions, allowing to execute jsonpath over jsonb values: * jsonb_path_exists(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_match(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query_array(jsonb, jsonpath[, jsonb, bool]). * jsonb_path_query_first(jsonb, jsonpath[, jsonb, bool]). This commit also implements "jsonb @? jsonpath" and "jsonb @@ jsonpath", which are wrappers over jsonpath_exists(jsonb, jsonpath) and jsonpath_predicate(jsonb, jsonpath) correspondingly. These operators will have an index support (implemented in subsequent patches). Catversion bumped, to add new functions and operators. Code was written by Nikita Glukhov and Teodor Sigaev, revised by me. Documentation was written by Oleg Bartunov and Liudmila Mantrova. The work was inspired by Oleg Bartunov. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Author: Nikita Glukhov, Teodor Sigaev, Alexander Korotkov, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Tomas Vondra, Andrew Dunstan, Pavel Stehule, Alexander Korotkov
2019-03-16 10:15:37 +01:00
case 2:
appendStringInfoCharMacro(buf, 0);
/* FALLTHROUGH */
Partial implementation of SQL/JSON path language SQL 2016 standards among other things contains set of SQL/JSON features for JSON processing inside of relational database. The core of SQL/JSON is JSON path language, allowing access parts of JSON documents and make computations over them. This commit implements partial support JSON path language as separate datatype called "jsonpath". The implementation is partial because it's lacking datetime support and suppression of numeric errors. Missing features will be added later by separate commits. Support of SQL/JSON features requires implementation of separate nodes, and it will be considered in subsequent patches. This commit includes following set of plain functions, allowing to execute jsonpath over jsonb values: * jsonb_path_exists(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_match(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query_array(jsonb, jsonpath[, jsonb, bool]). * jsonb_path_query_first(jsonb, jsonpath[, jsonb, bool]). This commit also implements "jsonb @? jsonpath" and "jsonb @@ jsonpath", which are wrappers over jsonpath_exists(jsonb, jsonpath) and jsonpath_predicate(jsonb, jsonpath) correspondingly. These operators will have an index support (implemented in subsequent patches). Catversion bumped, to add new functions and operators. Code was written by Nikita Glukhov and Teodor Sigaev, revised by me. Documentation was written by Oleg Bartunov and Liudmila Mantrova. The work was inspired by Oleg Bartunov. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Author: Nikita Glukhov, Teodor Sigaev, Alexander Korotkov, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Tomas Vondra, Andrew Dunstan, Pavel Stehule, Alexander Korotkov
2019-03-16 10:15:37 +01:00
case 1:
appendStringInfoCharMacro(buf, 0);
/* FALLTHROUGH */
Partial implementation of SQL/JSON path language SQL 2016 standards among other things contains set of SQL/JSON features for JSON processing inside of relational database. The core of SQL/JSON is JSON path language, allowing access parts of JSON documents and make computations over them. This commit implements partial support JSON path language as separate datatype called "jsonpath". The implementation is partial because it's lacking datetime support and suppression of numeric errors. Missing features will be added later by separate commits. Support of SQL/JSON features requires implementation of separate nodes, and it will be considered in subsequent patches. This commit includes following set of plain functions, allowing to execute jsonpath over jsonb values: * jsonb_path_exists(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_match(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query_array(jsonb, jsonpath[, jsonb, bool]). * jsonb_path_query_first(jsonb, jsonpath[, jsonb, bool]). This commit also implements "jsonb @? jsonpath" and "jsonb @@ jsonpath", which are wrappers over jsonpath_exists(jsonb, jsonpath) and jsonpath_predicate(jsonb, jsonpath) correspondingly. These operators will have an index support (implemented in subsequent patches). Catversion bumped, to add new functions and operators. Code was written by Nikita Glukhov and Teodor Sigaev, revised by me. Documentation was written by Oleg Bartunov and Liudmila Mantrova. The work was inspired by Oleg Bartunov. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Author: Nikita Glukhov, Teodor Sigaev, Alexander Korotkov, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Tomas Vondra, Andrew Dunstan, Pavel Stehule, Alexander Korotkov
2019-03-16 10:15:37 +01:00
default:
break;
}
}
/*
* Reserve space for int32 JsonPathItem pointer. Now zero pointer is written,
* actual value will be recorded at '(int32 *) &buf->data[pos]' later.
*/
static int32
reserveSpaceForItemPointer(StringInfo buf)
{
int32 pos = buf->len;
int32 ptr = 0;
appendBinaryStringInfo(buf, (char *) &ptr, sizeof(ptr));
return pos;
}
/*
* Prints text representation of given jsonpath item and all its children.
*/
static void
printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey,
bool printBracketes)
{
JsonPathItem elem;
int i;
check_stack_depth();
CHECK_FOR_INTERRUPTS();
switch (v->type)
{
case jpiNull:
appendStringInfoString(buf, "null");
break;
case jpiKey:
if (inKey)
appendStringInfoChar(buf, '.');
escape_json(buf, jspGetString(v, NULL));
break;
case jpiString:
escape_json(buf, jspGetString(v, NULL));
break;
case jpiVariable:
appendStringInfoChar(buf, '$');
escape_json(buf, jspGetString(v, NULL));
break;
case jpiNumeric:
appendStringInfoString(buf,
DatumGetCString(DirectFunctionCall1(numeric_out,
NumericGetDatum(jspGetNumeric(v)))));
Partial implementation of SQL/JSON path language SQL 2016 standards among other things contains set of SQL/JSON features for JSON processing inside of relational database. The core of SQL/JSON is JSON path language, allowing access parts of JSON documents and make computations over them. This commit implements partial support JSON path language as separate datatype called "jsonpath". The implementation is partial because it's lacking datetime support and suppression of numeric errors. Missing features will be added later by separate commits. Support of SQL/JSON features requires implementation of separate nodes, and it will be considered in subsequent patches. This commit includes following set of plain functions, allowing to execute jsonpath over jsonb values: * jsonb_path_exists(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_match(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query_array(jsonb, jsonpath[, jsonb, bool]). * jsonb_path_query_first(jsonb, jsonpath[, jsonb, bool]). This commit also implements "jsonb @? jsonpath" and "jsonb @@ jsonpath", which are wrappers over jsonpath_exists(jsonb, jsonpath) and jsonpath_predicate(jsonb, jsonpath) correspondingly. These operators will have an index support (implemented in subsequent patches). Catversion bumped, to add new functions and operators. Code was written by Nikita Glukhov and Teodor Sigaev, revised by me. Documentation was written by Oleg Bartunov and Liudmila Mantrova. The work was inspired by Oleg Bartunov. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Author: Nikita Glukhov, Teodor Sigaev, Alexander Korotkov, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Tomas Vondra, Andrew Dunstan, Pavel Stehule, Alexander Korotkov
2019-03-16 10:15:37 +01:00
break;
case jpiBool:
if (jspGetBool(v))
appendBinaryStringInfo(buf, "true", 4);
else
appendBinaryStringInfo(buf, "false", 5);
break;
case jpiAnd:
case jpiOr:
case jpiEqual:
case jpiNotEqual:
case jpiLess:
case jpiGreater:
case jpiLessOrEqual:
case jpiGreaterOrEqual:
case jpiAdd:
case jpiSub:
case jpiMul:
case jpiDiv:
case jpiMod:
case jpiStartsWith:
if (printBracketes)
appendStringInfoChar(buf, '(');
jspGetLeftArg(v, &elem);
printJsonPathItem(buf, &elem, false,
operationPriority(elem.type) <=
operationPriority(v->type));
appendStringInfoChar(buf, ' ');
appendStringInfoString(buf, jspOperationName(v->type));
appendStringInfoChar(buf, ' ');
jspGetRightArg(v, &elem);
printJsonPathItem(buf, &elem, false,
operationPriority(elem.type) <=
operationPriority(v->type));
if (printBracketes)
appendStringInfoChar(buf, ')');
break;
case jpiLikeRegex:
if (printBracketes)
appendStringInfoChar(buf, '(');
jspInitByBuffer(&elem, v->base, v->content.like_regex.expr);
printJsonPathItem(buf, &elem, false,
operationPriority(elem.type) <=
operationPriority(v->type));
appendBinaryStringInfo(buf, " like_regex ", 12);
escape_json(buf, v->content.like_regex.pattern);
if (v->content.like_regex.flags)
{
appendBinaryStringInfo(buf, " flag \"", 7);
if (v->content.like_regex.flags & JSP_REGEX_ICASE)
appendStringInfoChar(buf, 'i');
Fix bogus handling of XQuery regex option flags. The SQL spec defers to XQuery to define what the option flags are for LIKE_REGEX patterns. XQuery says that: * 's' allows the dot character to match newlines, which by default it will not; * 'm' allows ^ and $ to match at newlines, not only at the start/end of the whole string. Thus, these are *not* inverses as they are for the similarly-named POSIX options, and neither one corresponds to the POSIX 'n' option. Fortunately, Spencer's library does expose these two behaviors as separately twiddlable flags, so we just have to fix the mapping from JSP flag bits to REG flag bits. I also chose to rename the symbol for 's' to DOTALL, to make it clearer that it's not the inverse of MLINE. Also, XQuery says that if the 'q' flag "is used together with the m, s, or x flag, that flag has no effect". I read this as saying that 'q' overrides the other flags; whoever wrote our code seems to have read it backwards. Lastly, while XQuery's 'x' flag is related to what Spencer's code does for REG_EXPANDED, it's not the same or a subset. It seems best to treat XQuery's 'x' as unimplemented for now. Maybe later we can expand our regex code to offer 'x'-style parsing as a separate option. While at it, refactor the jsonpath code so that (a) there's only one copy of the flag transformation logic not two, and (b) the processing of flags is independent of the order in which the flags are written. We need some documentation updates to go with this, but I'll tackle that separately. Back-patch to v12 where this code originated. Discussion: https://postgr.es/m/CAPpHfdvDci4iqNF9fhRkTqhe-5_8HmzeLt56drH%2B_Rv2rNRqfg@mail.gmail.com Reference: https://www.w3.org/TR/2017/REC-xpath-functions-31-20170321/#flags
2019-09-17 21:39:51 +02:00
if (v->content.like_regex.flags & JSP_REGEX_DOTALL)
Partial implementation of SQL/JSON path language SQL 2016 standards among other things contains set of SQL/JSON features for JSON processing inside of relational database. The core of SQL/JSON is JSON path language, allowing access parts of JSON documents and make computations over them. This commit implements partial support JSON path language as separate datatype called "jsonpath". The implementation is partial because it's lacking datetime support and suppression of numeric errors. Missing features will be added later by separate commits. Support of SQL/JSON features requires implementation of separate nodes, and it will be considered in subsequent patches. This commit includes following set of plain functions, allowing to execute jsonpath over jsonb values: * jsonb_path_exists(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_match(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query_array(jsonb, jsonpath[, jsonb, bool]). * jsonb_path_query_first(jsonb, jsonpath[, jsonb, bool]). This commit also implements "jsonb @? jsonpath" and "jsonb @@ jsonpath", which are wrappers over jsonpath_exists(jsonb, jsonpath) and jsonpath_predicate(jsonb, jsonpath) correspondingly. These operators will have an index support (implemented in subsequent patches). Catversion bumped, to add new functions and operators. Code was written by Nikita Glukhov and Teodor Sigaev, revised by me. Documentation was written by Oleg Bartunov and Liudmila Mantrova. The work was inspired by Oleg Bartunov. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Author: Nikita Glukhov, Teodor Sigaev, Alexander Korotkov, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Tomas Vondra, Andrew Dunstan, Pavel Stehule, Alexander Korotkov
2019-03-16 10:15:37 +01:00
appendStringInfoChar(buf, 's');
if (v->content.like_regex.flags & JSP_REGEX_MLINE)
appendStringInfoChar(buf, 'm');
if (v->content.like_regex.flags & JSP_REGEX_WSPACE)
appendStringInfoChar(buf, 'x');
if (v->content.like_regex.flags & JSP_REGEX_QUOTE)
appendStringInfoChar(buf, 'q');
Partial implementation of SQL/JSON path language SQL 2016 standards among other things contains set of SQL/JSON features for JSON processing inside of relational database. The core of SQL/JSON is JSON path language, allowing access parts of JSON documents and make computations over them. This commit implements partial support JSON path language as separate datatype called "jsonpath". The implementation is partial because it's lacking datetime support and suppression of numeric errors. Missing features will be added later by separate commits. Support of SQL/JSON features requires implementation of separate nodes, and it will be considered in subsequent patches. This commit includes following set of plain functions, allowing to execute jsonpath over jsonb values: * jsonb_path_exists(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_match(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query_array(jsonb, jsonpath[, jsonb, bool]). * jsonb_path_query_first(jsonb, jsonpath[, jsonb, bool]). This commit also implements "jsonb @? jsonpath" and "jsonb @@ jsonpath", which are wrappers over jsonpath_exists(jsonb, jsonpath) and jsonpath_predicate(jsonb, jsonpath) correspondingly. These operators will have an index support (implemented in subsequent patches). Catversion bumped, to add new functions and operators. Code was written by Nikita Glukhov and Teodor Sigaev, revised by me. Documentation was written by Oleg Bartunov and Liudmila Mantrova. The work was inspired by Oleg Bartunov. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Author: Nikita Glukhov, Teodor Sigaev, Alexander Korotkov, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Tomas Vondra, Andrew Dunstan, Pavel Stehule, Alexander Korotkov
2019-03-16 10:15:37 +01:00
appendStringInfoChar(buf, '"');
}
if (printBracketes)
appendStringInfoChar(buf, ')');
break;
case jpiPlus:
case jpiMinus:
if (printBracketes)
appendStringInfoChar(buf, '(');
appendStringInfoChar(buf, v->type == jpiPlus ? '+' : '-');
jspGetArg(v, &elem);
printJsonPathItem(buf, &elem, false,
operationPriority(elem.type) <=
operationPriority(v->type));
if (printBracketes)
appendStringInfoChar(buf, ')');
break;
case jpiFilter:
appendBinaryStringInfo(buf, "?(", 2);
jspGetArg(v, &elem);
printJsonPathItem(buf, &elem, false, false);
appendStringInfoChar(buf, ')');
break;
case jpiNot:
appendBinaryStringInfo(buf, "!(", 2);
jspGetArg(v, &elem);
printJsonPathItem(buf, &elem, false, false);
appendStringInfoChar(buf, ')');
break;
case jpiIsUnknown:
appendStringInfoChar(buf, '(');
jspGetArg(v, &elem);
printJsonPathItem(buf, &elem, false, false);
appendBinaryStringInfo(buf, ") is unknown", 12);
break;
case jpiExists:
appendBinaryStringInfo(buf, "exists (", 8);
jspGetArg(v, &elem);
printJsonPathItem(buf, &elem, false, false);
appendStringInfoChar(buf, ')');
break;
case jpiCurrent:
Assert(!inKey);
appendStringInfoChar(buf, '@');
break;
case jpiRoot:
Assert(!inKey);
appendStringInfoChar(buf, '$');
break;
case jpiLast:
appendBinaryStringInfo(buf, "last", 4);
break;
case jpiAnyArray:
appendBinaryStringInfo(buf, "[*]", 3);
break;
case jpiAnyKey:
if (inKey)
appendStringInfoChar(buf, '.');
appendStringInfoChar(buf, '*');
break;
case jpiIndexArray:
appendStringInfoChar(buf, '[');
for (i = 0; i < v->content.array.nelems; i++)
{
JsonPathItem from;
JsonPathItem to;
bool range = jspGetArraySubscript(v, &from, &to, i);
if (i)
appendStringInfoChar(buf, ',');
printJsonPathItem(buf, &from, false, false);
if (range)
{
appendBinaryStringInfo(buf, " to ", 4);
printJsonPathItem(buf, &to, false, false);
}
}
appendStringInfoChar(buf, ']');
break;
case jpiAny:
if (inKey)
appendStringInfoChar(buf, '.');
if (v->content.anybounds.first == 0 &&
v->content.anybounds.last == PG_UINT32_MAX)
appendBinaryStringInfo(buf, "**", 2);
else if (v->content.anybounds.first == v->content.anybounds.last)
{
if (v->content.anybounds.first == PG_UINT32_MAX)
appendStringInfo(buf, "**{last}");
else
appendStringInfo(buf, "**{%u}",
v->content.anybounds.first);
}
else if (v->content.anybounds.first == PG_UINT32_MAX)
appendStringInfo(buf, "**{last to %u}",
v->content.anybounds.last);
else if (v->content.anybounds.last == PG_UINT32_MAX)
appendStringInfo(buf, "**{%u to last}",
v->content.anybounds.first);
else
appendStringInfo(buf, "**{%u to %u}",
v->content.anybounds.first,
v->content.anybounds.last);
break;
case jpiType:
appendBinaryStringInfo(buf, ".type()", 7);
break;
case jpiSize:
appendBinaryStringInfo(buf, ".size()", 7);
break;
case jpiAbs:
appendBinaryStringInfo(buf, ".abs()", 6);
break;
case jpiFloor:
appendBinaryStringInfo(buf, ".floor()", 8);
break;
case jpiCeiling:
appendBinaryStringInfo(buf, ".ceiling()", 10);
break;
case jpiDouble:
appendBinaryStringInfo(buf, ".double()", 9);
break;
Implement jsonpath .datetime() method This commit implements jsonpath .datetime() method as it's specified in SQL/JSON standard. There are no-argument and single-argument versions of this method. No-argument version selects first of ISO datetime formats matching input string. Single-argument version accepts template string as its argument. Additionally to .datetime() method itself this commit also implements comparison ability of resulting date and time values. There is some difficulty because exising jsonb_path_*() functions are immutable, while comparison of timezoned and non-timezoned types involves current timezone. At first, current timezone could be changes in session. Moreover, timezones themselves are not immutable and could be updated. This is why we let existing immutable functions throw errors on such non-immutable comparison. In the same time this commit provides jsonb_path_*_tz() functions which are stable and support operations involving timezones. As new functions are added to the system catalog, catversion is bumped. Support of .datetime() method was the only blocker prevents T832 from being marked as supported. sql_features.txt is updated correspondingly. Extracted from original patch by Nikita Glukhov, Teodor Sigaev, Oleg Bartunov. Heavily revised by me. Comments were adjusted by Liudmila Mantrova. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Discussion: https://postgr.es/m/CAPpHfdsZgYEra_PeCLGNoXOWYx6iU-S3wF8aX0ObQUcZU%2B4XTw%40mail.gmail.com Author: Alexander Korotkov, Nikita Glukhov, Teodor Sigaev, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Anastasia Lubennikova, Peter Eisentraut
2019-09-25 20:54:14 +02:00
case jpiDatetime:
appendBinaryStringInfo(buf, ".datetime(", 10);
if (v->content.arg)
{
jspGetArg(v, &elem);
printJsonPathItem(buf, &elem, false, false);
}
appendStringInfoChar(buf, ')');
break;
Partial implementation of SQL/JSON path language SQL 2016 standards among other things contains set of SQL/JSON features for JSON processing inside of relational database. The core of SQL/JSON is JSON path language, allowing access parts of JSON documents and make computations over them. This commit implements partial support JSON path language as separate datatype called "jsonpath". The implementation is partial because it's lacking datetime support and suppression of numeric errors. Missing features will be added later by separate commits. Support of SQL/JSON features requires implementation of separate nodes, and it will be considered in subsequent patches. This commit includes following set of plain functions, allowing to execute jsonpath over jsonb values: * jsonb_path_exists(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_match(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query_array(jsonb, jsonpath[, jsonb, bool]). * jsonb_path_query_first(jsonb, jsonpath[, jsonb, bool]). This commit also implements "jsonb @? jsonpath" and "jsonb @@ jsonpath", which are wrappers over jsonpath_exists(jsonb, jsonpath) and jsonpath_predicate(jsonb, jsonpath) correspondingly. These operators will have an index support (implemented in subsequent patches). Catversion bumped, to add new functions and operators. Code was written by Nikita Glukhov and Teodor Sigaev, revised by me. Documentation was written by Oleg Bartunov and Liudmila Mantrova. The work was inspired by Oleg Bartunov. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Author: Nikita Glukhov, Teodor Sigaev, Alexander Korotkov, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Tomas Vondra, Andrew Dunstan, Pavel Stehule, Alexander Korotkov
2019-03-16 10:15:37 +01:00
case jpiKeyValue:
appendBinaryStringInfo(buf, ".keyvalue()", 11);
break;
default:
elog(ERROR, "unrecognized jsonpath item type: %d", v->type);
}
if (jspGetNext(v, &elem))
printJsonPathItem(buf, &elem, true, true);
}
const char *
jspOperationName(JsonPathItemType type)
{
switch (type)
{
case jpiAnd:
return "&&";
case jpiOr:
return "||";
case jpiEqual:
return "==";
case jpiNotEqual:
return "!=";
case jpiLess:
return "<";
case jpiGreater:
return ">";
case jpiLessOrEqual:
return "<=";
case jpiGreaterOrEqual:
return ">=";
case jpiPlus:
case jpiAdd:
return "+";
case jpiMinus:
case jpiSub:
return "-";
case jpiMul:
return "*";
case jpiDiv:
return "/";
case jpiMod:
return "%";
case jpiStartsWith:
return "starts with";
case jpiLikeRegex:
return "like_regex";
case jpiType:
return "type";
case jpiSize:
return "size";
case jpiKeyValue:
return "keyvalue";
case jpiDouble:
return "double";
case jpiAbs:
return "abs";
case jpiFloor:
return "floor";
case jpiCeiling:
return "ceiling";
Implement jsonpath .datetime() method This commit implements jsonpath .datetime() method as it's specified in SQL/JSON standard. There are no-argument and single-argument versions of this method. No-argument version selects first of ISO datetime formats matching input string. Single-argument version accepts template string as its argument. Additionally to .datetime() method itself this commit also implements comparison ability of resulting date and time values. There is some difficulty because exising jsonb_path_*() functions are immutable, while comparison of timezoned and non-timezoned types involves current timezone. At first, current timezone could be changes in session. Moreover, timezones themselves are not immutable and could be updated. This is why we let existing immutable functions throw errors on such non-immutable comparison. In the same time this commit provides jsonb_path_*_tz() functions which are stable and support operations involving timezones. As new functions are added to the system catalog, catversion is bumped. Support of .datetime() method was the only blocker prevents T832 from being marked as supported. sql_features.txt is updated correspondingly. Extracted from original patch by Nikita Glukhov, Teodor Sigaev, Oleg Bartunov. Heavily revised by me. Comments were adjusted by Liudmila Mantrova. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Discussion: https://postgr.es/m/CAPpHfdsZgYEra_PeCLGNoXOWYx6iU-S3wF8aX0ObQUcZU%2B4XTw%40mail.gmail.com Author: Alexander Korotkov, Nikita Glukhov, Teodor Sigaev, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Anastasia Lubennikova, Peter Eisentraut
2019-09-25 20:54:14 +02:00
case jpiDatetime:
return "datetime";
Partial implementation of SQL/JSON path language SQL 2016 standards among other things contains set of SQL/JSON features for JSON processing inside of relational database. The core of SQL/JSON is JSON path language, allowing access parts of JSON documents and make computations over them. This commit implements partial support JSON path language as separate datatype called "jsonpath". The implementation is partial because it's lacking datetime support and suppression of numeric errors. Missing features will be added later by separate commits. Support of SQL/JSON features requires implementation of separate nodes, and it will be considered in subsequent patches. This commit includes following set of plain functions, allowing to execute jsonpath over jsonb values: * jsonb_path_exists(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_match(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query_array(jsonb, jsonpath[, jsonb, bool]). * jsonb_path_query_first(jsonb, jsonpath[, jsonb, bool]). This commit also implements "jsonb @? jsonpath" and "jsonb @@ jsonpath", which are wrappers over jsonpath_exists(jsonb, jsonpath) and jsonpath_predicate(jsonb, jsonpath) correspondingly. These operators will have an index support (implemented in subsequent patches). Catversion bumped, to add new functions and operators. Code was written by Nikita Glukhov and Teodor Sigaev, revised by me. Documentation was written by Oleg Bartunov and Liudmila Mantrova. The work was inspired by Oleg Bartunov. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Author: Nikita Glukhov, Teodor Sigaev, Alexander Korotkov, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Tomas Vondra, Andrew Dunstan, Pavel Stehule, Alexander Korotkov
2019-03-16 10:15:37 +01:00
default:
elog(ERROR, "unrecognized jsonpath item type: %d", type);
return NULL;
}
}
static int
operationPriority(JsonPathItemType op)
{
switch (op)
{
case jpiOr:
return 0;
case jpiAnd:
return 1;
case jpiEqual:
case jpiNotEqual:
case jpiLess:
case jpiGreater:
case jpiLessOrEqual:
case jpiGreaterOrEqual:
case jpiStartsWith:
return 2;
case jpiAdd:
case jpiSub:
return 3;
case jpiMul:
case jpiDiv:
case jpiMod:
return 4;
case jpiPlus:
case jpiMinus:
return 5;
default:
return 6;
}
}
/******************* Support functions for JsonPath *************************/
/*
* Support macros to read stored values
*/
#define read_byte(v, b, p) do { \
(v) = *(uint8*)((b) + (p)); \
(p) += 1; \
} while(0) \
#define read_int32(v, b, p) do { \
(v) = *(uint32*)((b) + (p)); \
(p) += sizeof(int32); \
} while(0) \
#define read_int32_n(v, b, p, n) do { \
(v) = (void *)((b) + (p)); \
(p) += sizeof(int32) * (n); \
} while(0) \
/*
* Read root node and fill root node representation
*/
void
jspInit(JsonPathItem *v, JsonPath *js)
{
Assert((js->header & ~JSONPATH_LAX) == JSONPATH_VERSION);
jspInitByBuffer(v, js->data, 0);
}
/*
* Read node from buffer and fill its representation
*/
void
jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
{
v->base = base + pos;
read_byte(v->type, base, pos);
pos = INTALIGN((uintptr_t) (base + pos)) - (uintptr_t) base;
read_int32(v->nextPos, base, pos);
switch (v->type)
{
case jpiNull:
case jpiRoot:
case jpiCurrent:
case jpiAnyArray:
case jpiAnyKey:
case jpiType:
case jpiSize:
case jpiAbs:
case jpiFloor:
case jpiCeiling:
case jpiDouble:
case jpiKeyValue:
case jpiLast:
break;
case jpiKey:
case jpiString:
case jpiVariable:
read_int32(v->content.value.datalen, base, pos);
/* FALLTHROUGH */
Partial implementation of SQL/JSON path language SQL 2016 standards among other things contains set of SQL/JSON features for JSON processing inside of relational database. The core of SQL/JSON is JSON path language, allowing access parts of JSON documents and make computations over them. This commit implements partial support JSON path language as separate datatype called "jsonpath". The implementation is partial because it's lacking datetime support and suppression of numeric errors. Missing features will be added later by separate commits. Support of SQL/JSON features requires implementation of separate nodes, and it will be considered in subsequent patches. This commit includes following set of plain functions, allowing to execute jsonpath over jsonb values: * jsonb_path_exists(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_match(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query_array(jsonb, jsonpath[, jsonb, bool]). * jsonb_path_query_first(jsonb, jsonpath[, jsonb, bool]). This commit also implements "jsonb @? jsonpath" and "jsonb @@ jsonpath", which are wrappers over jsonpath_exists(jsonb, jsonpath) and jsonpath_predicate(jsonb, jsonpath) correspondingly. These operators will have an index support (implemented in subsequent patches). Catversion bumped, to add new functions and operators. Code was written by Nikita Glukhov and Teodor Sigaev, revised by me. Documentation was written by Oleg Bartunov and Liudmila Mantrova. The work was inspired by Oleg Bartunov. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Author: Nikita Glukhov, Teodor Sigaev, Alexander Korotkov, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Tomas Vondra, Andrew Dunstan, Pavel Stehule, Alexander Korotkov
2019-03-16 10:15:37 +01:00
case jpiNumeric:
case jpiBool:
v->content.value.data = base + pos;
break;
case jpiAnd:
case jpiOr:
case jpiAdd:
case jpiSub:
case jpiMul:
case jpiDiv:
case jpiMod:
case jpiEqual:
case jpiNotEqual:
case jpiLess:
case jpiGreater:
case jpiLessOrEqual:
case jpiGreaterOrEqual:
case jpiStartsWith:
read_int32(v->content.args.left, base, pos);
read_int32(v->content.args.right, base, pos);
break;
case jpiLikeRegex:
read_int32(v->content.like_regex.flags, base, pos);
read_int32(v->content.like_regex.expr, base, pos);
read_int32(v->content.like_regex.patternlen, base, pos);
v->content.like_regex.pattern = base + pos;
break;
case jpiNot:
case jpiExists:
case jpiIsUnknown:
case jpiPlus:
case jpiMinus:
case jpiFilter:
Implement jsonpath .datetime() method This commit implements jsonpath .datetime() method as it's specified in SQL/JSON standard. There are no-argument and single-argument versions of this method. No-argument version selects first of ISO datetime formats matching input string. Single-argument version accepts template string as its argument. Additionally to .datetime() method itself this commit also implements comparison ability of resulting date and time values. There is some difficulty because exising jsonb_path_*() functions are immutable, while comparison of timezoned and non-timezoned types involves current timezone. At first, current timezone could be changes in session. Moreover, timezones themselves are not immutable and could be updated. This is why we let existing immutable functions throw errors on such non-immutable comparison. In the same time this commit provides jsonb_path_*_tz() functions which are stable and support operations involving timezones. As new functions are added to the system catalog, catversion is bumped. Support of .datetime() method was the only blocker prevents T832 from being marked as supported. sql_features.txt is updated correspondingly. Extracted from original patch by Nikita Glukhov, Teodor Sigaev, Oleg Bartunov. Heavily revised by me. Comments were adjusted by Liudmila Mantrova. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Discussion: https://postgr.es/m/CAPpHfdsZgYEra_PeCLGNoXOWYx6iU-S3wF8aX0ObQUcZU%2B4XTw%40mail.gmail.com Author: Alexander Korotkov, Nikita Glukhov, Teodor Sigaev, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Anastasia Lubennikova, Peter Eisentraut
2019-09-25 20:54:14 +02:00
case jpiDatetime:
Partial implementation of SQL/JSON path language SQL 2016 standards among other things contains set of SQL/JSON features for JSON processing inside of relational database. The core of SQL/JSON is JSON path language, allowing access parts of JSON documents and make computations over them. This commit implements partial support JSON path language as separate datatype called "jsonpath". The implementation is partial because it's lacking datetime support and suppression of numeric errors. Missing features will be added later by separate commits. Support of SQL/JSON features requires implementation of separate nodes, and it will be considered in subsequent patches. This commit includes following set of plain functions, allowing to execute jsonpath over jsonb values: * jsonb_path_exists(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_match(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query_array(jsonb, jsonpath[, jsonb, bool]). * jsonb_path_query_first(jsonb, jsonpath[, jsonb, bool]). This commit also implements "jsonb @? jsonpath" and "jsonb @@ jsonpath", which are wrappers over jsonpath_exists(jsonb, jsonpath) and jsonpath_predicate(jsonb, jsonpath) correspondingly. These operators will have an index support (implemented in subsequent patches). Catversion bumped, to add new functions and operators. Code was written by Nikita Glukhov and Teodor Sigaev, revised by me. Documentation was written by Oleg Bartunov and Liudmila Mantrova. The work was inspired by Oleg Bartunov. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Author: Nikita Glukhov, Teodor Sigaev, Alexander Korotkov, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Tomas Vondra, Andrew Dunstan, Pavel Stehule, Alexander Korotkov
2019-03-16 10:15:37 +01:00
read_int32(v->content.arg, base, pos);
break;
case jpiIndexArray:
read_int32(v->content.array.nelems, base, pos);
read_int32_n(v->content.array.elems, base, pos,
v->content.array.nelems * 2);
break;
case jpiAny:
read_int32(v->content.anybounds.first, base, pos);
read_int32(v->content.anybounds.last, base, pos);
break;
default:
elog(ERROR, "unrecognized jsonpath item type: %d", v->type);
}
}
void
jspGetArg(JsonPathItem *v, JsonPathItem *a)
{
Assert(v->type == jpiFilter ||
v->type == jpiNot ||
v->type == jpiIsUnknown ||
v->type == jpiExists ||
v->type == jpiPlus ||
Implement jsonpath .datetime() method This commit implements jsonpath .datetime() method as it's specified in SQL/JSON standard. There are no-argument and single-argument versions of this method. No-argument version selects first of ISO datetime formats matching input string. Single-argument version accepts template string as its argument. Additionally to .datetime() method itself this commit also implements comparison ability of resulting date and time values. There is some difficulty because exising jsonb_path_*() functions are immutable, while comparison of timezoned and non-timezoned types involves current timezone. At first, current timezone could be changes in session. Moreover, timezones themselves are not immutable and could be updated. This is why we let existing immutable functions throw errors on such non-immutable comparison. In the same time this commit provides jsonb_path_*_tz() functions which are stable and support operations involving timezones. As new functions are added to the system catalog, catversion is bumped. Support of .datetime() method was the only blocker prevents T832 from being marked as supported. sql_features.txt is updated correspondingly. Extracted from original patch by Nikita Glukhov, Teodor Sigaev, Oleg Bartunov. Heavily revised by me. Comments were adjusted by Liudmila Mantrova. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Discussion: https://postgr.es/m/CAPpHfdsZgYEra_PeCLGNoXOWYx6iU-S3wF8aX0ObQUcZU%2B4XTw%40mail.gmail.com Author: Alexander Korotkov, Nikita Glukhov, Teodor Sigaev, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Anastasia Lubennikova, Peter Eisentraut
2019-09-25 20:54:14 +02:00
v->type == jpiMinus ||
v->type == jpiDatetime);
Partial implementation of SQL/JSON path language SQL 2016 standards among other things contains set of SQL/JSON features for JSON processing inside of relational database. The core of SQL/JSON is JSON path language, allowing access parts of JSON documents and make computations over them. This commit implements partial support JSON path language as separate datatype called "jsonpath". The implementation is partial because it's lacking datetime support and suppression of numeric errors. Missing features will be added later by separate commits. Support of SQL/JSON features requires implementation of separate nodes, and it will be considered in subsequent patches. This commit includes following set of plain functions, allowing to execute jsonpath over jsonb values: * jsonb_path_exists(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_match(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query_array(jsonb, jsonpath[, jsonb, bool]). * jsonb_path_query_first(jsonb, jsonpath[, jsonb, bool]). This commit also implements "jsonb @? jsonpath" and "jsonb @@ jsonpath", which are wrappers over jsonpath_exists(jsonb, jsonpath) and jsonpath_predicate(jsonb, jsonpath) correspondingly. These operators will have an index support (implemented in subsequent patches). Catversion bumped, to add new functions and operators. Code was written by Nikita Glukhov and Teodor Sigaev, revised by me. Documentation was written by Oleg Bartunov and Liudmila Mantrova. The work was inspired by Oleg Bartunov. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Author: Nikita Glukhov, Teodor Sigaev, Alexander Korotkov, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Tomas Vondra, Andrew Dunstan, Pavel Stehule, Alexander Korotkov
2019-03-16 10:15:37 +01:00
jspInitByBuffer(a, v->base, v->content.arg);
}
bool
jspGetNext(JsonPathItem *v, JsonPathItem *a)
{
if (jspHasNext(v))
{
Assert(v->type == jpiString ||
v->type == jpiNumeric ||
v->type == jpiBool ||
v->type == jpiNull ||
v->type == jpiKey ||
v->type == jpiAny ||
v->type == jpiAnyArray ||
v->type == jpiAnyKey ||
v->type == jpiIndexArray ||
v->type == jpiFilter ||
v->type == jpiCurrent ||
v->type == jpiExists ||
v->type == jpiRoot ||
v->type == jpiVariable ||
v->type == jpiLast ||
v->type == jpiAdd ||
v->type == jpiSub ||
v->type == jpiMul ||
v->type == jpiDiv ||
v->type == jpiMod ||
v->type == jpiPlus ||
v->type == jpiMinus ||
v->type == jpiEqual ||
v->type == jpiNotEqual ||
v->type == jpiGreater ||
v->type == jpiGreaterOrEqual ||
v->type == jpiLess ||
v->type == jpiLessOrEqual ||
v->type == jpiAnd ||
v->type == jpiOr ||
v->type == jpiNot ||
v->type == jpiIsUnknown ||
v->type == jpiType ||
v->type == jpiSize ||
v->type == jpiAbs ||
v->type == jpiFloor ||
v->type == jpiCeiling ||
v->type == jpiDouble ||
Implement jsonpath .datetime() method This commit implements jsonpath .datetime() method as it's specified in SQL/JSON standard. There are no-argument and single-argument versions of this method. No-argument version selects first of ISO datetime formats matching input string. Single-argument version accepts template string as its argument. Additionally to .datetime() method itself this commit also implements comparison ability of resulting date and time values. There is some difficulty because exising jsonb_path_*() functions are immutable, while comparison of timezoned and non-timezoned types involves current timezone. At first, current timezone could be changes in session. Moreover, timezones themselves are not immutable and could be updated. This is why we let existing immutable functions throw errors on such non-immutable comparison. In the same time this commit provides jsonb_path_*_tz() functions which are stable and support operations involving timezones. As new functions are added to the system catalog, catversion is bumped. Support of .datetime() method was the only blocker prevents T832 from being marked as supported. sql_features.txt is updated correspondingly. Extracted from original patch by Nikita Glukhov, Teodor Sigaev, Oleg Bartunov. Heavily revised by me. Comments were adjusted by Liudmila Mantrova. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Discussion: https://postgr.es/m/CAPpHfdsZgYEra_PeCLGNoXOWYx6iU-S3wF8aX0ObQUcZU%2B4XTw%40mail.gmail.com Author: Alexander Korotkov, Nikita Glukhov, Teodor Sigaev, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Anastasia Lubennikova, Peter Eisentraut
2019-09-25 20:54:14 +02:00
v->type == jpiDatetime ||
Partial implementation of SQL/JSON path language SQL 2016 standards among other things contains set of SQL/JSON features for JSON processing inside of relational database. The core of SQL/JSON is JSON path language, allowing access parts of JSON documents and make computations over them. This commit implements partial support JSON path language as separate datatype called "jsonpath". The implementation is partial because it's lacking datetime support and suppression of numeric errors. Missing features will be added later by separate commits. Support of SQL/JSON features requires implementation of separate nodes, and it will be considered in subsequent patches. This commit includes following set of plain functions, allowing to execute jsonpath over jsonb values: * jsonb_path_exists(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_match(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query(jsonb, jsonpath[, jsonb, bool]), * jsonb_path_query_array(jsonb, jsonpath[, jsonb, bool]). * jsonb_path_query_first(jsonb, jsonpath[, jsonb, bool]). This commit also implements "jsonb @? jsonpath" and "jsonb @@ jsonpath", which are wrappers over jsonpath_exists(jsonb, jsonpath) and jsonpath_predicate(jsonb, jsonpath) correspondingly. These operators will have an index support (implemented in subsequent patches). Catversion bumped, to add new functions and operators. Code was written by Nikita Glukhov and Teodor Sigaev, revised by me. Documentation was written by Oleg Bartunov and Liudmila Mantrova. The work was inspired by Oleg Bartunov. Discussion: https://postgr.es/m/fcc6fc6a-b497-f39a-923d-aa34d0c588e8%402ndQuadrant.com Author: Nikita Glukhov, Teodor Sigaev, Alexander Korotkov, Oleg Bartunov, Liudmila Mantrova Reviewed-by: Tomas Vondra, Andrew Dunstan, Pavel Stehule, Alexander Korotkov
2019-03-16 10:15:37 +01:00
v->type == jpiKeyValue ||
v->type == jpiStartsWith);
if (a)
jspInitByBuffer(a, v->base, v->nextPos);
return true;
}
return false;
}
void
jspGetLeftArg(JsonPathItem *v, JsonPathItem *a)
{
Assert(v->type == jpiAnd ||
v->type == jpiOr ||
v->type == jpiEqual ||
v->type == jpiNotEqual ||
v->type == jpiLess ||
v->type == jpiGreater ||
v->type == jpiLessOrEqual ||
v->type == jpiGreaterOrEqual ||
v->type == jpiAdd ||
v->type == jpiSub ||
v->type == jpiMul ||
v->type == jpiDiv ||
v->type == jpiMod ||
v->type == jpiStartsWith);
jspInitByBuffer(a, v->base, v->content.args.left);
}
void
jspGetRightArg(JsonPathItem *v, JsonPathItem *a)
{
Assert(v->type == jpiAnd ||
v->type == jpiOr ||
v->type == jpiEqual ||
v->type == jpiNotEqual ||
v->type == jpiLess ||
v->type == jpiGreater ||
v->type == jpiLessOrEqual ||
v->type == jpiGreaterOrEqual ||
v->type == jpiAdd ||
v->type == jpiSub ||
v->type == jpiMul ||
v->type == jpiDiv ||
v->type == jpiMod ||
v->type == jpiStartsWith);
jspInitByBuffer(a, v->base, v->content.args.right);
}
bool
jspGetBool(JsonPathItem *v)
{
Assert(v->type == jpiBool);
return (bool) *v->content.value.data;
}
Numeric
jspGetNumeric(JsonPathItem *v)
{
Assert(v->type == jpiNumeric);
return (Numeric) v->content.value.data;
}
char *
jspGetString(JsonPathItem *v, int32 *len)
{
Assert(v->type == jpiKey ||
v->type == jpiString ||
v->type == jpiVariable);
if (len)
*len = v->content.value.datalen;
return v->content.value.data;
}
bool
jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from, JsonPathItem *to,
int i)
{
Assert(v->type == jpiIndexArray);
jspInitByBuffer(from, v->base, v->content.array.elems[i].from);
if (!v->content.array.elems[i].to)
return false;
jspInitByBuffer(to, v->base, v->content.array.elems[i].to);
return true;
}