mirror of
https://github.com/postgres/postgres.git
synced 2025-05-02 11:44:50 +03:00
Reviewed by Tom Lane Discussion: https://postgr.es/m/a8dc5700-c341-3ba8-0507-cc09881e6200@dunslane.net
265 lines
6.5 KiB
C
265 lines
6.5 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* jsonpath.h
|
|
* Definitions for jsonpath datatype
|
|
*
|
|
* Copyright (c) 2019-2022, PostgreSQL Global Development Group
|
|
*
|
|
* IDENTIFICATION
|
|
* src/include/utils/jsonpath.h
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
#ifndef JSONPATH_H
|
|
#define JSONPATH_H
|
|
|
|
#include "fmgr.h"
|
|
#include "nodes/pg_list.h"
|
|
#include "utils/jsonb.h"
|
|
|
|
typedef struct
|
|
{
|
|
int32 vl_len_; /* varlena header (do not touch directly!) */
|
|
uint32 header; /* version and flags (see below) */
|
|
char data[FLEXIBLE_ARRAY_MEMBER];
|
|
} JsonPath;
|
|
|
|
#define JSONPATH_VERSION (0x01)
|
|
#define JSONPATH_LAX (0x80000000)
|
|
#define JSONPATH_HDRSZ (offsetof(JsonPath, data))
|
|
|
|
static inline JsonPath *
|
|
DatumGetJsonPathP(Datum d)
|
|
{
|
|
return (JsonPath *) PG_DETOAST_DATUM(d);
|
|
}
|
|
|
|
static inline JsonPath *
|
|
DatumGetJsonPathPCopy(Datum d)
|
|
{
|
|
return (JsonPath *) PG_DETOAST_DATUM_COPY(d);
|
|
}
|
|
|
|
#define PG_GETARG_JSONPATH_P(x) DatumGetJsonPathP(PG_GETARG_DATUM(x))
|
|
#define PG_GETARG_JSONPATH_P_COPY(x) DatumGetJsonPathPCopy(PG_GETARG_DATUM(x))
|
|
#define PG_RETURN_JSONPATH_P(p) PG_RETURN_POINTER(p)
|
|
|
|
#define jspIsScalar(type) ((type) >= jpiNull && (type) <= jpiBool)
|
|
|
|
/*
|
|
* All node's type of jsonpath expression
|
|
*/
|
|
typedef enum JsonPathItemType
|
|
{
|
|
jpiNull = jbvNull, /* NULL literal */
|
|
jpiString = jbvString, /* string literal */
|
|
jpiNumeric = jbvNumeric, /* numeric literal */
|
|
jpiBool = jbvBool, /* boolean literal: TRUE or FALSE */
|
|
jpiAnd, /* predicate && predicate */
|
|
jpiOr, /* predicate || predicate */
|
|
jpiNot, /* ! predicate */
|
|
jpiIsUnknown, /* (predicate) IS UNKNOWN */
|
|
jpiEqual, /* expr == expr */
|
|
jpiNotEqual, /* expr != expr */
|
|
jpiLess, /* expr < expr */
|
|
jpiGreater, /* expr > expr */
|
|
jpiLessOrEqual, /* expr <= expr */
|
|
jpiGreaterOrEqual, /* expr >= expr */
|
|
jpiAdd, /* expr + expr */
|
|
jpiSub, /* expr - expr */
|
|
jpiMul, /* expr * expr */
|
|
jpiDiv, /* expr / expr */
|
|
jpiMod, /* expr % expr */
|
|
jpiPlus, /* + expr */
|
|
jpiMinus, /* - expr */
|
|
jpiAnyArray, /* [*] */
|
|
jpiAnyKey, /* .* */
|
|
jpiIndexArray, /* [subscript, ...] */
|
|
jpiAny, /* .** */
|
|
jpiKey, /* .key */
|
|
jpiCurrent, /* @ */
|
|
jpiRoot, /* $ */
|
|
jpiVariable, /* $variable */
|
|
jpiFilter, /* ? (predicate) */
|
|
jpiExists, /* EXISTS (expr) predicate */
|
|
jpiType, /* .type() item method */
|
|
jpiSize, /* .size() item method */
|
|
jpiAbs, /* .abs() item method */
|
|
jpiFloor, /* .floor() item method */
|
|
jpiCeiling, /* .ceiling() item method */
|
|
jpiDouble, /* .double() item method */
|
|
jpiDatetime, /* .datetime() item method */
|
|
jpiKeyValue, /* .keyvalue() item method */
|
|
jpiSubscript, /* array subscript: 'expr' or 'expr TO expr' */
|
|
jpiLast, /* LAST array subscript */
|
|
jpiStartsWith, /* STARTS WITH predicate */
|
|
jpiLikeRegex, /* LIKE_REGEX predicate */
|
|
} JsonPathItemType;
|
|
|
|
/* XQuery regex mode flags for LIKE_REGEX predicate */
|
|
#define JSP_REGEX_ICASE 0x01 /* i flag, case insensitive */
|
|
#define JSP_REGEX_DOTALL 0x02 /* s flag, dot matches newline */
|
|
#define JSP_REGEX_MLINE 0x04 /* m flag, ^/$ match at newlines */
|
|
#define JSP_REGEX_WSPACE 0x08 /* x flag, ignore whitespace in pattern */
|
|
#define JSP_REGEX_QUOTE 0x10 /* q flag, no special characters */
|
|
|
|
/*
|
|
* Support functions to parse/construct binary value.
|
|
* Unlike many other representation of expression the first/main
|
|
* node is not an operation but left operand of expression. That
|
|
* allows to implement cheap follow-path descending in jsonb
|
|
* structure and then execute operator with right operand
|
|
*/
|
|
|
|
typedef struct JsonPathItem
|
|
{
|
|
JsonPathItemType type;
|
|
|
|
/* position form base to next node */
|
|
int32 nextPos;
|
|
|
|
/*
|
|
* pointer into JsonPath value to current node, all positions of current
|
|
* are relative to this base
|
|
*/
|
|
char *base;
|
|
|
|
union
|
|
{
|
|
/* classic operator with two operands: and, or etc */
|
|
struct
|
|
{
|
|
int32 left;
|
|
int32 right;
|
|
} args;
|
|
|
|
/* any unary operation */
|
|
int32 arg;
|
|
|
|
/* storage for jpiIndexArray: indexes of array */
|
|
struct
|
|
{
|
|
int32 nelems;
|
|
struct
|
|
{
|
|
int32 from;
|
|
int32 to;
|
|
} *elems;
|
|
} array;
|
|
|
|
/* jpiAny: levels */
|
|
struct
|
|
{
|
|
uint32 first;
|
|
uint32 last;
|
|
} anybounds;
|
|
|
|
struct
|
|
{
|
|
char *data; /* for bool, numeric and string/key */
|
|
int32 datalen; /* filled only for string/key */
|
|
} value;
|
|
|
|
struct
|
|
{
|
|
int32 expr;
|
|
char *pattern;
|
|
int32 patternlen;
|
|
uint32 flags;
|
|
} like_regex;
|
|
} content;
|
|
} JsonPathItem;
|
|
|
|
#define jspHasNext(jsp) ((jsp)->nextPos > 0)
|
|
|
|
extern void jspInit(JsonPathItem *v, JsonPath *js);
|
|
extern void jspInitByBuffer(JsonPathItem *v, char *base, int32 pos);
|
|
extern bool jspGetNext(JsonPathItem *v, JsonPathItem *a);
|
|
extern void jspGetArg(JsonPathItem *v, JsonPathItem *a);
|
|
extern void jspGetLeftArg(JsonPathItem *v, JsonPathItem *a);
|
|
extern void jspGetRightArg(JsonPathItem *v, JsonPathItem *a);
|
|
extern Numeric jspGetNumeric(JsonPathItem *v);
|
|
extern bool jspGetBool(JsonPathItem *v);
|
|
extern char *jspGetString(JsonPathItem *v, int32 *len);
|
|
extern bool jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from,
|
|
JsonPathItem *to, int i);
|
|
|
|
extern const char *jspOperationName(JsonPathItemType type);
|
|
|
|
/*
|
|
* Parsing support data structures.
|
|
*/
|
|
|
|
typedef struct JsonPathParseItem JsonPathParseItem;
|
|
|
|
struct JsonPathParseItem
|
|
{
|
|
JsonPathItemType type;
|
|
JsonPathParseItem *next; /* next in path */
|
|
|
|
union
|
|
{
|
|
|
|
/* classic operator with two operands: and, or etc */
|
|
struct
|
|
{
|
|
JsonPathParseItem *left;
|
|
JsonPathParseItem *right;
|
|
} args;
|
|
|
|
/* any unary operation */
|
|
JsonPathParseItem *arg;
|
|
|
|
/* storage for jpiIndexArray: indexes of array */
|
|
struct
|
|
{
|
|
int nelems;
|
|
struct
|
|
{
|
|
JsonPathParseItem *from;
|
|
JsonPathParseItem *to;
|
|
} *elems;
|
|
} array;
|
|
|
|
/* jpiAny: levels */
|
|
struct
|
|
{
|
|
uint32 first;
|
|
uint32 last;
|
|
} anybounds;
|
|
|
|
struct
|
|
{
|
|
JsonPathParseItem *expr;
|
|
char *pattern; /* could not be not null-terminated */
|
|
uint32 patternlen;
|
|
uint32 flags;
|
|
} like_regex;
|
|
|
|
/* scalars */
|
|
Numeric numeric;
|
|
bool boolean;
|
|
struct
|
|
{
|
|
uint32 len;
|
|
char *val; /* could not be not null-terminated */
|
|
} string;
|
|
} value;
|
|
};
|
|
|
|
typedef struct JsonPathParseResult
|
|
{
|
|
JsonPathParseItem *expr;
|
|
bool lax;
|
|
} JsonPathParseResult;
|
|
|
|
extern JsonPathParseResult *parsejsonpath(const char *str, int len,
|
|
struct Node *escontext);
|
|
|
|
extern bool jspConvertRegexFlags(uint32 xflags, int *result,
|
|
struct Node *escontext);
|
|
|
|
|
|
#endif
|