PostgreSQL Source Code git master
Loading...
Searching...
No Matches
jsonfuncs.c File Reference
#include "postgres.h"
#include <limits.h>
#include "access/htup_details.h"
#include "catalog/pg_type.h"
#include "common/int.h"
#include "common/jsonapi.h"
#include "common/string.h"
#include "fmgr.h"
#include "funcapi.h"
#include "lib/stringinfo.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "nodes/miscnodes.h"
#include "parser/parse_coerce.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/hsearch.h"
#include "utils/json.h"
#include "utils/jsonb.h"
#include "utils/jsonfuncs.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
Include dependency graph for jsonfuncs.c:

Go to the source code of this file.

Data Structures

struct  OkeysState
 
struct  IterateJsonStringValuesState
 
struct  TransformJsonStringValuesState
 
struct  GetState
 
struct  AlenState
 
struct  EachState
 
struct  ElementsState
 
struct  JHashState
 
struct  JsonHashEntry
 
struct  ScalarIOData
 
struct  ArrayIOData
 
struct  CompositeIOData
 
struct  DomainIOData
 
struct  ColumnIOData
 
struct  RecordIOData
 
struct  PopulateRecordCache
 
struct  PopulateRecordsetState
 
struct  PopulateArrayContext
 
struct  PopulateArrayState
 
struct  StripnullState
 
struct  JsValue
 
struct  JsObject
 

Macros

#define JB_PATH_CREATE   0x0001
 
#define JB_PATH_DELETE   0x0002
 
#define JB_PATH_REPLACE   0x0004
 
#define JB_PATH_INSERT_BEFORE   0x0008
 
#define JB_PATH_INSERT_AFTER   0x0010
 
#define JB_PATH_CREATE_OR_INSERT    (JB_PATH_INSERT_BEFORE | JB_PATH_INSERT_AFTER | JB_PATH_CREATE)
 
#define JB_PATH_FILL_GAPS   0x0020
 
#define JB_PATH_CONSISTENT_POSITION   0x0040
 
#define JsValueIsNull(jsv)
 
#define JsValueIsString(jsv)
 
#define JsObjectIsEmpty(jso)
 
#define JsObjectFree(jso)
 

Typedefs

typedef struct OkeysState OkeysState
 
typedef struct IterateJsonStringValuesState IterateJsonStringValuesState
 
typedef struct TransformJsonStringValuesState TransformJsonStringValuesState
 
typedef struct GetState GetState
 
typedef struct AlenState AlenState
 
typedef struct EachState EachState
 
typedef struct ElementsState ElementsState
 
typedef struct JHashState JHashState
 
typedef struct JsonHashEntry JsonHashEntry
 
typedef struct ScalarIOData ScalarIOData
 
typedef struct ColumnIOData ColumnIOData
 
typedef struct RecordIOData RecordIOData
 
typedef struct ArrayIOData ArrayIOData
 
typedef struct CompositeIOData CompositeIOData
 
typedef struct DomainIOData DomainIOData
 
typedef enum TypeCat TypeCat
 
typedef struct PopulateRecordCache PopulateRecordCache
 
typedef struct PopulateRecordsetState PopulateRecordsetState
 
typedef struct PopulateArrayContext PopulateArrayContext
 
typedef struct PopulateArrayState PopulateArrayState
 
typedef struct StripnullState StripnullState
 
typedef struct JsValue JsValue
 
typedef struct JsObject JsObject
 

Enumerations

enum  TypeCat {
  TYPECAT_SCALAR = 's' , TYPECAT_ARRAY = 'a' , TYPECAT_COMPOSITE = 'c' , TYPECAT_COMPOSITE_DOMAIN = 'C' ,
  TYPECAT_DOMAIN = 'd'
}
 

Functions

static int report_json_context (JsonLexContext *lex)
 
static JsonParseErrorType okeys_object_field_start (void *state, char *fname, bool isnull)
 
static JsonParseErrorType okeys_array_start (void *state)
 
static JsonParseErrorType okeys_scalar (void *state, char *token, JsonTokenType tokentype)
 
static JsonParseErrorType get_object_start (void *state)
 
static JsonParseErrorType get_object_end (void *state)
 
static JsonParseErrorType get_object_field_start (void *state, char *fname, bool isnull)
 
static JsonParseErrorType get_object_field_end (void *state, char *fname, bool isnull)
 
static JsonParseErrorType get_array_start (void *state)
 
static JsonParseErrorType get_array_end (void *state)
 
static JsonParseErrorType get_array_element_start (void *state, bool isnull)
 
static JsonParseErrorType get_array_element_end (void *state, bool isnull)
 
static JsonParseErrorType get_scalar (void *state, char *token, JsonTokenType tokentype)
 
static Datum get_path_all (FunctionCallInfo fcinfo, bool as_text)
 
static textget_worker (text *json, char **tpath, int *ipath, int npath, bool normalize_results)
 
static Datum get_jsonb_path_all (FunctionCallInfo fcinfo, bool as_text)
 
static textJsonbValueAsText (JsonbValue *v)
 
static JsonParseErrorType alen_object_start (void *state)
 
static JsonParseErrorType alen_scalar (void *state, char *token, JsonTokenType tokentype)
 
static JsonParseErrorType alen_array_element_start (void *state, bool isnull)
 
static Datum each_worker (FunctionCallInfo fcinfo, bool as_text)
 
static Datum each_worker_jsonb (FunctionCallInfo fcinfo, const char *funcname, bool as_text)
 
static JsonParseErrorType each_object_field_start (void *state, char *fname, bool isnull)
 
static JsonParseErrorType each_object_field_end (void *state, char *fname, bool isnull)
 
static JsonParseErrorType each_array_start (void *state)
 
static JsonParseErrorType each_scalar (void *state, char *token, JsonTokenType tokentype)
 
static Datum elements_worker (FunctionCallInfo fcinfo, const char *funcname, bool as_text)
 
static Datum elements_worker_jsonb (FunctionCallInfo fcinfo, const char *funcname, bool as_text)
 
static JsonParseErrorType elements_object_start (void *state)
 
static JsonParseErrorType elements_array_element_start (void *state, bool isnull)
 
static JsonParseErrorType elements_array_element_end (void *state, bool isnull)
 
static JsonParseErrorType elements_scalar (void *state, char *token, JsonTokenType tokentype)
 
static HTABget_json_object_as_hash (const char *json, int len, const char *funcname, Node *escontext)
 
static JsonParseErrorType populate_array_object_start (void *_state)
 
static JsonParseErrorType populate_array_array_end (void *_state)
 
static JsonParseErrorType populate_array_element_start (void *_state, bool isnull)
 
static JsonParseErrorType populate_array_element_end (void *_state, bool isnull)
 
static JsonParseErrorType populate_array_scalar (void *_state, char *token, JsonTokenType tokentype)
 
static JsonParseErrorType hash_object_field_start (void *state, char *fname, bool isnull)
 
static JsonParseErrorType hash_object_field_end (void *state, char *fname, bool isnull)
 
static JsonParseErrorType hash_array_start (void *state)
 
static JsonParseErrorType hash_scalar (void *state, char *token, JsonTokenType tokentype)
 
static JsonParseErrorType populate_recordset_object_field_start (void *state, char *fname, bool isnull)
 
static JsonParseErrorType populate_recordset_object_field_end (void *state, char *fname, bool isnull)
 
static JsonParseErrorType populate_recordset_scalar (void *state, char *token, JsonTokenType tokentype)
 
static JsonParseErrorType populate_recordset_object_start (void *state)
 
static JsonParseErrorType populate_recordset_object_end (void *state)
 
static JsonParseErrorType populate_recordset_array_start (void *state)
 
static JsonParseErrorType populate_recordset_array_element_start (void *state, bool isnull)
 
static JsonParseErrorType sn_object_start (void *state)
 
static JsonParseErrorType sn_object_end (void *state)
 
static JsonParseErrorType sn_array_start (void *state)
 
static JsonParseErrorType sn_array_end (void *state)
 
static JsonParseErrorType sn_object_field_start (void *state, char *fname, bool isnull)
 
static JsonParseErrorType sn_array_element_start (void *state, bool isnull)
 
static JsonParseErrorType sn_scalar (void *state, char *token, JsonTokenType tokentype)
 
static Datum populate_recordset_worker (FunctionCallInfo fcinfo, const char *funcname, bool is_json, bool have_record_arg)
 
static Datum populate_record_worker (FunctionCallInfo fcinfo, const char *funcname, bool is_json, bool have_record_arg, Node *escontext)
 
static HeapTupleHeader populate_record (TupleDesc tupdesc, RecordIOData **record_p, HeapTupleHeader defaultval, MemoryContext mcxt, JsObject *obj, Node *escontext)
 
static void get_record_type_from_argument (FunctionCallInfo fcinfo, const char *funcname, PopulateRecordCache *cache)
 
static void get_record_type_from_query (FunctionCallInfo fcinfo, const char *funcname, PopulateRecordCache *cache)
 
static bool JsValueToJsObject (JsValue *jsv, JsObject *jso, Node *escontext)
 
static Datum populate_composite (CompositeIOData *io, Oid typid, const char *colname, MemoryContext mcxt, HeapTupleHeader defaultval, JsValue *jsv, bool *isnull, Node *escontext)
 
static Datum populate_scalar (ScalarIOData *io, Oid typid, int32 typmod, JsValue *jsv, bool *isnull, Node *escontext, bool omit_quotes)
 
static void prepare_column_cache (ColumnIOData *column, Oid typid, int32 typmod, MemoryContext mcxt, bool need_scalar)
 
static Datum populate_record_field (ColumnIOData *col, Oid typid, int32 typmod, const char *colname, MemoryContext mcxt, Datum defaultval, JsValue *jsv, bool *isnull, Node *escontext, bool omit_scalar_quotes)
 
static RecordIODataallocate_record_info (MemoryContext mcxt, int ncolumns)
 
static bool JsObjectGetField (JsObject *obj, char *field, JsValue *jsv)
 
static void populate_recordset_record (PopulateRecordsetState *state, JsObject *obj)
 
static bool populate_array_json (PopulateArrayContext *ctx, const char *json, int len)
 
static bool populate_array_dim_jsonb (PopulateArrayContext *ctx, JsonbValue *jbv, int ndim)
 
static void populate_array_report_expected_array (PopulateArrayContext *ctx, int ndim)
 
static bool populate_array_assign_ndims (PopulateArrayContext *ctx, int ndims)
 
static bool populate_array_check_dimension (PopulateArrayContext *ctx, int ndim)
 
static bool populate_array_element (PopulateArrayContext *ctx, int ndim, JsValue *jsv)
 
static Datum populate_array (ArrayIOData *aio, const char *colname, MemoryContext mcxt, JsValue *jsv, bool *isnull, Node *escontext)
 
static Datum populate_domain (DomainIOData *io, Oid typid, const char *colname, MemoryContext mcxt, JsValue *jsv, bool *isnull, Node *escontext, bool omit_quotes)
 
static void IteratorConcat (JsonbIterator **it1, JsonbIterator **it2, JsonbInState *state)
 
static void setPath (JsonbIterator **it, const Datum *path_elems, const bool *path_nulls, int path_len, JsonbInState *st, int level, JsonbValue *newval, int op_type)
 
static void setPathObject (JsonbIterator **it, const Datum *path_elems, const bool *path_nulls, int path_len, JsonbInState *st, int level, JsonbValue *newval, uint32 npairs, int op_type)
 
static void setPathArray (JsonbIterator **it, const Datum *path_elems, const bool *path_nulls, int path_len, JsonbInState *st, int level, JsonbValue *newval, uint32 nelems, int op_type)
 
static JsonParseErrorType iterate_values_scalar (void *state, char *token, JsonTokenType tokentype)
 
static JsonParseErrorType iterate_values_object_field_start (void *state, char *fname, bool isnull)
 
static JsonParseErrorType transform_string_values_object_start (void *state)
 
static JsonParseErrorType transform_string_values_object_end (void *state)
 
static JsonParseErrorType transform_string_values_array_start (void *state)
 
static JsonParseErrorType transform_string_values_array_end (void *state)
 
static JsonParseErrorType transform_string_values_object_field_start (void *state, char *fname, bool isnull)
 
static JsonParseErrorType transform_string_values_array_element_start (void *state, bool isnull)
 
static JsonParseErrorType transform_string_values_scalar (void *state, char *token, JsonTokenType tokentype)
 
bool pg_parse_json_or_errsave (JsonLexContext *lex, const JsonSemAction *sem, Node *escontext)
 
JsonLexContextmakeJsonLexContext (JsonLexContext *lex, text *json, bool need_escapes)
 
Datum jsonb_object_keys (PG_FUNCTION_ARGS)
 
void json_errsave_error (JsonParseErrorType error, JsonLexContext *lex, Node *escontext)
 
Datum json_object_keys (PG_FUNCTION_ARGS)
 
Datum json_object_field (PG_FUNCTION_ARGS)
 
Datum jsonb_object_field (PG_FUNCTION_ARGS)
 
Datum json_object_field_text (PG_FUNCTION_ARGS)
 
Datum jsonb_object_field_text (PG_FUNCTION_ARGS)
 
Datum json_array_element (PG_FUNCTION_ARGS)
 
Datum jsonb_array_element (PG_FUNCTION_ARGS)
 
Datum json_array_element_text (PG_FUNCTION_ARGS)
 
Datum jsonb_array_element_text (PG_FUNCTION_ARGS)
 
Datum json_extract_path (PG_FUNCTION_ARGS)
 
Datum json_extract_path_text (PG_FUNCTION_ARGS)
 
Datum jsonb_extract_path (PG_FUNCTION_ARGS)
 
Datum jsonb_extract_path_text (PG_FUNCTION_ARGS)
 
Datum jsonb_get_element (Jsonb *jb, const Datum *path, int npath, bool *isnull, bool as_text)
 
Datum jsonb_set_element (Jsonb *jb, const Datum *path, int path_len, JsonbValue *newval)
 
static void push_null_elements (JsonbInState *ps, int num)
 
static void push_path (JsonbInState *st, int level, const Datum *path_elems, const bool *path_nulls, int path_len, JsonbValue *newval)
 
Datum json_array_length (PG_FUNCTION_ARGS)
 
Datum jsonb_array_length (PG_FUNCTION_ARGS)
 
Datum json_each (PG_FUNCTION_ARGS)
 
Datum jsonb_each (PG_FUNCTION_ARGS)
 
Datum json_each_text (PG_FUNCTION_ARGS)
 
Datum jsonb_each_text (PG_FUNCTION_ARGS)
 
Datum jsonb_array_elements (PG_FUNCTION_ARGS)
 
Datum jsonb_array_elements_text (PG_FUNCTION_ARGS)
 
Datum json_array_elements (PG_FUNCTION_ARGS)
 
Datum json_array_elements_text (PG_FUNCTION_ARGS)
 
Datum jsonb_populate_record (PG_FUNCTION_ARGS)
 
Datum jsonb_populate_record_valid (PG_FUNCTION_ARGS)
 
Datum jsonb_to_record (PG_FUNCTION_ARGS)
 
Datum json_populate_record (PG_FUNCTION_ARGS)
 
Datum json_to_record (PG_FUNCTION_ARGS)
 
static void update_cached_tupdesc (CompositeIOData *io, MemoryContext mcxt)
 
Datum json_populate_type (Datum json_val, Oid json_type, Oid typid, int32 typmod, void **cache, MemoryContext mcxt, bool *isnull, bool omit_quotes, Node *escontext)
 
Datum jsonb_populate_recordset (PG_FUNCTION_ARGS)
 
Datum jsonb_to_recordset (PG_FUNCTION_ARGS)
 
Datum json_populate_recordset (PG_FUNCTION_ARGS)
 
Datum json_to_recordset (PG_FUNCTION_ARGS)
 
Datum json_strip_nulls (PG_FUNCTION_ARGS)
 
Datum jsonb_strip_nulls (PG_FUNCTION_ARGS)
 
Datum jsonb_pretty (PG_FUNCTION_ARGS)
 
Datum jsonb_concat (PG_FUNCTION_ARGS)
 
Datum jsonb_delete (PG_FUNCTION_ARGS)
 
Datum jsonb_delete_array (PG_FUNCTION_ARGS)
 
Datum jsonb_delete_idx (PG_FUNCTION_ARGS)
 
Datum jsonb_set (PG_FUNCTION_ARGS)
 
Datum jsonb_set_lax (PG_FUNCTION_ARGS)
 
Datum jsonb_delete_path (PG_FUNCTION_ARGS)
 
Datum jsonb_insert (PG_FUNCTION_ARGS)
 
uint32 parse_jsonb_index_flags (Jsonb *jb)
 
void iterate_jsonb_values (Jsonb *jb, uint32 flags, void *state, JsonIterateStringValuesAction action)
 
void iterate_json_values (text *json, uint32 flags, void *action_state, JsonIterateStringValuesAction action)
 
Jsonbtransform_jsonb_string_values (Jsonb *jsonb, void *action_state, JsonTransformStringValuesAction transform_action)
 
texttransform_json_string_values (text *json, void *action_state, JsonTransformStringValuesAction transform_action)
 
JsonTokenType json_get_first_token (text *json, bool throw_error)
 
void json_categorize_type (Oid typoid, bool is_jsonb, JsonTypeCategory *tcategory, Oid *outfuncoid)
 

Macro Definition Documentation

◆ JB_PATH_CONSISTENT_POSITION

#define JB_PATH_CONSISTENT_POSITION   0x0040

Definition at line 52 of file jsonfuncs.c.

◆ JB_PATH_CREATE

#define JB_PATH_CREATE   0x0001

Definition at line 44 of file jsonfuncs.c.

◆ JB_PATH_CREATE_OR_INSERT

#define JB_PATH_CREATE_OR_INSERT    (JB_PATH_INSERT_BEFORE | JB_PATH_INSERT_AFTER | JB_PATH_CREATE)

Definition at line 49 of file jsonfuncs.c.

56{
57 JsonLexContext *lex;
58 char **result;
59 int result_size;
60 int result_count;
61 int sent_count;
63
64/* state for iterate_json_values function */
66{
68 JsonIterateStringValuesAction action; /* an action that will be applied
69 * to each json value */
70 void *action_state; /* any necessary context for iteration */
71 uint32 flags; /* what kind of elements from a json we want
72 * to iterate */
74
75/* state for transform_json_string_values function */
77{
79 StringInfo strval; /* resulting json */
80 JsonTransformStringValuesAction action; /* an action that will be applied
81 * to each json value */
82 void *action_state; /* any necessary context for transformation */
84
85/* state for json_get* functions */
86typedef struct GetState
87{
90 const char *result_start;
92 bool next_scalar;
93 int npath; /* length of each path-related array */
94 char **path_names; /* field name(s) being sought */
95 int *path_indexes; /* array index(es) being sought */
96 bool *pathok; /* is path matched to current depth? */
97 int *array_cur_index; /* current element index at each path
98 * level */
99} GetState;
100
101/* state for json_array_length */
102typedef struct AlenState
103{
105 int count;
106} AlenState;
107
108/* state for json_each */
109typedef struct EachState
110{
115 const char *result_start;
117 bool next_scalar;
118 char *normalized_scalar;
119} EachState;
120
121/* state for json_array_elements */
122typedef struct ElementsState
123{
125 const char *function_name;
129 const char *result_start;
131 bool next_scalar;
132 char *normalized_scalar;
134
135/* state for get_json_object_as_hash */
136typedef struct JHashState
137{
139 const char *function_name;
140 HTAB *hash;
141 char *saved_scalar;
142 const char *save_json_start;
144} JHashState;
145
146/* hashtable element */
147typedef struct JsonHashEntry
148{
149 char fname[NAMEDATALEN]; /* hash key (MUST BE FIRST) */
150 char *val;
153
154/* structure to cache type I/O metadata needed for populate_scalar() */
155typedef struct ScalarIOData
156{
160
161/* these two structures are used recursively */
162typedef struct ColumnIOData ColumnIOData;
163typedef struct RecordIOData RecordIOData;
164
165/* structure to cache metadata needed for populate_array() */
166typedef struct ArrayIOData
167{
168 ColumnIOData *element_info; /* metadata cache */
169 Oid element_type; /* array element type id */
170 int32 element_typmod; /* array element type modifier */
172
173/* structure to cache metadata needed for populate_composite() */
174typedef struct CompositeIOData
175{
176 /*
177 * We use pointer to a RecordIOData here because variable-length struct
178 * RecordIOData can't be used directly in ColumnIOData.io union
179 */
180 RecordIOData *record_io; /* metadata cache for populate_record() */
181 TupleDesc tupdesc; /* cached tuple descriptor */
182 /* these fields differ from target type only if domain over composite: */
183 Oid base_typid; /* base type id */
184 int32 base_typmod; /* base type modifier */
185 /* this field is used only if target type is domain over composite: */
186 void *domain_info; /* opaque cache for domain checks */
188
189/* structure to cache metadata needed for populate_domain() */
190typedef struct DomainIOData
191{
192 ColumnIOData *base_io; /* metadata cache */
193 Oid base_typid; /* base type id */
194 int32 base_typmod; /* base type modifier */
195 void *domain_info; /* opaque cache for domain checks */
197
198/* enumeration type categories */
199typedef enum TypeCat
200{
201 TYPECAT_SCALAR = 's',
202 TYPECAT_ARRAY = 'a',
203 TYPECAT_COMPOSITE = 'c',
205 TYPECAT_DOMAIN = 'd',
206} TypeCat;
207
208/* these two are stolen from hstore / record_out, used in populate_record* */
209
210/* structure to cache record metadata needed for populate_record_field() */
211struct ColumnIOData
212{
213 Oid typid; /* column type id */
214 int32 typmod; /* column type modifier */
215 TypeCat typcat; /* column type category */
216 ScalarIOData scalar_io; /* metadata cache for direct conversion
217 * through input function */
218 union
219 {
223 } io; /* metadata cache for various column type
224 * categories */
225};
226
227/* structure to cache record metadata needed for populate_record() */
228struct RecordIOData
229{
232 int ncolumns;
234};
235
236/* per-query cache for populate_record_worker and populate_recordset_worker */
237typedef struct PopulateRecordCache
238{
239 Oid argtype; /* declared type of the record argument */
240 ColumnIOData c; /* metadata cache for populate_composite() */
241 MemoryContext fn_mcxt; /* where this is stored */
243
244/* per-call state for populate_recordset */
245typedef struct PopulateRecordsetState
246{
248 const char *function_name;
250 char *saved_scalar;
251 const char *save_json_start;
257
258/* common data for populate_array_json() and populate_array_dim_jsonb() */
259typedef struct PopulateArrayContext
260{
261 ArrayBuildState *astate; /* array build state */
262 ArrayIOData *aio; /* metadata cache */
263 MemoryContext acxt; /* array build memory context */
264 MemoryContext mcxt; /* cache memory context */
265 const char *colname; /* for diagnostics only */
266 int *dims; /* dimensions */
267 int *sizes; /* current dimension counters */
268 int ndims; /* number of dimensions */
269 Node *escontext; /* For soft-error handling */
271
272/* state for populate_array_json() */
273typedef struct PopulateArrayState
274{
275 JsonLexContext *lex; /* json lexer */
276 PopulateArrayContext *ctx; /* context */
277 const char *element_start; /* start of the current array element */
278 char *element_scalar; /* current array element token if it is a
279 * scalar */
280 JsonTokenType element_type; /* current array element type */
282
283/* state for json_strip_nulls */
284typedef struct StripnullState
285{
288 bool skip_next_null;
289 bool strip_in_arrays;
291
292/* structure for generalized json/jsonb value passing */
293typedef struct JsValue
294{
295 bool is_json; /* json/jsonb */
296 union
297 {
298 struct
299 {
300 const char *str; /* json string */
301 int len; /* json string length or -1 if null-terminated */
302 JsonTokenType type; /* json type */
303 } json; /* json value */
304
305 JsonbValue *jsonb; /* jsonb value */
306 } val;
307} JsValue;
308
309typedef struct JsObject
310{
311 bool is_json; /* json/jsonb */
312 union
313 {
316 } val;
317} JsObject;
318
319/* useful macros for testing JsValue properties */
320#define JsValueIsNull(jsv) \
321 ((jsv)->is_json ? \
322 (!(jsv)->val.json.str || (jsv)->val.json.type == JSON_TOKEN_NULL) : \
323 (!(jsv)->val.jsonb || (jsv)->val.jsonb->type == jbvNull))
324
325#define JsValueIsString(jsv) \
326 ((jsv)->is_json ? (jsv)->val.json.type == JSON_TOKEN_STRING \
327 : ((jsv)->val.jsonb && (jsv)->val.jsonb->type == jbvString))
328
329#define JsObjectIsEmpty(jso) \
330 ((jso)->is_json \
331 ? hash_get_num_entries((jso)->val.json_hash) == 0 \
332 : ((jso)->val.jsonb_cont == NULL || \
333 JsonContainerSize((jso)->val.jsonb_cont) == 0))
334
335#define JsObjectFree(jso) \
336 do { \
337 if ((jso)->is_json) \
338 hash_destroy((jso)->val.json_hash); \
339 } while (0)
340
341static int report_json_context(JsonLexContext *lex);
342
343/* semantic action functions for json_object_keys */
344static JsonParseErrorType okeys_object_field_start(void *state, char *fname, bool isnull);
346static JsonParseErrorType okeys_scalar(void *state, char *token, JsonTokenType tokentype);
347
348/* semantic action functions for json_get* functions */
351static JsonParseErrorType get_object_field_start(void *state, char *fname, bool isnull);
352static JsonParseErrorType get_object_field_end(void *state, char *fname, bool isnull);
355static JsonParseErrorType get_array_element_start(void *state, bool isnull);
356static JsonParseErrorType get_array_element_end(void *state, bool isnull);
357static JsonParseErrorType get_scalar(void *state, char *token, JsonTokenType tokentype);
358
359/* common worker function for json getter functions */
360static Datum get_path_all(FunctionCallInfo fcinfo, bool as_text);
361static text *get_worker(text *json, char **tpath, int *ipath, int npath,
362 bool normalize_results);
365
366/* semantic action functions for json_array_length */
368static JsonParseErrorType alen_scalar(void *state, char *token, JsonTokenType tokentype);
369static JsonParseErrorType alen_array_element_start(void *state, bool isnull);
370
371/* common workers for json{b}_each* functions */
372static Datum each_worker(FunctionCallInfo fcinfo, bool as_text);
373static Datum each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname,
374 bool as_text);
375
376/* semantic action functions for json_each */
377static JsonParseErrorType each_object_field_start(void *state, char *fname, bool isnull);
378static JsonParseErrorType each_object_field_end(void *state, char *fname, bool isnull);
380static JsonParseErrorType each_scalar(void *state, char *token, JsonTokenType tokentype);
381
382/* common workers for json{b}_array_elements_* functions */
383static Datum elements_worker(FunctionCallInfo fcinfo, const char *funcname,
384 bool as_text);
385static Datum elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname,
386 bool as_text);
387
388/* semantic action functions for json_array_elements */
390static JsonParseErrorType elements_array_element_start(void *state, bool isnull);
391static JsonParseErrorType elements_array_element_end(void *state, bool isnull);
392static JsonParseErrorType elements_scalar(void *state, char *token, JsonTokenType tokentype);
393
394/* turn a json object into a hash table */
395static HTAB *get_json_object_as_hash(const char *json, int len, const char *funcname,
396 Node *escontext);
397
398/* semantic actions for populate_array_json */
402static JsonParseErrorType populate_array_element_end(void *_state, bool isnull);
404
405/* semantic action functions for get_json_object_as_hash */
406static JsonParseErrorType hash_object_field_start(void *state, char *fname, bool isnull);
407static JsonParseErrorType hash_object_field_end(void *state, char *fname, bool isnull);
409static JsonParseErrorType hash_scalar(void *state, char *token, JsonTokenType tokentype);
410
411/* semantic action functions for populate_recordset */
412static JsonParseErrorType populate_recordset_object_field_start(void *state, char *fname, bool isnull);
413static JsonParseErrorType populate_recordset_object_field_end(void *state, char *fname, bool isnull);
419
420/* semantic action functions for json_strip_nulls */
425static JsonParseErrorType sn_object_field_start(void *state, char *fname, bool isnull);
426static JsonParseErrorType sn_array_element_start(void *state, bool isnull);
427static JsonParseErrorType sn_scalar(void *state, char *token, JsonTokenType tokentype);
428
429/* worker functions for populate_record, to_record, populate_recordset and to_recordset */
431 bool is_json, bool have_record_arg);
432static Datum populate_record_worker(FunctionCallInfo fcinfo, const char *funcname,
433 bool is_json, bool have_record_arg,
434 Node *escontext);
435
436/* helper functions for populate_record[set] */
439 JsObject *obj, Node *escontext);
441 const char *funcname,
442 PopulateRecordCache *cache);
444 const char *funcname,
445 PopulateRecordCache *cache);
446static bool JsValueToJsObject(JsValue *jsv, JsObject *jso, Node *escontext);
448 const char *colname, MemoryContext mcxt,
449 HeapTupleHeader defaultval, JsValue *jsv, bool *isnull,
450 Node *escontext);
451static Datum populate_scalar(ScalarIOData *io, Oid typid, int32 typmod, JsValue *jsv,
452 bool *isnull, Node *escontext, bool omit_quotes);
453static void prepare_column_cache(ColumnIOData *column, Oid typid, int32 typmod,
454 MemoryContext mcxt, bool need_scalar);
455static Datum populate_record_field(ColumnIOData *col, Oid typid, int32 typmod,
456 const char *colname, MemoryContext mcxt, Datum defaultval,
457 JsValue *jsv, bool *isnull, Node *escontext,
458 bool omit_scalar_quotes);
459static RecordIOData *allocate_record_info(MemoryContext mcxt, int ncolumns);
460static bool JsObjectGetField(JsObject *obj, char *field, JsValue *jsv);
462static bool populate_array_json(PopulateArrayContext *ctx, const char *json, int len);
464 int ndim);
466static bool populate_array_assign_ndims(PopulateArrayContext *ctx, int ndims);
467static bool populate_array_check_dimension(PopulateArrayContext *ctx, int ndim);
468static bool populate_array_element(PopulateArrayContext *ctx, int ndim, JsValue *jsv);
469static Datum populate_array(ArrayIOData *aio, const char *colname,
471 bool *isnull,
472 Node *escontext);
473static Datum populate_domain(DomainIOData *io, Oid typid, const char *colname,
474 MemoryContext mcxt, JsValue *jsv, bool *isnull,
475 Node *escontext, bool omit_quotes);
476
477/* functions supporting jsonb_delete, jsonb_set and jsonb_concat */
480static void setPath(JsonbIterator **it, const Datum *path_elems,
481 const bool *path_nulls, int path_len,
482 JsonbInState *st, int level, JsonbValue *newval,
483 int op_type);
484static void setPathObject(JsonbIterator **it, const Datum *path_elems,
485 const bool *path_nulls, int path_len, JsonbInState *st,
486 int level,
488static void setPathArray(JsonbIterator **it, const Datum *path_elems,
489 const bool *path_nulls, int path_len, JsonbInState *st,
490 int level,
491 JsonbValue *newval, uint32 nelems, int op_type);
492
493/* function supporting iterate_json_values */
495static JsonParseErrorType iterate_values_object_field_start(void *state, char *fname, bool isnull);
496
497/* functions supporting transform_json_string_values */
502static JsonParseErrorType transform_string_values_object_field_start(void *state, char *fname, bool isnull);
505
506
507/*
508 * pg_parse_json_or_errsave
509 *
510 * This function is like pg_parse_json, except that it does not return a
511 * JsonParseErrorType. Instead, in case of any failure, this function will
512 * save error data into *escontext if that's an ErrorSaveContext, otherwise
513 * ereport(ERROR).
514 *
515 * Returns a boolean indicating success or failure (failure will only be
516 * returned when escontext is an ErrorSaveContext).
517 */
518bool
520 Node *escontext)
521{
522 JsonParseErrorType result;
523
524 result = pg_parse_json(lex, sem);
525 if (result != JSON_SUCCESS)
526 {
527 json_errsave_error(result, lex, escontext);
528 return false;
529 }
530 return true;
531}
532
533/*
534 * makeJsonLexContext
535 *
536 * This is like makeJsonLexContextCstringLen, but it accepts a text value
537 * directly.
538 */
540makeJsonLexContext(JsonLexContext *lex, text *json, bool need_escapes)
541{
542 /*
543 * Most callers pass a detoasted datum, but it's not clear that they all
544 * do. pg_detoast_datum_packed() is cheap insurance.
545 */
546 json = pg_detoast_datum_packed(json);
547
549 VARDATA_ANY(json),
550 VARSIZE_ANY_EXHDR(json),
552 need_escapes);
553}
554
555/*
556 * SQL function json_object_keys
557 *
558 * Returns the set of keys for the object argument.
559 *
560 * This SRF operates in value-per-call mode. It processes the
561 * object during the first call, and the keys are simply stashed
562 * in an array, whose size is expanded as necessary. This is probably
563 * safe enough for a list of keys of a single object, since they are
564 * limited in size to NAMEDATALEN and the number of keys is unlikely to
565 * be so huge that it has major memory implications.
566 */
567Datum
569{
572
573 if (SRF_IS_FIRSTCALL())
574 {
575 MemoryContext oldcontext;
577 bool skipNested = false;
579 JsonbValue v;
581
585 errmsg("cannot call %s on a scalar",
586 "jsonb_object_keys")));
587 else if (JB_ROOT_IS_ARRAY(jb))
590 errmsg("cannot call %s on an array",
591 "jsonb_object_keys")));
592
594 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
595
597
598 state->result_size = JB_ROOT_COUNT(jb);
599 state->result_count = 0;
600 state->sent_count = 0;
601 state->result = palloc_array(char *, state->result_size);
602
603 it = JsonbIteratorInit(&jb->root);
604
605 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
606 {
607 skipNested = true;
608
609 if (r == WJB_KEY)
610 {
611 char *cstr;
612
613 cstr = palloc(v.val.string.len + 1 * sizeof(char));
614 memcpy(cstr, v.val.string.val, v.val.string.len);
615 cstr[v.val.string.len] = '\0';
616 state->result[state->result_count++] = cstr;
617 }
618 }
619
620 MemoryContextSwitchTo(oldcontext);
621 funcctx->user_fctx = state;
622 }
623
625 state = (OkeysState *) funcctx->user_fctx;
626
627 if (state->sent_count < state->result_count)
628 {
629 char *nxt = state->result[state->sent_count++];
630
632 }
633
635}
636
637/*
638 * Report a JSON error.
639 */
640void
642 Node *escontext)
643{
647 errsave(escontext,
649 errmsg("unsupported Unicode escape sequence"),
651 report_json_context(lex)));
652 else if (error == JSON_SEM_ACTION_FAILED)
653 {
654 /* semantic action function had better have reported something */
655 if (!SOFT_ERROR_OCCURRED(escontext))
656 elog(ERROR, "JSON semantic action function did not provide error information");
657 }
658 else
659 errsave(escontext,
661 errmsg("invalid input syntax for type %s", "json"),
663 report_json_context(lex)));
664}
665
666/*
667 * Report a CONTEXT line for bogus JSON input.
668 *
669 * lex->token_terminator must be set to identify the spot where we detected
670 * the error. Note that lex->token_start might be NULL, in case we recognized
671 * error at EOF.
672 *
673 * The return value isn't meaningful, but we make it non-void so that this
674 * can be invoked inside ereport().
675 */
676static int
678{
679 const char *context_start;
680 const char *context_end;
681 const char *line_start;
682 char *ctxt;
683 int ctxtlen;
684 const char *prefix;
685 const char *suffix;
686
687 /* Choose boundaries for the part of the input we will display */
688 line_start = lex->line_start;
689 context_start = line_start;
692
693 /* Advance until we are close enough to context_end */
694 while (context_end - context_start >= 50)
695 {
696 /* Advance to next multibyte character */
699 else
701 }
702
703 /*
704 * We add "..." to indicate that the excerpt doesn't start at the
705 * beginning of the line ... but if we're within 3 characters of the
706 * beginning of the line, we might as well just show the whole line.
707 */
708 if (context_start - line_start <= 3)
709 context_start = line_start;
710
711 /* Get a null-terminated copy of the data to present */
713 ctxt = palloc(ctxtlen + 1);
715 ctxt[ctxtlen] = '\0';
716
717 /*
718 * Show the context, prefixing "..." if not starting at start of line, and
719 * suffixing "..." if not ending at end of line.
720 */
721 prefix = (context_start > line_start) ? "..." : "";
722 suffix = (lex->token_type != JSON_TOKEN_END &&
723 context_end - lex->input < lex->input_length &&
724 *context_end != '\n' && *context_end != '\r') ? "..." : "";
725
726 return errcontext("JSON data, line %d: %s%s%s",
727 lex->line_number, prefix, ctxt, suffix);
728}
729
730
731Datum
733{
736
737 if (SRF_IS_FIRSTCALL())
738 {
739 text *json = PG_GETARG_TEXT_PP(0);
740 JsonLexContext lex;
742 MemoryContext oldcontext;
743
745 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
746
749
750 state->lex = makeJsonLexContext(&lex, json, true);
751 state->result_size = 256;
752 state->result_count = 0;
753 state->sent_count = 0;
754 state->result = palloc_array(char *, 256);
755
756 sem->semstate = state;
760 /* remainder are all NULL, courtesy of palloc0 above */
761
763 /* keys are now in state->result */
764
765 freeJsonLexContext(&lex);
766 pfree(sem);
767
768 MemoryContextSwitchTo(oldcontext);
769 funcctx->user_fctx = state;
770 }
771
773 state = (OkeysState *) funcctx->user_fctx;
774
775 if (state->sent_count < state->result_count)
776 {
777 char *nxt = state->result[state->sent_count++];
778
780 }
781
783}
784
786okeys_object_field_start(void *state, char *fname, bool isnull)
787{
789
790 /* only collecting keys for the top level object */
791 if (_state->lex->lex_level != 1)
792 return JSON_SUCCESS;
793
794 /* enlarge result array if necessary */
795 if (_state->result_count >= _state->result_size)
796 {
797 _state->result_size *= 2;
798 _state->result = (char **)
799 repalloc(_state->result, sizeof(char *) * _state->result_size);
800 }
801
802 /* save a copy of the field name */
803 _state->result[_state->result_count++] = pstrdup(fname);
804
805 return JSON_SUCCESS;
806}
807
810{
812
813 /* top level must be a json object */
814 if (_state->lex->lex_level == 0)
817 errmsg("cannot call %s on an array",
818 "json_object_keys")));
819
820 return JSON_SUCCESS;
821}
822
824okeys_scalar(void *state, char *token, JsonTokenType tokentype)
825{
827
828 /* top level must be a json object */
829 if (_state->lex->lex_level == 0)
832 errmsg("cannot call %s on a scalar",
833 "json_object_keys")));
834
835 return JSON_SUCCESS;
836}
837
838/*
839 * json and jsonb getter functions
840 * these implement the -> ->> #> and #>> operators
841 * and the json{b?}_extract_path*(json, text, ...) functions
842 */
843
844
845Datum
847{
848 text *json = PG_GETARG_TEXT_PP(0);
849 text *fname = PG_GETARG_TEXT_PP(1);
850 char *fnamestr = text_to_cstring(fname);
851 text *result;
852
853 result = get_worker(json, &fnamestr, NULL, 1, false);
854
855 if (result != NULL)
856 PG_RETURN_TEXT_P(result);
857 else
859}
860
861Datum
863{
866 JsonbValue *v;
868
869 if (!JB_ROOT_IS_OBJECT(jb))
871
873 VARDATA_ANY(key),
875 &vbuf);
876
877 if (v != NULL)
879
881}
882
883Datum
885{
886 text *json = PG_GETARG_TEXT_PP(0);
887 text *fname = PG_GETARG_TEXT_PP(1);
888 char *fnamestr = text_to_cstring(fname);
889 text *result;
890
891 result = get_worker(json, &fnamestr, NULL, 1, true);
892
893 if (result != NULL)
894 PG_RETURN_TEXT_P(result);
895 else
897}
898
899Datum
901{
904 JsonbValue *v;
906
907 if (!JB_ROOT_IS_OBJECT(jb))
909
911 VARDATA_ANY(key),
913 &vbuf);
914
915 if (v != NULL && v->type != jbvNull)
917
919}
920
921Datum
923{
924 text *json = PG_GETARG_TEXT_PP(0);
925 int element = PG_GETARG_INT32(1);
926 text *result;
927
928 result = get_worker(json, NULL, &element, 1, false);
929
930 if (result != NULL)
931 PG_RETURN_TEXT_P(result);
932 else
934}
935
936Datum
938{
940 int element = PG_GETARG_INT32(1);
941 JsonbValue *v;
942
943 if (!JB_ROOT_IS_ARRAY(jb))
945
946 /* Handle negative subscript */
947 if (element < 0)
948 {
949 uint32 nelements = JB_ROOT_COUNT(jb);
950
951 if (pg_abs_s32(element) > nelements)
953 else
954 element += nelements;
955 }
956
958 if (v != NULL)
960
962}
963
964Datum
966{
967 text *json = PG_GETARG_TEXT_PP(0);
968 int element = PG_GETARG_INT32(1);
969 text *result;
970
971 result = get_worker(json, NULL, &element, 1, true);
972
973 if (result != NULL)
974 PG_RETURN_TEXT_P(result);
975 else
977}
978
979Datum
981{
983 int element = PG_GETARG_INT32(1);
984 JsonbValue *v;
985
986 if (!JB_ROOT_IS_ARRAY(jb))
988
989 /* Handle negative subscript */
990 if (element < 0)
991 {
992 uint32 nelements = JB_ROOT_COUNT(jb);
993
994 if (pg_abs_s32(element) > nelements)
996 else
997 element += nelements;
998 }
999
1001
1002 if (v != NULL && v->type != jbvNull)
1004
1006}
1007
1008Datum
1010{
1011 return get_path_all(fcinfo, false);
1012}
1013
1014Datum
1016{
1017 return get_path_all(fcinfo, true);
1018}
1019
1020/*
1021 * common routine for extract_path functions
1022 */
1023static Datum
1025{
1026 text *json = PG_GETARG_TEXT_PP(0);
1028 text *result;
1029 Datum *pathtext;
1030 bool *pathnulls;
1031 int npath;
1032 char **tpath;
1033 int *ipath;
1034 int i;
1035
1036 /*
1037 * If the array contains any null elements, return NULL, on the grounds
1038 * that you'd have gotten NULL if any RHS value were NULL in a nested
1039 * series of applications of the -> operator. (Note: because we also
1040 * return NULL for error cases such as no-such-field, this is true
1041 * regardless of the contents of the rest of the array.)
1042 */
1043 if (array_contains_nulls(path))
1045
1047
1048 tpath = palloc_array(char *, npath);
1049 ipath = palloc_array(int, npath);
1050
1051 for (i = 0; i < npath; i++)
1052 {
1053 Assert(!pathnulls[i]);
1055
1056 /*
1057 * we have no idea at this stage what structure the document is so
1058 * just convert anything in the path that we can to an integer and set
1059 * all the other integers to INT_MIN which will never match.
1060 */
1061 if (*tpath[i] != '\0')
1062 {
1063 int ind;
1064 char *endptr;
1065
1066 errno = 0;
1067 ind = strtoint(tpath[i], &endptr, 10);
1068 if (endptr == tpath[i] || *endptr != '\0' || errno != 0)
1069 ipath[i] = INT_MIN;
1070 else
1071 ipath[i] = ind;
1072 }
1073 else
1074 ipath[i] = INT_MIN;
1075 }
1076
1077 result = get_worker(json, tpath, ipath, npath, as_text);
1078
1079 if (result != NULL)
1080 PG_RETURN_TEXT_P(result);
1081 else
1083}
1084
1085/*
1086 * get_worker
1087 *
1088 * common worker for all the json getter functions
1089 *
1090 * json: JSON object (in text form)
1091 * tpath[]: field name(s) to extract
1092 * ipath[]: array index(es) (zero-based) to extract, accepts negatives
1093 * npath: length of tpath[] and/or ipath[]
1094 * normalize_results: true to de-escape string and null scalars
1095 *
1096 * tpath can be NULL, or any one tpath[] entry can be NULL, if an object
1097 * field is not to be matched at that nesting level. Similarly, ipath can
1098 * be NULL, or any one ipath[] entry can be INT_MIN if an array element is
1099 * not to be matched at that nesting level (a json datum should never be
1100 * large enough to have -INT_MIN elements due to MaxAllocSize restriction).
1101 */
1102static text *
1103get_worker(text *json,
1104 char **tpath,
1105 int *ipath,
1106 int npath,
1107 bool normalize_results)
1108{
1111
1112 Assert(npath >= 0);
1113
1114 state->lex = makeJsonLexContext(NULL, json, true);
1115
1116 /* is it "_as_text" variant? */
1117 state->normalize_results = normalize_results;
1118 state->npath = npath;
1119 state->path_names = tpath;
1120 state->path_indexes = ipath;
1121 state->pathok = palloc0_array(bool, npath);
1122 state->array_cur_index = palloc_array(int, npath);
1123
1124 if (npath > 0)
1125 state->pathok[0] = true;
1126
1127 sem->semstate = state;
1128
1129 /*
1130 * Not all variants need all the semantic routines. Only set the ones that
1131 * are actually needed for maximum efficiency.
1132 */
1134 if (npath == 0)
1135 {
1140 }
1141 if (tpath != NULL)
1142 {
1145 }
1146 if (ipath != NULL)
1147 {
1151 }
1152
1155
1156 return state->tresult;
1157}
1158
1159static JsonParseErrorType
1161{
1163 int lex_level = _state->lex->lex_level;
1164
1165 if (lex_level == 0 && _state->npath == 0)
1166 {
1167 /*
1168 * Special case: we should match the entire object. We only need this
1169 * at outermost level because at nested levels the match will have
1170 * been started by the outer field or array element callback.
1171 */
1172 _state->result_start = _state->lex->token_start;
1173 }
1174
1175 return JSON_SUCCESS;
1176}
1177
1178static JsonParseErrorType
1179get_object_end(void *state)
1180{
1182 int lex_level = _state->lex->lex_level;
1183
1184 if (lex_level == 0 && _state->npath == 0)
1185 {
1186 /* Special case: return the entire object */
1187 const char *start = _state->result_start;
1188 int len = _state->lex->prev_token_terminator - start;
1189
1191 }
1192
1193 return JSON_SUCCESS;
1194}
1195
1196static JsonParseErrorType
1197get_object_field_start(void *state, char *fname, bool isnull)
1198{
1200 bool get_next = false;
1201 int lex_level = _state->lex->lex_level;
1202
1203 if (lex_level <= _state->npath &&
1204 _state->pathok[lex_level - 1] &&
1205 _state->path_names != NULL &&
1206 _state->path_names[lex_level - 1] != NULL &&
1207 strcmp(fname, _state->path_names[lex_level - 1]) == 0)
1208 {
1209 if (lex_level < _state->npath)
1210 {
1211 /* if not at end of path just mark path ok */
1212 _state->pathok[lex_level] = true;
1213 }
1214 else
1215 {
1216 /* end of path, so we want this value */
1217 get_next = true;
1218 }
1219 }
1220
1221 if (get_next)
1222 {
1223 /* this object overrides any previous matching object */
1224 _state->tresult = NULL;
1225 _state->result_start = NULL;
1226
1227 if (_state->normalize_results &&
1228 _state->lex->token_type == JSON_TOKEN_STRING)
1229 {
1230 /* for as_text variants, tell get_scalar to set it for us */
1231 _state->next_scalar = true;
1232 }
1233 else
1234 {
1235 /* for non-as_text variants, just note the json starting point */
1236 _state->result_start = _state->lex->token_start;
1237 }
1238 }
1239
1240 return JSON_SUCCESS;
1241}
1242
1243static JsonParseErrorType
1244get_object_field_end(void *state, char *fname, bool isnull)
1245{
1247 bool get_last = false;
1248 int lex_level = _state->lex->lex_level;
1249
1250 /* same tests as in get_object_field_start */
1251 if (lex_level <= _state->npath &&
1252 _state->pathok[lex_level - 1] &&
1253 _state->path_names != NULL &&
1254 _state->path_names[lex_level - 1] != NULL &&
1255 strcmp(fname, _state->path_names[lex_level - 1]) == 0)
1256 {
1257 if (lex_level < _state->npath)
1258 {
1259 /* done with this field so reset pathok */
1260 _state->pathok[lex_level] = false;
1261 }
1262 else
1263 {
1264 /* end of path, so we want this value */
1265 get_last = true;
1266 }
1267 }
1268
1269 /* for as_text scalar case, our work is already done */
1270 if (get_last && _state->result_start != NULL)
1271 {
1272 /*
1273 * make a text object from the string from the previously noted json
1274 * start up to the end of the previous token (the lexer is by now
1275 * ahead of us on whatever came after what we're interested in).
1276 */
1277 if (isnull && _state->normalize_results)
1278 _state->tresult = (text *) NULL;
1279 else
1280 {
1281 const char *start = _state->result_start;
1282 int len = _state->lex->prev_token_terminator - start;
1283
1285 }
1286
1287 /* this should be unnecessary but let's do it for cleanliness: */
1288 _state->result_start = NULL;
1289 }
1290
1291 return JSON_SUCCESS;
1292}
1293
1294static JsonParseErrorType
1296{
1298 int lex_level = _state->lex->lex_level;
1299
1300 if (lex_level < _state->npath)
1301 {
1302 /* Initialize counting of elements in this array */
1303 _state->array_cur_index[lex_level] = -1;
1304
1305 /* INT_MIN value is reserved to represent invalid subscript */
1306 if (_state->path_indexes[lex_level] < 0 &&
1307 _state->path_indexes[lex_level] != INT_MIN)
1308 {
1309 /* Negative subscript -- convert to positive-wise subscript */
1311 int nelements;
1312
1313 error = json_count_array_elements(_state->lex, &nelements);
1314 if (error != JSON_SUCCESS)
1316
1317 if (-_state->path_indexes[lex_level] <= nelements)
1318 _state->path_indexes[lex_level] += nelements;
1319 }
1320 }
1321 else if (lex_level == 0 && _state->npath == 0)
1322 {
1323 /*
1324 * Special case: we should match the entire array. We only need this
1325 * at the outermost level because at nested levels the match will have
1326 * been started by the outer field or array element callback.
1327 */
1328 _state->result_start = _state->lex->token_start;
1329 }
1330
1331 return JSON_SUCCESS;
1332}
1333
1334static JsonParseErrorType
1335get_array_end(void *state)
1336{
1338 int lex_level = _state->lex->lex_level;
1339
1340 if (lex_level == 0 && _state->npath == 0)
1341 {
1342 /* Special case: return the entire array */
1343 const char *start = _state->result_start;
1344 int len = _state->lex->prev_token_terminator - start;
1345
1347 }
1348
1349 return JSON_SUCCESS;
1350}
1351
1352static JsonParseErrorType
1353get_array_element_start(void *state, bool isnull)
1354{
1356 bool get_next = false;
1357 int lex_level = _state->lex->lex_level;
1358
1359 /* Update array element counter */
1360 if (lex_level <= _state->npath)
1361 _state->array_cur_index[lex_level - 1]++;
1362
1363 if (lex_level <= _state->npath &&
1364 _state->pathok[lex_level - 1] &&
1365 _state->path_indexes != NULL &&
1366 _state->array_cur_index[lex_level - 1] == _state->path_indexes[lex_level - 1])
1367 {
1368 if (lex_level < _state->npath)
1369 {
1370 /* if not at end of path just mark path ok */
1371 _state->pathok[lex_level] = true;
1372 }
1373 else
1374 {
1375 /* end of path, so we want this value */
1376 get_next = true;
1377 }
1378 }
1379
1380 /* same logic as for objects */
1381 if (get_next)
1382 {
1383 _state->tresult = NULL;
1384 _state->result_start = NULL;
1385
1386 if (_state->normalize_results &&
1387 _state->lex->token_type == JSON_TOKEN_STRING)
1388 {
1389 _state->next_scalar = true;
1390 }
1391 else
1392 {
1393 _state->result_start = _state->lex->token_start;
1394 }
1395 }
1396
1397 return JSON_SUCCESS;
1398}
1399
1400static JsonParseErrorType
1401get_array_element_end(void *state, bool isnull)
1402{
1404 bool get_last = false;
1405 int lex_level = _state->lex->lex_level;
1406
1407 /* same tests as in get_array_element_start */
1408 if (lex_level <= _state->npath &&
1409 _state->pathok[lex_level - 1] &&
1410 _state->path_indexes != NULL &&
1411 _state->array_cur_index[lex_level - 1] == _state->path_indexes[lex_level - 1])
1412 {
1413 if (lex_level < _state->npath)
1414 {
1415 /* done with this element so reset pathok */
1416 _state->pathok[lex_level] = false;
1417 }
1418 else
1419 {
1420 /* end of path, so we want this value */
1421 get_last = true;
1422 }
1423 }
1424
1425 /* same logic as for objects */
1426 if (get_last && _state->result_start != NULL)
1427 {
1428 if (isnull && _state->normalize_results)
1429 _state->tresult = (text *) NULL;
1430 else
1431 {
1432 const char *start = _state->result_start;
1433 int len = _state->lex->prev_token_terminator - start;
1434
1436 }
1437
1438 _state->result_start = NULL;
1439 }
1440
1441 return JSON_SUCCESS;
1442}
1443
1444static JsonParseErrorType
1445get_scalar(void *state, char *token, JsonTokenType tokentype)
1446{
1448 int lex_level = _state->lex->lex_level;
1449
1450 /* Check for whole-object match */
1451 if (lex_level == 0 && _state->npath == 0)
1452 {
1453 if (_state->normalize_results && tokentype == JSON_TOKEN_STRING)
1454 {
1455 /* we want the de-escaped string */
1456 _state->next_scalar = true;
1457 }
1458 else if (_state->normalize_results && tokentype == JSON_TOKEN_NULL)
1459 {
1460 _state->tresult = (text *) NULL;
1461 }
1462 else
1463 {
1464 /*
1465 * This is a bit hokey: we will suppress whitespace after the
1466 * scalar token, but not whitespace before it. Probably not worth
1467 * doing our own space-skipping to avoid that.
1468 */
1469 const char *start = _state->lex->input;
1470 int len = _state->lex->prev_token_terminator - start;
1471
1473 }
1474 }
1475
1476 if (_state->next_scalar)
1477 {
1478 /* a de-escaped text value is wanted, so supply it */
1479 _state->tresult = cstring_to_text(token);
1480 /* make sure the next call to get_scalar doesn't overwrite it */
1481 _state->next_scalar = false;
1482 }
1483
1484 return JSON_SUCCESS;
1485}
1486
1487Datum
1489{
1490 return get_jsonb_path_all(fcinfo, false);
1491}
1492
1493Datum
1495{
1496 return get_jsonb_path_all(fcinfo, true);
1497}
1498
1499static Datum
1501{
1504 Datum *pathtext;
1505 bool *pathnulls;
1506 bool isnull;
1507 int npath;
1508 Datum res;
1509
1510 /*
1511 * If the array contains any null elements, return NULL, on the grounds
1512 * that you'd have gotten NULL if any RHS value were NULL in a nested
1513 * series of applications of the -> operator. (Note: because we also
1514 * return NULL for error cases such as no-such-field, this is true
1515 * regardless of the contents of the rest of the array.)
1516 */
1517 if (array_contains_nulls(path))
1519
1521
1522 res = jsonb_get_element(jb, pathtext, npath, &isnull, as_text);
1523
1524 if (isnull)
1526 else
1527 PG_RETURN_DATUM(res);
1528}
1529
1530Datum
1531jsonb_get_element(Jsonb *jb, const Datum *path, int npath, bool *isnull, bool as_text)
1532{
1533 JsonbContainer *container = &jb->root;
1534 JsonbValue *jbvp = NULL;
1535 int i;
1536 bool have_object = false,
1537 have_array = false;
1538
1539 *isnull = false;
1540
1541 /* Identify whether we have object, array, or scalar at top-level */
1542 if (JB_ROOT_IS_OBJECT(jb))
1543 have_object = true;
1544 else if (JB_ROOT_IS_ARRAY(jb) && !JB_ROOT_IS_SCALAR(jb))
1545 have_array = true;
1546 else
1547 {
1549 /* Extract the scalar value, if it is what we'll return */
1550 if (npath <= 0)
1551 jbvp = getIthJsonbValueFromContainer(container, 0);
1552 }
1553
1554 /*
1555 * If the array is empty, return the entire LHS object, on the grounds
1556 * that we should do zero field or element extractions. For the
1557 * non-scalar case we can just hand back the object without much work. For
1558 * the scalar case, fall through and deal with the value below the loop.
1559 * (This inconsistency arises because there's no easy way to generate a
1560 * JsonbValue directly for root-level containers.)
1561 */
1562 if (npath <= 0 && jbvp == NULL)
1563 {
1564 if (as_text)
1565 {
1567 container,
1568 VARSIZE(jb))));
1569 }
1570 else
1571 {
1572 /* not text mode - just hand back the jsonb */
1574 }
1575 }
1576
1577 for (i = 0; i < npath; i++)
1578 {
1579 if (have_object)
1580 {
1581 text *subscr = DatumGetTextPP(path[i]);
1582
1586 NULL);
1587 }
1588 else if (have_array)
1589 {
1590 int lindex;
1591 uint32 index;
1592 char *indextext = TextDatumGetCString(path[i]);
1593 char *endptr;
1594
1595 errno = 0;
1596 lindex = strtoint(indextext, &endptr, 10);
1597 if (endptr == indextext || *endptr != '\0' || errno != 0)
1598 {
1599 *isnull = true;
1600 return PointerGetDatum(NULL);
1601 }
1602
1603 if (lindex >= 0)
1604 {
1605 index = (uint32) lindex;
1606 }
1607 else
1608 {
1609 /* Handle negative subscript */
1610 uint32 nelements;
1611
1612 /* Container must be array, but make sure */
1613 if (!JsonContainerIsArray(container))
1614 elog(ERROR, "not a jsonb array");
1615
1616 nelements = JsonContainerSize(container);
1617
1618 if (lindex == INT_MIN || -lindex > nelements)
1619 {
1620 *isnull = true;
1621 return PointerGetDatum(NULL);
1622 }
1623 else
1624 index = nelements + lindex;
1625 }
1626
1628 }
1629 else
1630 {
1631 /* scalar, extraction yields a null */
1632 *isnull = true;
1633 return PointerGetDatum(NULL);
1634 }
1635
1636 if (jbvp == NULL)
1637 {
1638 *isnull = true;
1639 return PointerGetDatum(NULL);
1640 }
1641 else if (i == npath - 1)
1642 break;
1643
1644 if (jbvp->type == jbvBinary)
1645 {
1646 container = jbvp->val.binary.data;
1648 have_array = JsonContainerIsArray(container);
1649 Assert(!JsonContainerIsScalar(container));
1650 }
1651 else
1652 {
1654 have_object = false;
1655 have_array = false;
1656 }
1657 }
1658
1659 if (as_text)
1660 {
1661 if (jbvp->type == jbvNull)
1662 {
1663 *isnull = true;
1664 return PointerGetDatum(NULL);
1665 }
1666
1668 }
1669 else
1670 {
1672
1673 /* not text mode - just hand back the jsonb */
1674 PG_RETURN_JSONB_P(res);
1675 }
1676}
1677
1678Datum
1679jsonb_set_element(Jsonb *jb, const Datum *path, int path_len,
1681{
1682 JsonbInState state = {0};
1684 bool *path_nulls = palloc0_array(bool, path_len);
1685
1686 if (newval->type == jbvArray && newval->val.array.rawScalar)
1687 *newval = newval->val.array.elems[0];
1688
1689 it = JsonbIteratorInit(&jb->root);
1690
1691 setPath(&it, path, path_nulls, path_len, &state, 0, newval,
1694
1696
1698}
1699
1700static void
1702{
1703 JsonbValue null;
1704
1705 null.type = jbvNull;
1706
1707 while (num-- > 0)
1708 pushJsonbValue(ps, WJB_ELEM, &null);
1709}
1710
1711/*
1712 * Prepare a new structure containing nested empty objects and arrays
1713 * corresponding to the specified path, and assign a new value at the end of
1714 * this path. E.g. the path [a][0][b] with the new value 1 will produce the
1715 * structure {a: [{b: 1}]}.
1716 *
1717 * Caller is responsible to make sure such path does not exist yet.
1718 */
1719static void
1720push_path(JsonbInState *st, int level, const Datum *path_elems,
1721 const bool *path_nulls, int path_len, JsonbValue *newval)
1722{
1723 /*
1724 * tpath contains expected type of an empty jsonb created at each level
1725 * higher or equal to the current one, either jbvObject or jbvArray. Since
1726 * it contains only information about path slice from level to the end,
1727 * the access index must be normalized by level.
1728 */
1729 enum jbvType *tpath = palloc0_array(enum jbvType, path_len - level);
1731
1732 /*
1733 * Create first part of the chain with beginning tokens. For the current
1734 * level WJB_BEGIN_OBJECT/WJB_BEGIN_ARRAY was already created, so start
1735 * with the next one.
1736 */
1737 for (int i = level + 1; i < path_len; i++)
1738 {
1739 char *c,
1740 *badp;
1741 int lindex;
1742
1743 if (path_nulls[i])
1744 break;
1745
1746 /*
1747 * Try to convert to an integer to find out the expected type, object
1748 * or array.
1749 */
1751 errno = 0;
1752 lindex = strtoint(c, &badp, 10);
1753 if (badp == c || *badp != '\0' || errno != 0)
1754 {
1755 /* text, an object is expected */
1756 newkey.type = jbvString;
1757 newkey.val.string.val = c;
1758 newkey.val.string.len = strlen(c);
1759
1762
1763 tpath[i - level] = jbvObject;
1764 }
1765 else
1766 {
1767 /* integer, an array is expected */
1769
1771
1772 tpath[i - level] = jbvArray;
1773 }
1774 }
1775
1776 /* Insert an actual value for either an object or array */
1777 if (tpath[(path_len - level) - 1] == jbvArray)
1779 else
1781
1782 /*
1783 * Close everything up to the last but one level. The last one will be
1784 * closed outside of this function.
1785 */
1786 for (int i = path_len - 1; i > level; i--)
1787 {
1788 if (path_nulls[i])
1789 break;
1790
1791 if (tpath[i - level] == jbvObject)
1793 else
1795 }
1796}
1797
1798/*
1799 * Return the text representation of the given JsonbValue.
1800 */
1801static text *
1803{
1804 switch (v->type)
1805 {
1806 case jbvNull:
1807 return NULL;
1808
1809 case jbvBool:
1810 return v->val.boolean ?
1811 cstring_to_text_with_len("true", 4) :
1812 cstring_to_text_with_len("false", 5);
1813
1814 case jbvString:
1815 return cstring_to_text_with_len(v->val.string.val,
1816 v->val.string.len);
1817
1818 case jbvNumeric:
1819 {
1820 Datum cstr;
1821
1823 PointerGetDatum(v->val.numeric));
1824
1826 }
1827
1828 case jbvBinary:
1829 {
1831
1833 (void) JsonbToCString(&jtext, v->val.binary.data,
1834 v->val.binary.len);
1835
1836 return cstring_to_text_with_len(jtext.data, jtext.len);
1837 }
1838
1839 default:
1840 elog(ERROR, "unrecognized jsonb type: %d", (int) v->type);
1841 return NULL;
1842 }
1843}
1844
1845/*
1846 * SQL function json_array_length(json) -> int
1847 */
1848Datum
1850{
1851 text *json = PG_GETARG_TEXT_PP(0);
1853 JsonLexContext lex;
1855
1857 state->lex = makeJsonLexContext(&lex, json, false);
1858 /* palloc0 does this for us */
1859#if 0
1860 state->count = 0;
1861#endif
1862
1864 sem->semstate = state;
1868
1870
1871 PG_RETURN_INT32(state->count);
1872}
1873
1874Datum
1876{
1878
1879 if (JB_ROOT_IS_SCALAR(jb))
1880 ereport(ERROR,
1882 errmsg("cannot get array length of a scalar")));
1883 else if (!JB_ROOT_IS_ARRAY(jb))
1884 ereport(ERROR,
1886 errmsg("cannot get array length of a non-array")));
1887
1889}
1890
1891/*
1892 * These next two checks ensure that the json is an array (since it can't be
1893 * a scalar or an object).
1894 */
1895
1896static JsonParseErrorType
1898{
1900
1901 /* json structure check */
1902 if (_state->lex->lex_level == 0)
1903 ereport(ERROR,
1905 errmsg("cannot get array length of a non-array")));
1906
1907 return JSON_SUCCESS;
1908}
1909
1910static JsonParseErrorType
1911alen_scalar(void *state, char *token, JsonTokenType tokentype)
1912{
1914
1915 /* json structure check */
1916 if (_state->lex->lex_level == 0)
1917 ereport(ERROR,
1919 errmsg("cannot get array length of a scalar")));
1920
1921 return JSON_SUCCESS;
1922}
1923
1924static JsonParseErrorType
1925alen_array_element_start(void *state, bool isnull)
1926{
1928
1929 /* just count up all the level 1 elements */
1930 if (_state->lex->lex_level == 1)
1931 _state->count++;
1932
1933 return JSON_SUCCESS;
1934}
1935
1936/*
1937 * SQL function json_each and json_each_text
1938 *
1939 * decompose a json object into key value pairs.
1940 *
1941 * Unlike json_object_keys() these SRFs operate in materialize mode,
1942 * stashing results into a Tuplestore object as they go.
1943 * The construction of tuples is done using a temporary memory context
1944 * that is cleared out after each tuple is built.
1945 */
1946Datum
1948{
1949 return each_worker(fcinfo, false);
1950}
1951
1952Datum
1954{
1955 return each_worker_jsonb(fcinfo, "jsonb_each", false);
1956}
1957
1958Datum
1960{
1961 return each_worker(fcinfo, true);
1962}
1963
1964Datum
1966{
1967 return each_worker_jsonb(fcinfo, "jsonb_each_text", true);
1968}
1969
1970static Datum
1971each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
1972{
1974 ReturnSetInfo *rsi;
1976 tmp_cxt;
1977 bool skipNested = false;
1979 JsonbValue v;
1981
1982 if (!JB_ROOT_IS_OBJECT(jb))
1983 ereport(ERROR,
1985 errmsg("cannot call %s on a non-object",
1986 funcname)));
1987
1988 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
1990
1992 "jsonb_each temporary cxt",
1994
1995 it = JsonbIteratorInit(&jb->root);
1996
1997 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
1998 {
1999 skipNested = true;
2000
2001 if (r == WJB_KEY)
2002 {
2003 text *key;
2004 Datum values[2];
2005 bool nulls[2] = {false, false};
2006
2007 /* Use the tmp context so we can clean up after each tuple is done */
2008 old_cxt = MemoryContextSwitchTo(tmp_cxt);
2009
2010 key = cstring_to_text_with_len(v.val.string.val, v.val.string.len);
2011
2012 /*
2013 * The next thing the iterator fetches should be the value, no
2014 * matter what shape it is.
2015 */
2016 r = JsonbIteratorNext(&it, &v, skipNested);
2017 Assert(r != WJB_DONE);
2018
2019 values[0] = PointerGetDatum(key);
2020
2021 if (as_text)
2022 {
2023 if (v.type == jbvNull)
2024 {
2025 /* a json null is an sql null in text mode */
2026 nulls[1] = true;
2027 values[1] = (Datum) 0;
2028 }
2029 else
2031 }
2032 else
2033 {
2034 /* Not in text mode, just return the Jsonb */
2036
2038 }
2039
2040 tuplestore_putvalues(rsi->setResult, rsi->setDesc, values, nulls);
2041
2042 /* clean up and switch back */
2044 MemoryContextReset(tmp_cxt);
2045 }
2046 }
2047
2048 MemoryContextDelete(tmp_cxt);
2049
2051}
2052
2053
2054static Datum
2056{
2057 text *json = PG_GETARG_TEXT_PP(0);
2058 JsonLexContext lex;
2060 ReturnSetInfo *rsi;
2062
2065
2066 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2067
2069 state->tuple_store = rsi->setResult;
2070 state->ret_tdesc = rsi->setDesc;
2071
2072 sem->semstate = state;
2077
2078 state->normalize_results = as_text;
2079 state->next_scalar = false;
2080 state->lex = makeJsonLexContext(&lex, json, true);
2082 "json_each temporary cxt",
2084
2086
2087 MemoryContextDelete(state->tmp_cxt);
2088 freeJsonLexContext(&lex);
2089
2091}
2092
2093
2094static JsonParseErrorType
2095each_object_field_start(void *state, char *fname, bool isnull)
2096{
2098
2099 /* save a pointer to where the value starts */
2100 if (_state->lex->lex_level == 1)
2101 {
2102 /*
2103 * next_scalar will be reset in the object_field_end handler, and
2104 * since we know the value is a scalar there is no danger of it being
2105 * on while recursing down the tree.
2106 */
2107 if (_state->normalize_results && _state->lex->token_type == JSON_TOKEN_STRING)
2108 _state->next_scalar = true;
2109 else
2110 _state->result_start = _state->lex->token_start;
2111 }
2112
2113 return JSON_SUCCESS;
2114}
2115
2116static JsonParseErrorType
2117each_object_field_end(void *state, char *fname, bool isnull)
2118{
2121 int len;
2122 text *val;
2123 HeapTuple tuple;
2124 Datum values[2];
2125 bool nulls[2] = {false, false};
2126
2127 /* skip over nested objects */
2128 if (_state->lex->lex_level != 1)
2129 return JSON_SUCCESS;
2130
2131 /* use the tmp context so we can clean up after each tuple is done */
2133
2134 values[0] = CStringGetTextDatum(fname);
2135
2136 if (isnull && _state->normalize_results)
2137 {
2138 nulls[1] = true;
2139 values[1] = (Datum) 0;
2140 }
2141 else if (_state->next_scalar)
2142 {
2143 values[1] = CStringGetTextDatum(_state->normalized_scalar);
2144 _state->next_scalar = false;
2145 }
2146 else
2147 {
2148 len = _state->lex->prev_token_terminator - _state->result_start;
2149 val = cstring_to_text_with_len(_state->result_start, len);
2151 }
2152
2153 tuple = heap_form_tuple(_state->ret_tdesc, values, nulls);
2154
2155 tuplestore_puttuple(_state->tuple_store, tuple);
2156
2157 /* clean up and switch back */
2159 MemoryContextReset(_state->tmp_cxt);
2160
2161 return JSON_SUCCESS;
2162}
2163
2164static JsonParseErrorType
2166{
2168
2169 /* json structure check */
2170 if (_state->lex->lex_level == 0)
2171 ereport(ERROR,
2173 errmsg("cannot deconstruct an array as an object")));
2174
2175 return JSON_SUCCESS;
2176}
2177
2178static JsonParseErrorType
2179each_scalar(void *state, char *token, JsonTokenType tokentype)
2180{
2182
2183 /* json structure check */
2184 if (_state->lex->lex_level == 0)
2185 ereport(ERROR,
2187 errmsg("cannot deconstruct a scalar")));
2188
2189 /* supply de-escaped value if required */
2190 if (_state->next_scalar)
2191 _state->normalized_scalar = token;
2192
2193 return JSON_SUCCESS;
2194}
2195
2196/*
2197 * SQL functions json_array_elements and json_array_elements_text
2198 *
2199 * get the elements from a json array
2200 *
2201 * a lot of this processing is similar to the json_each* functions
2202 */
2203
2204Datum
2206{
2207 return elements_worker_jsonb(fcinfo, "jsonb_array_elements", false);
2208}
2209
2210Datum
2212{
2213 return elements_worker_jsonb(fcinfo, "jsonb_array_elements_text", true);
2214}
2215
2216static Datum
2218 bool as_text)
2219{
2221 ReturnSetInfo *rsi;
2223 tmp_cxt;
2224 bool skipNested = false;
2226 JsonbValue v;
2228
2229 if (JB_ROOT_IS_SCALAR(jb))
2230 ereport(ERROR,
2232 errmsg("cannot extract elements from a scalar")));
2233 else if (!JB_ROOT_IS_ARRAY(jb))
2234 ereport(ERROR,
2236 errmsg("cannot extract elements from an object")));
2237
2238 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2239
2241
2243 "jsonb_array_elements temporary cxt",
2245
2246 it = JsonbIteratorInit(&jb->root);
2247
2248 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
2249 {
2250 skipNested = true;
2251
2252 if (r == WJB_ELEM)
2253 {
2254 Datum values[1];
2255 bool nulls[1] = {false};
2256
2257 /* use the tmp context so we can clean up after each tuple is done */
2258 old_cxt = MemoryContextSwitchTo(tmp_cxt);
2259
2260 if (as_text)
2261 {
2262 if (v.type == jbvNull)
2263 {
2264 /* a json null is an sql null in text mode */
2265 nulls[0] = true;
2266 values[0] = (Datum) 0;
2267 }
2268 else
2270 }
2271 else
2272 {
2273 /* Not in text mode, just return the Jsonb */
2275
2277 }
2278
2279 tuplestore_putvalues(rsi->setResult, rsi->setDesc, values, nulls);
2280
2281 /* clean up and switch back */
2283 MemoryContextReset(tmp_cxt);
2284 }
2285 }
2286
2287 MemoryContextDelete(tmp_cxt);
2288
2290}
2291
2292Datum
2294{
2295 return elements_worker(fcinfo, "json_array_elements", false);
2296}
2297
2298Datum
2300{
2301 return elements_worker(fcinfo, "json_array_elements_text", true);
2302}
2303
2304static Datum
2305elements_worker(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
2306{
2307 text *json = PG_GETARG_TEXT_PP(0);
2308 JsonLexContext lex;
2310 ReturnSetInfo *rsi;
2312
2313 /* elements only needs escaped strings when as_text */
2314 makeJsonLexContext(&lex, json, as_text);
2315
2318
2320 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2321 state->tuple_store = rsi->setResult;
2322 state->ret_tdesc = rsi->setDesc;
2323
2324 sem->semstate = state;
2329
2330 state->function_name = funcname;
2331 state->normalize_results = as_text;
2332 state->next_scalar = false;
2333 state->lex = &lex;
2335 "json_array_elements temporary cxt",
2337
2339
2340 MemoryContextDelete(state->tmp_cxt);
2341 freeJsonLexContext(&lex);
2342
2344}
2345
2346static JsonParseErrorType
2347elements_array_element_start(void *state, bool isnull)
2348{
2350
2351 /* save a pointer to where the value starts */
2352 if (_state->lex->lex_level == 1)
2353 {
2354 /*
2355 * next_scalar will be reset in the array_element_end handler, and
2356 * since we know the value is a scalar there is no danger of it being
2357 * on while recursing down the tree.
2358 */
2359 if (_state->normalize_results && _state->lex->token_type == JSON_TOKEN_STRING)
2360 _state->next_scalar = true;
2361 else
2362 _state->result_start = _state->lex->token_start;
2363 }
2364
2365 return JSON_SUCCESS;
2366}
2367
2368static JsonParseErrorType
2369elements_array_element_end(void *state, bool isnull)
2370{
2373 int len;
2374 text *val;
2375 HeapTuple tuple;
2376 Datum values[1];
2377 bool nulls[1] = {false};
2378
2379 /* skip over nested objects */
2380 if (_state->lex->lex_level != 1)
2381 return JSON_SUCCESS;
2382
2383 /* use the tmp context so we can clean up after each tuple is done */
2385
2386 if (isnull && _state->normalize_results)
2387 {
2388 nulls[0] = true;
2389 values[0] = (Datum) 0;
2390 }
2391 else if (_state->next_scalar)
2392 {
2393 values[0] = CStringGetTextDatum(_state->normalized_scalar);
2394 _state->next_scalar = false;
2395 }
2396 else
2397 {
2398 len = _state->lex->prev_token_terminator - _state->result_start;
2399 val = cstring_to_text_with_len(_state->result_start, len);
2401 }
2402
2403 tuple = heap_form_tuple(_state->ret_tdesc, values, nulls);
2404
2405 tuplestore_puttuple(_state->tuple_store, tuple);
2406
2407 /* clean up and switch back */
2409 MemoryContextReset(_state->tmp_cxt);
2410
2411 return JSON_SUCCESS;
2412}
2413
2414static JsonParseErrorType
2416{
2418
2419 /* json structure check */
2420 if (_state->lex->lex_level == 0)
2421 ereport(ERROR,
2423 errmsg("cannot call %s on a non-array",
2424 _state->function_name)));
2425
2426 return JSON_SUCCESS;
2427}
2428
2429static JsonParseErrorType
2430elements_scalar(void *state, char *token, JsonTokenType tokentype)
2431{
2433
2434 /* json structure check */
2435 if (_state->lex->lex_level == 0)
2436 ereport(ERROR,
2438 errmsg("cannot call %s on a scalar",
2439 _state->function_name)));
2440
2441 /* supply de-escaped value if required */
2442 if (_state->next_scalar)
2443 _state->normalized_scalar = token;
2444
2445 return JSON_SUCCESS;
2446}
2447
2448/*
2449 * SQL function json_populate_record
2450 *
2451 * set fields in a record from the argument json
2452 *
2453 * Code adapted shamelessly from hstore's populate_record
2454 * which is in turn partly adapted from record_out.
2455 *
2456 * The json is decomposed into a hash table, in which each
2457 * field in the record is then looked up by name. For jsonb
2458 * we fetch the values direct from the object.
2459 */
2460Datum
2462{
2463 return populate_record_worker(fcinfo, "jsonb_populate_record",
2464 false, true, NULL);
2465}
2466
2467/*
2468 * SQL function that can be used for testing json_populate_record().
2469 *
2470 * Returns false if json_populate_record() encounters an error for the
2471 * provided input JSON object, true otherwise.
2472 */
2473Datum
2475{
2477
2478 (void) populate_record_worker(fcinfo, "jsonb_populate_record",
2479 false, true, (Node *) &escontext);
2480
2481 return BoolGetDatum(!escontext.error_occurred);
2482}
2483
2484Datum
2486{
2487 return populate_record_worker(fcinfo, "jsonb_to_record",
2488 false, false, NULL);
2489}
2490
2491Datum
2493{
2494 return populate_record_worker(fcinfo, "json_populate_record",
2495 true, true, NULL);
2496}
2497
2498Datum
2500{
2501 return populate_record_worker(fcinfo, "json_to_record",
2502 true, false, NULL);
2503}
2504
2505/* helper function for diagnostics */
2506static void
2508{
2509 if (ndim <= 0)
2510 {
2511 if (ctx->colname)
2512 errsave(ctx->escontext,
2514 errmsg("expected JSON array"),
2515 errhint("See the value of key \"%s\".", ctx->colname)));
2516 else
2517 errsave(ctx->escontext,
2519 errmsg("expected JSON array")));
2520 return;
2521 }
2522 else
2523 {
2524 StringInfoData indices;
2525 int i;
2526
2527 initStringInfo(&indices);
2528
2529 Assert(ctx->ndims > 0 && ndim < ctx->ndims);
2530
2531 for (i = 0; i < ndim; i++)
2532 appendStringInfo(&indices, "[%d]", ctx->sizes[i]);
2533
2534 if (ctx->colname)
2535 errsave(ctx->escontext,
2537 errmsg("expected JSON array"),
2538 errhint("See the array element %s of key \"%s\".",
2539 indices.data, ctx->colname)));
2540 else
2541 errsave(ctx->escontext,
2543 errmsg("expected JSON array"),
2544 errhint("See the array element %s.",
2545 indices.data)));
2546 return;
2547 }
2548}
2549
2550/*
2551 * Validate and set ndims for populating an array with some
2552 * populate_array_*() function.
2553 *
2554 * Returns false if the input (ndims) is erroneous.
2555 */
2556static bool
2558{
2559 int i;
2560
2561 Assert(ctx->ndims <= 0);
2562
2563 if (ndims <= 0)
2564 {
2566 /* Getting here means the error was reported softly. */
2568 return false;
2569 }
2570
2571 ctx->ndims = ndims;
2572 ctx->dims = palloc_array(int, ndims);
2573 ctx->sizes = palloc0_array(int, ndims);
2574
2575 for (i = 0; i < ndims; i++)
2576 ctx->dims[i] = -1; /* dimensions are unknown yet */
2577
2578 return true;
2579}
2580
2581/*
2582 * Check the populated subarray dimension
2583 *
2584 * Returns false if the input (ndims) is erroneous.
2585 */
2586static bool
2588{
2589 int dim = ctx->sizes[ndim]; /* current dimension counter */
2590
2591 if (ctx->dims[ndim] == -1)
2592 ctx->dims[ndim] = dim; /* assign dimension if not yet known */
2593 else if (ctx->dims[ndim] != dim)
2594 ereturn(ctx->escontext, false,
2596 errmsg("malformed JSON array"),
2597 errdetail("Multidimensional arrays must have "
2598 "sub-arrays with matching dimensions.")));
2599
2600 /* reset the current array dimension size counter */
2601 ctx->sizes[ndim] = 0;
2602
2603 /* increment the parent dimension counter if it is a nested sub-array */
2604 if (ndim > 0)
2605 ctx->sizes[ndim - 1]++;
2606
2607 return true;
2608}
2609
2610/*
2611 * Returns true if the array element value was successfully extracted from jsv
2612 * and added to ctx->astate. False if an error occurred when doing so.
2613 */
2614static bool
2616{
2617 Datum element;
2618 bool element_isnull;
2619
2620 /* populate the array element */
2622 ctx->aio->element_type,
2623 ctx->aio->element_typmod,
2624 NULL, ctx->mcxt, PointerGetDatum(NULL),
2626 false);
2627 /* Nothing to do on an error. */
2629 return false;
2630
2632 ctx->aio->element_type, ctx->acxt);
2633
2634 Assert(ndim > 0);
2635 ctx->sizes[ndim - 1]++; /* increment current dimension counter */
2636
2637 return true;
2638}
2639
2640/* json object start handler for populate_array_json() */
2641static JsonParseErrorType
2643{
2645 int ndim = state->lex->lex_level;
2646
2647 if (state->ctx->ndims <= 0)
2648 {
2649 if (!populate_array_assign_ndims(state->ctx, ndim))
2651 }
2652 else if (ndim < state->ctx->ndims)
2653 {
2655 /* Getting here means the error was reported softly. */
2656 Assert(SOFT_ERROR_OCCURRED(state->ctx->escontext));
2658 }
2659
2660 return JSON_SUCCESS;
2661}
2662
2663/* json array end handler for populate_array_json() */
2664static JsonParseErrorType
2666{
2668 PopulateArrayContext *ctx = state->ctx;
2669 int ndim = state->lex->lex_level;
2670
2671 if (ctx->ndims <= 0)
2672 {
2673 if (!populate_array_assign_ndims(ctx, ndim + 1))
2675 }
2676
2677 if (ndim < ctx->ndims)
2678 {
2679 /* Report if an error occurred. */
2680 if (!populate_array_check_dimension(ctx, ndim))
2682 }
2683
2684 return JSON_SUCCESS;
2685}
2686
2687/* json array element start handler for populate_array_json() */
2688static JsonParseErrorType
2689populate_array_element_start(void *_state, bool isnull)
2690{
2692 int ndim = state->lex->lex_level;
2693
2694 if (state->ctx->ndims <= 0 || ndim == state->ctx->ndims)
2695 {
2696 /* remember current array element start */
2697 state->element_start = state->lex->token_start;
2698 state->element_type = state->lex->token_type;
2699 state->element_scalar = NULL;
2700 }
2701
2702 return JSON_SUCCESS;
2703}
2704
2705/* json array element end handler for populate_array_json() */
2706static JsonParseErrorType
2707populate_array_element_end(void *_state, bool isnull)
2708{
2710 PopulateArrayContext *ctx = state->ctx;
2711 int ndim = state->lex->lex_level;
2712
2713 Assert(ctx->ndims > 0);
2714
2715 if (ndim == ctx->ndims)
2716 {
2717 JsValue jsv;
2718
2719 jsv.is_json = true;
2720 jsv.val.json.type = state->element_type;
2721
2722 if (isnull)
2723 {
2724 Assert(jsv.val.json.type == JSON_TOKEN_NULL);
2725 jsv.val.json.str = NULL;
2726 jsv.val.json.len = 0;
2727 }
2728 else if (state->element_scalar)
2729 {
2730 jsv.val.json.str = state->element_scalar;
2731 jsv.val.json.len = -1; /* null-terminated */
2732 }
2733 else
2734 {
2735 jsv.val.json.str = state->element_start;
2736 jsv.val.json.len = (state->lex->prev_token_terminator -
2737 state->element_start) * sizeof(char);
2738 }
2739
2740 /* Report if an error occurred. */
2741 if (!populate_array_element(ctx, ndim, &jsv))
2743 }
2744
2745 return JSON_SUCCESS;
2746}
2747
2748/* json scalar handler for populate_array_json() */
2749static JsonParseErrorType
2750populate_array_scalar(void *_state, char *token, JsonTokenType tokentype)
2751{
2753 PopulateArrayContext *ctx = state->ctx;
2754 int ndim = state->lex->lex_level;
2755
2756 if (ctx->ndims <= 0)
2757 {
2758 if (!populate_array_assign_ndims(ctx, ndim))
2760 }
2761 else if (ndim < ctx->ndims)
2762 {
2764 /* Getting here means the error was reported softly. */
2767 }
2768
2769 if (ndim == ctx->ndims)
2770 {
2771 /* remember the scalar element token */
2772 state->element_scalar = token;
2773 /* element_type must already be set in populate_array_element_start() */
2774 Assert(state->element_type == tokentype);
2775 }
2776
2777 return JSON_SUCCESS;
2778}
2779
2780/*
2781 * Parse a json array and populate array
2782 *
2783 * Returns false if an error occurs when parsing.
2784 */
2785static bool
2786populate_array_json(PopulateArrayContext *ctx, const char *json, int len)
2787{
2790
2792 GetDatabaseEncoding(), true);
2793 state.ctx = ctx;
2794
2795 memset(&sem, 0, sizeof(sem));
2796 sem.semstate = &state;
2802
2804 {
2805 /* number of dimensions should be already known */
2806 Assert(ctx->ndims > 0 && ctx->dims);
2807 }
2808
2810
2811 return !SOFT_ERROR_OCCURRED(ctx->escontext);
2812}
2813
2814/*
2815 * populate_array_dim_jsonb() -- Iterate recursively through jsonb sub-array
2816 * elements and accumulate result using given ArrayBuildState.
2817 *
2818 * Returns false if we return partway through because of an error in a
2819 * subroutine.
2820 */
2821static bool
2823 JsonbValue *jbv, /* jsonb sub-array */
2824 int ndim) /* current dimension */
2825{
2826 JsonbContainer *jbc = jbv->val.binary.data;
2830 JsValue jsv;
2831
2833
2834 /* Even scalars can end up here thanks to ExecEvalJsonCoercion(). */
2835 if (jbv->type != jbvBinary || !JsonContainerIsArray(jbc) ||
2837 {
2839 /* Getting here means the error was reported softly. */
2841 return false;
2842 }
2843
2844 it = JsonbIteratorInit(jbc);
2845
2846 tok = JsonbIteratorNext(&it, &val, true);
2848
2849 tok = JsonbIteratorNext(&it, &val, true);
2850
2851 /*
2852 * If the number of dimensions is not yet known and we have found end of
2853 * the array, or the first child element is not an array, then assign the
2854 * number of dimensions now.
2855 */
2856 if (ctx->ndims <= 0 &&
2857 (tok == WJB_END_ARRAY ||
2858 (tok == WJB_ELEM &&
2859 (val.type != jbvBinary ||
2860 !JsonContainerIsArray(val.val.binary.data)))))
2861 {
2862 if (!populate_array_assign_ndims(ctx, ndim))
2863 return false;
2864 }
2865
2866 jsv.is_json = false;
2867 jsv.val.jsonb = &val;
2868
2869 /* process all the array elements */
2870 while (tok == WJB_ELEM)
2871 {
2872 /*
2873 * Recurse only if the dimensions of dimensions is still unknown or if
2874 * it is not the innermost dimension.
2875 */
2876 if (ctx->ndims > 0 && ndim >= ctx->ndims)
2877 {
2878 if (!populate_array_element(ctx, ndim, &jsv))
2879 return false;
2880 }
2881 else
2882 {
2883 /* populate child sub-array */
2884 if (!populate_array_dim_jsonb(ctx, &val, ndim + 1))
2885 return false;
2886
2887 /* number of dimensions should be already known */
2888 Assert(ctx->ndims > 0 && ctx->dims);
2889
2890 if (!populate_array_check_dimension(ctx, ndim))
2891 return false;
2892 }
2893
2894 tok = JsonbIteratorNext(&it, &val, true);
2895 }
2896
2898
2899 /* free iterator, iterating until WJB_DONE */
2900 tok = JsonbIteratorNext(&it, &val, true);
2901 Assert(tok == WJB_DONE && !it);
2902
2903 return true;
2904}
2905
2906/*
2907 * Recursively populate an array from json/jsonb
2908 *
2909 * *isnull is set to true if an error is reported during parsing.
2910 */
2911static Datum
2913 const char *colname,
2914 MemoryContext mcxt,
2915 JsValue *jsv,
2916 bool *isnull,
2917 Node *escontext)
2918{
2920 Datum result;
2921 int *lbs;
2922 int i;
2923
2924 ctx.aio = aio;
2925 ctx.mcxt = mcxt;
2927 ctx.astate = initArrayResult(aio->element_type, ctx.acxt, true);
2928 ctx.colname = colname;
2929 ctx.ndims = 0; /* unknown yet */
2930 ctx.dims = NULL;
2931 ctx.sizes = NULL;
2932 ctx.escontext = escontext;
2933
2934 if (jsv->is_json)
2935 {
2936 /* Return null if an error was found. */
2937 if (!populate_array_json(&ctx, jsv->val.json.str,
2938 jsv->val.json.len >= 0 ? jsv->val.json.len
2939 : strlen(jsv->val.json.str)))
2940 {
2941 *isnull = true;
2942 return (Datum) 0;
2943 }
2944 }
2945 else
2946 {
2947 /* Return null if an error was found. */
2948 if (!populate_array_dim_jsonb(&ctx, jsv->val.jsonb, 1))
2949 {
2950 *isnull = true;
2951 return (Datum) 0;
2952 }
2953 ctx.dims[0] = ctx.sizes[0];
2954 }
2955
2956 Assert(ctx.ndims > 0);
2957
2958 lbs = palloc_array(int, ctx.ndims);
2959
2960 for (i = 0; i < ctx.ndims; i++)
2961 lbs[i] = 1;
2962
2963 result = makeMdArrayResult(ctx.astate, ctx.ndims, ctx.dims, lbs,
2964 ctx.acxt, true);
2965
2966 pfree(ctx.dims);
2967 pfree(ctx.sizes);
2968 pfree(lbs);
2969
2970 *isnull = false;
2971 return result;
2972}
2973
2974/*
2975 * Returns false if an error occurs, provided escontext points to an
2976 * ErrorSaveContext.
2977 */
2978static bool
2980{
2981 jso->is_json = jsv->is_json;
2982
2983 if (jsv->is_json)
2984 {
2985 /* convert plain-text json into a hash table */
2986 jso->val.json_hash =
2987 get_json_object_as_hash(jsv->val.json.str,
2988 jsv->val.json.len >= 0
2989 ? jsv->val.json.len
2990 : strlen(jsv->val.json.str),
2991 "populate_composite",
2992 escontext);
2993 Assert(jso->val.json_hash != NULL || SOFT_ERROR_OCCURRED(escontext));
2994 }
2995 else
2996 {
2997 JsonbValue *jbv = jsv->val.jsonb;
2998
2999 if (jbv->type == jbvBinary &&
3000 JsonContainerIsObject(jbv->val.binary.data))
3001 {
3002 jso->val.jsonb_cont = jbv->val.binary.data;
3003 }
3004 else
3005 {
3006 bool is_scalar;
3007
3009 (jbv->type == jbvBinary &&
3010 JsonContainerIsScalar(jbv->val.binary.data));
3011 errsave(escontext,
3013 is_scalar
3014 ? errmsg("cannot call %s on a scalar",
3015 "populate_composite")
3016 : errmsg("cannot call %s on an array",
3017 "populate_composite")));
3018 }
3019 }
3020
3021 return !SOFT_ERROR_OCCURRED(escontext);
3022}
3023
3024/* acquire or update cached tuple descriptor for a composite type */
3025static void
3027{
3028 if (!io->tupdesc ||
3029 io->tupdesc->tdtypeid != io->base_typid ||
3030 io->tupdesc->tdtypmod != io->base_typmod)
3031 {
3033 io->base_typmod);
3035
3036 if (io->tupdesc)
3038
3039 /* copy tuple desc without constraints into cache memory context */
3041 io->tupdesc = CreateTupleDescCopy(tupdesc);
3043
3044 ReleaseTupleDesc(tupdesc);
3045 }
3046}
3047
3048/*
3049 * Recursively populate a composite (row type) value from json/jsonb
3050 *
3051 * Returns null if an error occurs in a subroutine, provided escontext points
3052 * to an ErrorSaveContext.
3053 */
3054static Datum
3056 Oid typid,
3057 const char *colname,
3058 MemoryContext mcxt,
3060 JsValue *jsv,
3061 bool *isnull,
3062 Node *escontext)
3063{
3064 Datum result;
3065
3066 /* acquire/update cached tuple descriptor */
3067 update_cached_tupdesc(io, mcxt);
3068
3069 if (*isnull)
3070 result = (Datum) 0;
3071 else
3072 {
3073 HeapTupleHeader tuple;
3074 JsObject jso;
3075
3076 /* prepare input value */
3077 if (!JsValueToJsObject(jsv, &jso, escontext))
3078 {
3079 *isnull = true;
3080 return (Datum) 0;
3081 }
3082
3083 /* populate resulting record tuple */
3084 tuple = populate_record(io->tupdesc, &io->record_io,
3085 defaultval, mcxt, &jso, escontext);
3086
3087 if (SOFT_ERROR_OCCURRED(escontext))
3088 {
3089 *isnull = true;
3090 return (Datum) 0;
3091 }
3092 result = HeapTupleHeaderGetDatum(tuple);
3093
3094 JsObjectFree(&jso);
3095 }
3096
3097 /*
3098 * If it's domain over composite, check domain constraints. (This should
3099 * probably get refactored so that we can see the TYPECAT value, but for
3100 * now, we can tell by comparing typid to base_typid.)
3101 */
3102 if (typid != io->base_typid && typid != RECORDOID)
3103 {
3104 if (!domain_check_safe(result, *isnull, typid, &io->domain_info, mcxt,
3105 escontext))
3106 {
3107 *isnull = true;
3108 return (Datum) 0;
3109 }
3110 }
3111
3112 return result;
3113}
3114
3115/*
3116 * Populate non-null scalar value from json/jsonb value.
3117 *
3118 * Returns null if an error occurs during the call to type input function,
3119 * provided escontext is valid.
3120 */
3121static Datum
3122populate_scalar(ScalarIOData *io, Oid typid, int32 typmod, JsValue *jsv,
3123 bool *isnull, Node *escontext, bool omit_quotes)
3124{
3125 Datum res;
3126 char *str = NULL;
3127 const char *json = NULL;
3128
3129 if (jsv->is_json)
3130 {
3131 int len = jsv->val.json.len;
3132
3133 json = jsv->val.json.str;
3134 Assert(json);
3135
3136 /* If converting to json/jsonb, make string into valid JSON literal */
3137 if ((typid == JSONOID || typid == JSONBOID) &&
3138 jsv->val.json.type == JSON_TOKEN_STRING)
3139 {
3141
3143 if (len >= 0)
3144 escape_json_with_len(&buf, json, len);
3145 else
3146 escape_json(&buf, json);
3147 str = buf.data;
3148 }
3149 else if (len >= 0)
3150 {
3151 /* create a NUL-terminated version */
3152 str = palloc(len + 1);
3153 memcpy(str, json, len);
3154 str[len] = '\0';
3155 }
3156 else
3157 {
3158 /* string is already NUL-terminated */
3159 str = unconstify(char *, json);
3160 }
3161 }
3162 else
3163 {
3164 JsonbValue *jbv = jsv->val.jsonb;
3165
3166 if (jbv->type == jbvString && omit_quotes)
3167 str = pnstrdup(jbv->val.string.val, jbv->val.string.len);
3168 else if (typid == JSONBOID)
3169 {
3170 Jsonb *jsonb = JsonbValueToJsonb(jbv); /* directly use jsonb */
3171
3172 return JsonbPGetDatum(jsonb);
3173 }
3174 /* convert jsonb to string for typio call */
3175 else if (typid == JSONOID && jbv->type != jbvBinary)
3176 {
3177 /*
3178 * Convert scalar jsonb (non-scalars are passed here as jbvBinary)
3179 * to json string, preserving quotes around top-level strings.
3180 */
3181 Jsonb *jsonb = JsonbValueToJsonb(jbv);
3182
3183 str = JsonbToCString(NULL, &jsonb->root, VARSIZE(jsonb));
3184 }
3185 else if (jbv->type == jbvString) /* quotes are stripped */
3186 str = pnstrdup(jbv->val.string.val, jbv->val.string.len);
3187 else if (jbv->type == jbvBool)
3188 str = pstrdup(jbv->val.boolean ? "true" : "false");
3189 else if (jbv->type == jbvNumeric)
3191 PointerGetDatum(jbv->val.numeric)));
3192 else if (jbv->type == jbvBinary)
3193 str = JsonbToCString(NULL, jbv->val.binary.data,
3194 jbv->val.binary.len);
3195 else
3196 elog(ERROR, "unrecognized jsonb type: %d", (int) jbv->type);
3197 }
3198
3199 if (!InputFunctionCallSafe(&io->typiofunc, str, io->typioparam, typmod,
3200 escontext, &res))
3201 {
3202 res = (Datum) 0;
3203 *isnull = true;
3204 }
3205
3206 /* free temporary buffer */
3207 if (str != json)
3208 pfree(str);
3209
3210 return res;
3211}
3212
3213static Datum
3215 Oid typid,
3216 const char *colname,
3217 MemoryContext mcxt,
3218 JsValue *jsv,
3219 bool *isnull,
3220 Node *escontext,
3221 bool omit_quotes)
3222{
3223 Datum res;
3224
3225 if (*isnull)
3226 res = (Datum) 0;
3227 else
3228 {
3230 io->base_typid, io->base_typmod,
3231 colname, mcxt, PointerGetDatum(NULL),
3232 jsv, isnull, escontext, omit_quotes);
3233 Assert(!*isnull || SOFT_ERROR_OCCURRED(escontext));
3234 }
3235
3236 if (!domain_check_safe(res, *isnull, typid, &io->domain_info, mcxt,
3237 escontext))
3238 {
3239 *isnull = true;
3240 return (Datum) 0;
3241 }
3242
3243 return res;
3244}
3245
3246/* prepare column metadata cache for the given type */
3247static void
3249 Oid typid,
3250 int32 typmod,
3251 MemoryContext mcxt,
3252 bool need_scalar)
3253{
3254 HeapTuple tup;
3256
3257 column->typid = typid;
3258 column->typmod = typmod;
3259
3261 if (!HeapTupleIsValid(tup))
3262 elog(ERROR, "cache lookup failed for type %u", typid);
3263
3265
3266 if (type->typtype == TYPTYPE_DOMAIN)
3267 {
3268 /*
3269 * We can move directly to the bottom base type; domain_check() will
3270 * take care of checking all constraints for a stack of domains.
3271 */
3272 Oid base_typid;
3273 int32 base_typmod = typmod;
3274
3275 base_typid = getBaseTypeAndTypmod(typid, &base_typmod);
3276 if (get_typtype(base_typid) == TYPTYPE_COMPOSITE)
3277 {
3278 /* domain over composite has its own code path */
3280 column->io.composite.record_io = NULL;
3281 column->io.composite.tupdesc = NULL;
3282 column->io.composite.base_typid = base_typid;
3283 column->io.composite.base_typmod = base_typmod;
3284 column->io.composite.domain_info = NULL;
3285 }
3286 else
3287 {
3288 /* domain over anything else */
3289 column->typcat = TYPECAT_DOMAIN;
3290 column->io.domain.base_typid = base_typid;
3291 column->io.domain.base_typmod = base_typmod;
3292 column->io.domain.base_io =
3293 MemoryContextAllocZero(mcxt, sizeof(ColumnIOData));
3294 column->io.domain.domain_info = NULL;
3295 }
3296 }
3297 else if (type->typtype == TYPTYPE_COMPOSITE || typid == RECORDOID)
3298 {
3299 column->typcat = TYPECAT_COMPOSITE;
3300 column->io.composite.record_io = NULL;
3301 column->io.composite.tupdesc = NULL;
3302 column->io.composite.base_typid = typid;
3303 column->io.composite.base_typmod = typmod;
3304 column->io.composite.domain_info = NULL;
3305 }
3306 else if (IsTrueArrayType(type))
3307 {
3308 column->typcat = TYPECAT_ARRAY;
3309 column->io.array.element_info = MemoryContextAllocZero(mcxt,
3310 sizeof(ColumnIOData));
3311 column->io.array.element_type = type->typelem;
3312 /* array element typemod stored in attribute's typmod */
3313 column->io.array.element_typmod = typmod;
3314 }
3315 else
3316 {
3317 column->typcat = TYPECAT_SCALAR;
3318 need_scalar = true;
3319 }
3320
3321 /* caller can force us to look up scalar_io info even for non-scalars */
3322 if (need_scalar)
3323 {
3324 Oid typioproc;
3325
3326 getTypeInputInfo(typid, &typioproc, &column->scalar_io.typioparam);
3327 fmgr_info_cxt(typioproc, &column->scalar_io.typiofunc, mcxt);
3328 }
3329
3331}
3332
3333/*
3334 * Populate and return the value of specified type from a given json/jsonb
3335 * value 'json_val'. 'cache' is caller-specified pointer to save the
3336 * ColumnIOData that will be initialized on the 1st call and then reused
3337 * during any subsequent calls. 'mcxt' gives the memory context to allocate
3338 * the ColumnIOData and any other subsidiary memory in. 'escontext',
3339 * if not NULL, tells that any errors that occur should be handled softly.
3340 */
3341Datum
3343 Oid typid, int32 typmod,
3344 void **cache, MemoryContext mcxt,
3345 bool *isnull, bool omit_quotes,
3346 Node *escontext)
3347{
3348 JsValue jsv = {0};
3350
3351 jsv.is_json = json_type == JSONOID;
3352
3353 if (*isnull)
3354 {
3355 if (jsv.is_json)
3356 jsv.val.json.str = NULL;
3357 else
3358 jsv.val.jsonb = NULL;
3359 }
3360 else if (jsv.is_json)
3361 {
3362 text *json = DatumGetTextPP(json_val);
3363
3364 jsv.val.json.str = VARDATA_ANY(json);
3365 jsv.val.json.len = VARSIZE_ANY_EXHDR(json);
3366 jsv.val.json.type = JSON_TOKEN_INVALID; /* not used in
3367 * populate_composite() */
3368 }
3369 else
3370 {
3371 Jsonb *jsonb = DatumGetJsonbP(json_val);
3372
3373 jsv.val.jsonb = &jbv;
3374
3375 if (omit_quotes)
3376 {
3378
3379 /* fill the quote-stripped string */
3380 jbv.type = jbvString;
3381 jbv.val.string.len = strlen(str);
3382 jbv.val.string.val = str;
3383 }
3384 else
3385 {
3386 /* fill binary jsonb value pointing to jb */
3387 jbv.type = jbvBinary;
3388 jbv.val.binary.data = &jsonb->root;
3389 jbv.val.binary.len = VARSIZE(jsonb) - VARHDRSZ;
3390 }
3391 }
3392
3393 if (*cache == NULL)
3394 *cache = MemoryContextAllocZero(mcxt, sizeof(ColumnIOData));
3395
3396 return populate_record_field(*cache, typid, typmod, NULL, mcxt,
3397 PointerGetDatum(NULL), &jsv, isnull,
3398 escontext, omit_quotes);
3399}
3400
3401/* recursively populate a record field or an array element from a json/jsonb value */
3402static Datum
3404 Oid typid,
3405 int32 typmod,
3406 const char *colname,
3407 MemoryContext mcxt,
3409 JsValue *jsv,
3410 bool *isnull,
3411 Node *escontext,
3412 bool omit_scalar_quotes)
3413{
3414 TypeCat typcat;
3415
3417
3418 /*
3419 * Prepare column metadata cache for the given type. Force lookup of the
3420 * scalar_io data so that the json string hack below will work.
3421 */
3422 if (col->typid != typid || col->typmod != typmod)
3423 prepare_column_cache(col, typid, typmod, mcxt, true);
3424
3425 *isnull = JsValueIsNull(jsv);
3426
3427 typcat = col->typcat;
3428
3429 /* try to convert json string to a non-scalar type through input function */
3430 if (JsValueIsString(jsv) &&
3431 (typcat == TYPECAT_ARRAY ||
3432 typcat == TYPECAT_COMPOSITE ||
3433 typcat == TYPECAT_COMPOSITE_DOMAIN))
3434 typcat = TYPECAT_SCALAR;
3435
3436 /* we must perform domain checks for NULLs, otherwise exit immediately */
3437 if (*isnull &&
3438 typcat != TYPECAT_DOMAIN &&
3439 typcat != TYPECAT_COMPOSITE_DOMAIN)
3440 return (Datum) 0;
3441
3442 switch (typcat)
3443 {
3444 case TYPECAT_SCALAR:
3445 return populate_scalar(&col->scalar_io, typid, typmod, jsv,
3446 isnull, escontext, omit_scalar_quotes);
3447
3448 case TYPECAT_ARRAY:
3449 return populate_array(&col->io.array, colname, mcxt, jsv,
3450 isnull, escontext);
3451
3452 case TYPECAT_COMPOSITE:
3454 return populate_composite(&col->io.composite, typid,
3455 colname, mcxt,
3458 : NULL,
3459 jsv, isnull,
3460 escontext);
3461
3462 case TYPECAT_DOMAIN:
3463 return populate_domain(&col->io.domain, typid, colname, mcxt,
3464 jsv, isnull, escontext, omit_scalar_quotes);
3465
3466 default:
3467 elog(ERROR, "unrecognized type category '%c'", typcat);
3468 return (Datum) 0;
3469 }
3470}
3471
3472static RecordIOData *
3473allocate_record_info(MemoryContext mcxt, int ncolumns)
3474{
3476 MemoryContextAlloc(mcxt,
3477 offsetof(RecordIOData, columns) +
3478 ncolumns * sizeof(ColumnIOData));
3479
3481 data->record_typmod = 0;
3482 data->ncolumns = ncolumns;
3483 MemSet(data->columns, 0, sizeof(ColumnIOData) * ncolumns);
3484
3485 return data;
3486}
3487
3488static bool
3489JsObjectGetField(JsObject *obj, char *field, JsValue *jsv)
3490{
3491 jsv->is_json = obj->is_json;
3492
3493 if (jsv->is_json)
3494 {
3496 HASH_FIND, NULL);
3497
3498 jsv->val.json.type = hashentry ? hashentry->type : JSON_TOKEN_NULL;
3499 jsv->val.json.str = jsv->val.json.type == JSON_TOKEN_NULL ? NULL :
3500 hashentry->val;
3501 jsv->val.json.len = jsv->val.json.str ? -1 : 0; /* null-terminated */
3502
3503 return hashentry != NULL;
3504 }
3505 else
3506 {
3507 jsv->val.jsonb = !obj->val.jsonb_cont ? NULL :
3509 NULL);
3510
3511 return jsv->val.jsonb != NULL;
3512 }
3513}
3514
3515/* populate a record tuple from json/jsonb value */
3516static HeapTupleHeader
3520 MemoryContext mcxt,
3521 JsObject *obj,
3522 Node *escontext)
3523{
3524 RecordIOData *record = *record_p;
3525 Datum *values;
3526 bool *nulls;
3527 HeapTuple res;
3528 int ncolumns = tupdesc->natts;
3529 int i;
3530
3531 /*
3532 * if the input json is empty, we can only skip the rest if we were passed
3533 * in a non-null record, since otherwise there may be issues with domain
3534 * nulls.
3535 */
3536 if (defaultval && JsObjectIsEmpty(obj))
3537 return defaultval;
3538
3539 /* (re)allocate metadata cache */
3540 if (record == NULL ||
3541 record->ncolumns != ncolumns)
3542 *record_p = record = allocate_record_info(mcxt, ncolumns);
3543
3544 /* invalidate metadata cache if the record type has changed */
3545 if (record->record_type != tupdesc->tdtypeid ||
3546 record->record_typmod != tupdesc->tdtypmod)
3547 {
3548 MemSet(record, 0, offsetof(RecordIOData, columns) +
3549 ncolumns * sizeof(ColumnIOData));
3550 record->record_type = tupdesc->tdtypeid;
3551 record->record_typmod = tupdesc->tdtypmod;
3552 record->ncolumns = ncolumns;
3553 }
3554
3555 values = (Datum *) palloc(ncolumns * sizeof(Datum));
3556 nulls = (bool *) palloc(ncolumns * sizeof(bool));
3557
3558 if (defaultval)
3559 {
3560 HeapTupleData tuple;
3561
3562 /* Build a temporary HeapTuple control structure */
3564 ItemPointerSetInvalid(&(tuple.t_self));
3565 tuple.t_tableOid = InvalidOid;
3566 tuple.t_data = defaultval;
3567
3568 /* Break down the tuple into fields */
3569 heap_deform_tuple(&tuple, tupdesc, values, nulls);
3570 }
3571 else
3572 {
3573 for (i = 0; i < ncolumns; ++i)
3574 {
3575 values[i] = (Datum) 0;
3576 nulls[i] = true;
3577 }
3578 }
3579
3580 for (i = 0; i < ncolumns; ++i)
3581 {
3583 char *colname = NameStr(att->attname);
3584 JsValue field = {0};
3585 bool found;
3586
3587 /* Ignore dropped columns in datatype */
3588 if (att->attisdropped)
3589 {
3590 nulls[i] = true;
3591 continue;
3592 }
3593
3594 found = JsObjectGetField(obj, colname, &field);
3595
3596 /*
3597 * we can't just skip here if the key wasn't found since we might have
3598 * a domain to deal with. If we were passed in a non-null record
3599 * datum, we assume that the existing values are valid (if they're
3600 * not, then it's not our fault), but if we were passed in a null,
3601 * then every field which we don't populate needs to be run through
3602 * the input function just in case it's a domain type.
3603 */
3604 if (defaultval && !found)
3605 continue;
3606
3607 values[i] = populate_record_field(&record->columns[i],
3608 att->atttypid,
3609 att->atttypmod,
3610 colname,
3611 mcxt,
3612 nulls[i] ? (Datum) 0 : values[i],
3613 &field,
3614 &nulls[i],
3615 escontext,
3616 false);
3617 }
3618
3619 res = heap_form_tuple(tupdesc, values, nulls);
3620
3621 pfree(values);
3622 pfree(nulls);
3623
3624 return res->t_data;
3625}
3626
3627/*
3628 * Setup for json{b}_populate_record{set}: result type will be same as first
3629 * argument's type --- unless first argument is "null::record", which we can't
3630 * extract type info from; we handle that later.
3631 */
3632static void
3634 const char *funcname,
3635 PopulateRecordCache *cache)
3636{
3637 cache->argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
3638 prepare_column_cache(&cache->c,
3639 cache->argtype, -1,
3640 cache->fn_mcxt, false);
3641 if (cache->c.typcat != TYPECAT_COMPOSITE &&
3643 ereport(ERROR,
3645 /* translator: %s is a function name, eg json_to_record */
3646 errmsg("first argument of %s must be a row type",
3647 funcname)));
3648}
3649
3650/*
3651 * Setup for json{b}_to_record{set}: result type is specified by calling
3652 * query. We'll also use this code for json{b}_populate_record{set},
3653 * if we discover that the first argument is a null of type RECORD.
3654 *
3655 * Here it is syntactically impossible to specify the target type
3656 * as domain-over-composite.
3657 */
3658static void
3660 const char *funcname,
3661 PopulateRecordCache *cache)
3662{
3663 TupleDesc tupdesc;
3665
3666 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
3667 ereport(ERROR,
3669 /* translator: %s is a function name, eg json_to_record */
3670 errmsg("could not determine row type for result of %s",
3671 funcname),
3672 errhint("Provide a non-null record argument, "
3673 "or call the function in the FROM clause "
3674 "using a column definition list.")));
3675
3676 Assert(tupdesc);
3677 cache->argtype = tupdesc->tdtypeid;
3678
3679 /* If we go through this more than once, avoid memory leak */
3680 if (cache->c.io.composite.tupdesc)
3682
3683 /* Save identified tupdesc */
3685 cache->c.io.composite.tupdesc = CreateTupleDescCopy(tupdesc);
3686 cache->c.io.composite.base_typid = tupdesc->tdtypeid;
3687 cache->c.io.composite.base_typmod = tupdesc->tdtypmod;
3689}
3690
3691/*
3692 * common worker for json{b}_populate_record() and json{b}_to_record()
3693 * is_json and have_record_arg identify the specific function
3694 */
3695static Datum
3697 bool is_json, bool have_record_arg,
3698 Node *escontext)
3699{
3700 int json_arg_num = have_record_arg ? 1 : 0;
3701 JsValue jsv = {0};
3702 HeapTupleHeader rec;
3704 bool isnull;
3707 PopulateRecordCache *cache = fcinfo->flinfo->fn_extra;
3708
3709 /*
3710 * If first time through, identify input/result record type. Note that
3711 * this stanza looks only at fcinfo context, which can't change during the
3712 * query; so we may not be able to fully resolve a RECORD input type yet.
3713 */
3714 if (!cache)
3715 {
3716 fcinfo->flinfo->fn_extra = cache =
3717 MemoryContextAllocZero(fnmcxt, sizeof(*cache));
3718 cache->fn_mcxt = fnmcxt;
3719
3720 if (have_record_arg)
3722 else
3723 get_record_type_from_query(fcinfo, funcname, cache);
3724 }
3725
3726 /* Collect record arg if we have one */
3727 if (!have_record_arg)
3728 rec = NULL; /* it's json{b}_to_record() */
3729 else if (!PG_ARGISNULL(0))
3730 {
3732
3733 /*
3734 * When declared arg type is RECORD, identify actual record type from
3735 * the tuple itself.
3736 */
3737 if (cache->argtype == RECORDOID)
3738 {
3741 }
3742 }
3743 else
3744 {
3745 rec = NULL;
3746
3747 /*
3748 * When declared arg type is RECORD, identify actual record type from
3749 * calling query, or fail if we can't.
3750 */
3751 if (cache->argtype == RECORDOID)
3752 {
3753 get_record_type_from_query(fcinfo, funcname, cache);
3754 /* This can't change argtype, which is important for next time */
3755 Assert(cache->argtype == RECORDOID);
3756 }
3757 }
3758
3759 /* If no JSON argument, just return the record (if any) unchanged */
3761 {
3762 if (rec)
3763 PG_RETURN_POINTER(rec);
3764 else
3766 }
3767
3768 jsv.is_json = is_json;
3769
3770 if (is_json)
3771 {
3773
3774 jsv.val.json.str = VARDATA_ANY(json);
3775 jsv.val.json.len = VARSIZE_ANY_EXHDR(json);
3776 jsv.val.json.type = JSON_TOKEN_INVALID; /* not used in
3777 * populate_composite() */
3778 }
3779 else
3780 {
3782
3783 jsv.val.jsonb = &jbv;
3784
3785 /* fill binary jsonb value pointing to jb */
3786 jbv.type = jbvBinary;
3787 jbv.val.binary.data = &jb->root;
3788 jbv.val.binary.len = VARSIZE(jb) - VARHDRSZ;
3789 }
3790
3791 isnull = false;
3792 rettuple = populate_composite(&cache->c.io.composite, cache->argtype,
3793 NULL, fnmcxt, rec, &jsv, &isnull,
3794 escontext);
3795 Assert(!isnull || SOFT_ERROR_OCCURRED(escontext));
3796
3798}
3799
3800/*
3801 * get_json_object_as_hash
3802 *
3803 * Decomposes a json object into a hash table.
3804 *
3805 * Returns the hash table if the json is parsed successfully, NULL otherwise.
3806 */
3807static HTAB *
3808get_json_object_as_hash(const char *json, int len, const char *funcname,
3809 Node *escontext)
3810{
3811 HASHCTL ctl;
3812 HTAB *tab;
3815
3816 ctl.keysize = NAMEDATALEN;
3817 ctl.entrysize = sizeof(JsonHashEntry);
3819 tab = hash_create("json object hashtable",
3820 100,
3821 &ctl,
3823
3826
3827 state->function_name = funcname;
3828 state->hash = tab;
3830 GetDatabaseEncoding(), true);
3831
3832 sem->semstate = state;
3837
3838 if (!pg_parse_json_or_errsave(state->lex, sem, escontext))
3839 {
3840 hash_destroy(state->hash);
3841 tab = NULL;
3842 }
3843
3845
3846 return tab;
3847}
3848
3849static JsonParseErrorType
3850hash_object_field_start(void *state, char *fname, bool isnull)
3851{
3853
3854 if (_state->lex->lex_level > 1)
3855 return JSON_SUCCESS;
3856
3857 /* remember token type */
3858 _state->saved_token_type = _state->lex->token_type;
3859
3860 if (_state->lex->token_type == JSON_TOKEN_ARRAY_START ||
3861 _state->lex->token_type == JSON_TOKEN_OBJECT_START)
3862 {
3863 /* remember start position of the whole text of the subobject */
3864 _state->save_json_start = _state->lex->token_start;
3865 }
3866 else
3867 {
3868 /* must be a scalar */
3869 _state->save_json_start = NULL;
3870 }
3871
3872 return JSON_SUCCESS;
3873}
3874
3875static JsonParseErrorType
3876hash_object_field_end(void *state, char *fname, bool isnull)
3877{
3880 bool found;
3881
3882 /*
3883 * Ignore nested fields.
3884 */
3885 if (_state->lex->lex_level > 1)
3886 return JSON_SUCCESS;
3887
3888 /*
3889 * Ignore field names >= NAMEDATALEN - they can't match a record field.
3890 * (Note: without this test, the hash code would truncate the string at
3891 * NAMEDATALEN-1, and could then match against a similarly-truncated
3892 * record field name. That would be a reasonable behavior, but this code
3893 * has previously insisted on exact equality, so we keep this behavior.)
3894 */
3895 if (strlen(fname) >= NAMEDATALEN)
3896 return JSON_SUCCESS;
3897
3898 hashentry = hash_search(_state->hash, fname, HASH_ENTER, &found);
3899
3900 /*
3901 * found being true indicates a duplicate. We don't do anything about
3902 * that, a later field with the same name overrides the earlier field.
3903 */
3904
3905 hashentry->type = _state->saved_token_type;
3906 Assert(isnull == (hashentry->type == JSON_TOKEN_NULL));
3907
3908 if (_state->save_json_start != NULL)
3909 {
3910 int len = _state->lex->prev_token_terminator - _state->save_json_start;
3911 char *val = palloc((len + 1) * sizeof(char));
3912
3913 memcpy(val, _state->save_json_start, len);
3914 val[len] = '\0';
3915 hashentry->val = val;
3916 }
3917 else
3918 {
3919 /* must have had a scalar instead */
3920 hashentry->val = _state->saved_scalar;
3921 }
3922
3923 return JSON_SUCCESS;
3924}
3925
3926static JsonParseErrorType
3928{
3930
3931 if (_state->lex->lex_level == 0)
3932 ereport(ERROR,
3934 errmsg("cannot call %s on an array", _state->function_name)));
3935
3936 return JSON_SUCCESS;
3937}
3938
3939static JsonParseErrorType
3940hash_scalar(void *state, char *token, JsonTokenType tokentype)
3941{
3943
3944 if (_state->lex->lex_level == 0)
3945 ereport(ERROR,
3947 errmsg("cannot call %s on a scalar", _state->function_name)));
3948
3949 if (_state->lex->lex_level == 1)
3950 {
3951 _state->saved_scalar = token;
3952 /* saved_token_type must already be set in hash_object_field_start() */
3953 Assert(_state->saved_token_type == tokentype);
3954 }
3955
3956 return JSON_SUCCESS;
3957}
3958
3959
3960/*
3961 * SQL function json_populate_recordset
3962 *
3963 * set fields in a set of records from the argument json,
3964 * which must be an array of objects.
3965 *
3966 * similar to json_populate_record, but the tuple-building code
3967 * is pushed down into the semantic action handlers so it's done
3968 * per object in the array.
3969 */
3970Datum
3972{
3973 return populate_recordset_worker(fcinfo, "jsonb_populate_recordset",
3974 false, true);
3975}
3976
3977Datum
3979{
3980 return populate_recordset_worker(fcinfo, "jsonb_to_recordset",
3981 false, false);
3982}
3983
3984Datum
3986{
3987 return populate_recordset_worker(fcinfo, "json_populate_recordset",
3988 true, true);
3989}
3990
3991Datum
3993{
3994 return populate_recordset_worker(fcinfo, "json_to_recordset",
3995 true, false);
3996}
3997
3998static void
4000{
4001 PopulateRecordCache *cache = state->cache;
4003 HeapTupleData tuple;
4004
4005 /* acquire/update cached tuple descriptor */
4006 update_cached_tupdesc(&cache->c.io.composite, cache->fn_mcxt);
4007
4008 /* replace record fields from json */
4010 &cache->c.io.composite.record_io,
4011 state->rec,
4012 cache->fn_mcxt,
4013 obj,
4014 NULL);
4015
4016 /* if it's domain over composite, check domain constraints */
4017 if (cache->c.typcat == TYPECAT_COMPOSITE_DOMAIN)
4019 cache->argtype,
4020 &cache->c.io.composite.domain_info,
4021 cache->fn_mcxt,
4022 NULL);
4023
4024 /* ok, save into tuplestore */
4026 ItemPointerSetInvalid(&(tuple.t_self));
4027 tuple.t_tableOid = InvalidOid;
4028 tuple.t_data = tuphead;
4029
4030 tuplestore_puttuple(state->tuple_store, &tuple);
4031}
4032
4033/*
4034 * common worker for json{b}_populate_recordset() and json{b}_to_recordset()
4035 * is_json and have_record_arg identify the specific function
4036 */
4037static Datum
4039 bool is_json, bool have_record_arg)
4040{
4041 int json_arg_num = have_record_arg ? 1 : 0;
4042 ReturnSetInfo *rsi;
4044 HeapTupleHeader rec;
4045 PopulateRecordCache *cache = fcinfo->flinfo->fn_extra;
4047
4048 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
4049
4050 if (!rsi || !IsA(rsi, ReturnSetInfo))
4051 ereport(ERROR,
4053 errmsg("set-valued function called in context that cannot accept a set")));
4054
4055 if (!(rsi->allowedModes & SFRM_Materialize))
4056 ereport(ERROR,
4058 errmsg("materialize mode required, but it is not allowed in this context")));
4059
4061
4062 /*
4063 * If first time through, identify input/result record type. Note that
4064 * this stanza looks only at fcinfo context, which can't change during the
4065 * query; so we may not be able to fully resolve a RECORD input type yet.
4066 */
4067 if (!cache)
4068 {
4069 fcinfo->flinfo->fn_extra = cache =
4070 MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt, sizeof(*cache));
4071 cache->fn_mcxt = fcinfo->flinfo->fn_mcxt;
4072
4073 if (have_record_arg)
4075 else
4076 get_record_type_from_query(fcinfo, funcname, cache);
4077 }
4078
4079 /* Collect record arg if we have one */
4080 if (!have_record_arg)
4081 rec = NULL; /* it's json{b}_to_recordset() */
4082 else if (!PG_ARGISNULL(0))
4083 {
4085
4086 /*
4087 * When declared arg type is RECORD, identify actual record type from
4088 * the tuple itself.
4089 */
4090 if (cache->argtype == RECORDOID)
4091 {
4094 }
4095 }
4096 else
4097 {
4098 rec = NULL;
4099
4100 /*
4101 * When declared arg type is RECORD, identify actual record type from
4102 * calling query, or fail if we can't.
4103 */
4104 if (cache->argtype == RECORDOID)
4105 {
4106 get_record_type_from_query(fcinfo, funcname, cache);
4107 /* This can't change argtype, which is important for next time */
4108 Assert(cache->argtype == RECORDOID);
4109 }
4110 }
4111
4112 /* if the json is null send back an empty set */
4115
4116 /*
4117 * Forcibly update the cached tupdesc, to ensure we have the right tupdesc
4118 * to return even if the JSON contains no rows.
4119 */
4120 update_cached_tupdesc(&cache->c.io.composite, cache->fn_mcxt);
4121
4123
4124 /* make tuplestore in a sufficiently long-lived memory context */
4126 state->tuple_store = tuplestore_begin_heap(rsi->allowedModes &
4128 false, work_mem);
4130
4131 state->function_name = funcname;
4132 state->cache = cache;
4133 state->rec = rec;
4134
4135 if (is_json)
4136 {
4138 JsonLexContext lex;
4140
4142
4143 makeJsonLexContext(&lex, json, true);
4144
4145 sem->semstate = state;
4153
4154 state->lex = &lex;
4155
4157
4158 freeJsonLexContext(&lex);
4159 state->lex = NULL;
4160 }
4161 else
4162 {
4165 JsonbValue v;
4166 bool skipNested = false;
4168
4170 ereport(ERROR,
4172 errmsg("cannot call %s on a non-array",
4173 funcname)));
4174
4175 it = JsonbIteratorInit(&jb->root);
4176
4177 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4178 {
4179 skipNested = true;
4180
4181 if (r == WJB_ELEM)
4182 {
4183 JsObject obj;
4184
4185 if (v.type != jbvBinary ||
4186 !JsonContainerIsObject(v.val.binary.data))
4187 ereport(ERROR,
4189 errmsg("argument of %s must be an array of objects",
4190 funcname)));
4191
4192 obj.is_json = false;
4193 obj.val.jsonb_cont = v.val.binary.data;
4194
4196 }
4197 }
4198 }
4199
4200 /*
4201 * Note: we must copy the cached tupdesc because the executor will free
4202 * the passed-back setDesc, but we want to hang onto the cache in case
4203 * we're called again in the same query.
4204 */
4205 rsi->setResult = state->tuple_store;
4207
4209}
4210
4211static JsonParseErrorType
4213{
4215 int lex_level = _state->lex->lex_level;
4216 HASHCTL ctl;
4217
4218 /* Reject object at top level: we must have an array at level 0 */
4219 if (lex_level == 0)
4220 ereport(ERROR,
4222 errmsg("cannot call %s on an object",
4223 _state->function_name)));
4224
4225 /* Nested objects require no special processing */
4226 if (lex_level > 1)
4227 return JSON_SUCCESS;
4228
4229 /* Object at level 1: set up a new hash table for this object */
4230 ctl.keysize = NAMEDATALEN;
4231 ctl.entrysize = sizeof(JsonHashEntry);
4233 _state->json_hash = hash_create("json object hashtable",
4234 100,
4235 &ctl,
4237
4238 return JSON_SUCCESS;
4239}
4240
4241static JsonParseErrorType
4243{
4245 JsObject obj;
4246
4247 /* Nested objects require no special processing */
4248 if (_state->lex->lex_level > 1)
4249 return JSON_SUCCESS;
4250
4251 obj.is_json = true;
4252 obj.val.json_hash = _state->json_hash;
4253
4254 /* Otherwise, construct and return a tuple based on this level-1 object */
4256
4257 /* Done with hash for this object */
4258 hash_destroy(_state->json_hash);
4259 _state->json_hash = NULL;
4260
4261 return JSON_SUCCESS;
4262}
4263
4264static JsonParseErrorType
4266{
4268
4269 if (_state->lex->lex_level == 1 &&
4270 _state->lex->token_type != JSON_TOKEN_OBJECT_START)
4271 ereport(ERROR,
4273 errmsg("argument of %s must be an array of objects",
4274 _state->function_name)));
4275
4276 return JSON_SUCCESS;
4277}
4278
4279static JsonParseErrorType
4281{
4282 /* nothing to do */
4283 return JSON_SUCCESS;
4284}
4285
4286static JsonParseErrorType
4287populate_recordset_scalar(void *state, char *token, JsonTokenType tokentype)
4288{
4290
4291 if (_state->lex->lex_level == 0)
4292 ereport(ERROR,
4294 errmsg("cannot call %s on a scalar",
4295 _state->function_name)));
4296
4297 if (_state->lex->lex_level == 2)
4298 _state->saved_scalar = token;
4299
4300 return JSON_SUCCESS;
4301}
4302
4303static JsonParseErrorType
4304populate_recordset_object_field_start(void *state, char *fname, bool isnull)
4305{
4307
4308 if (_state->lex->lex_level > 2)
4309 return JSON_SUCCESS;
4310
4311 _state->saved_token_type = _state->lex->token_type;
4312
4313 if (_state->lex->token_type == JSON_TOKEN_ARRAY_START ||
4314 _state->lex->token_type == JSON_TOKEN_OBJECT_START)
4315 {
4316 _state->save_json_start = _state->lex->token_start;
4317 }
4318 else
4319 {
4320 _state->save_json_start = NULL;
4321 }
4322
4323 return JSON_SUCCESS;
4324}
4325
4326static JsonParseErrorType
4327populate_recordset_object_field_end(void *state, char *fname, bool isnull)
4328{
4331 bool found;
4332
4333 /*
4334 * Ignore nested fields.
4335 */
4336 if (_state->lex->lex_level > 2)
4337 return JSON_SUCCESS;
4338
4339 /*
4340 * Ignore field names >= NAMEDATALEN - they can't match a record field.
4341 * (Note: without this test, the hash code would truncate the string at
4342 * NAMEDATALEN-1, and could then match against a similarly-truncated
4343 * record field name. That would be a reasonable behavior, but this code
4344 * has previously insisted on exact equality, so we keep this behavior.)
4345 */
4346 if (strlen(fname) >= NAMEDATALEN)
4347 return JSON_SUCCESS;
4348
4349 hashentry = hash_search(_state->json_hash, fname, HASH_ENTER, &found);
4350
4351 /*
4352 * found being true indicates a duplicate. We don't do anything about
4353 * that, a later field with the same name overrides the earlier field.
4354 */
4355
4356 hashentry->type = _state->saved_token_type;
4357 Assert(isnull == (hashentry->type == JSON_TOKEN_NULL));
4358
4359 if (_state->save_json_start != NULL)
4360 {
4361 int len = _state->lex->prev_token_terminator - _state->save_json_start;
4362 char *val = palloc((len + 1) * sizeof(char));
4363
4364 memcpy(val, _state->save_json_start, len);
4365 val[len] = '\0';
4366 hashentry->val = val;
4367 }
4368 else
4369 {
4370 /* must have had a scalar instead */
4371 hashentry->val = _state->saved_scalar;
4372 }
4373
4374 return JSON_SUCCESS;
4375}
4376
4377/*
4378 * Semantic actions for json_strip_nulls.
4379 *
4380 * Simply repeat the input on the output unless we encounter
4381 * a null object field. State for this is set when the field
4382 * is started and reset when the scalar action (which must be next)
4383 * is called.
4384 */
4385
4386static JsonParseErrorType
4388{
4390
4391 appendStringInfoCharMacro(_state->strval, '{');
4392
4393 return JSON_SUCCESS;
4394}
4395
4396static JsonParseErrorType
4397sn_object_end(void *state)
4398{
4400
4401 appendStringInfoCharMacro(_state->strval, '}');
4402
4403 return JSON_SUCCESS;
4404}
4405
4406static JsonParseErrorType
4407sn_array_start(void *state)
4408{
4410
4411 appendStringInfoCharMacro(_state->strval, '[');
4412
4413 return JSON_SUCCESS;
4414}
4415
4416static JsonParseErrorType
4417sn_array_end(void *state)
4418{
4420
4421 appendStringInfoCharMacro(_state->strval, ']');
4422
4423 return JSON_SUCCESS;
4424}
4425
4426static JsonParseErrorType
4427sn_object_field_start(void *state, char *fname, bool isnull)
4428{
4430
4431 if (isnull)
4432 {
4433 /*
4434 * The next thing must be a scalar or isnull couldn't be true, so
4435 * there is no danger of this state being carried down into a nested
4436 * object or array. The flag will be reset in the scalar action.
4437 */
4438 _state->skip_next_null = true;
4439 return JSON_SUCCESS;
4440 }
4441
4442 if (_state->strval->data[_state->strval->len - 1] != '{')
4443 appendStringInfoCharMacro(_state->strval, ',');
4444
4445 /*
4446 * Unfortunately we don't have the quoted and escaped string any more, so
4447 * we have to re-escape it.
4448 */
4449 escape_json(_state->strval, fname);
4450
4451 appendStringInfoCharMacro(_state->strval, ':');
4452
4453 return JSON_SUCCESS;
4454}
4455
4456static JsonParseErrorType
4457sn_array_element_start(void *state, bool isnull)
4458{
4460
4461 /* If strip_in_arrays is enabled and this is a null, mark it for skipping */
4462 if (isnull && _state->strip_in_arrays)
4463 {
4464 _state->skip_next_null = true;
4465 return JSON_SUCCESS;
4466 }
4467
4468 /* Only add a comma if this is not the first valid element */
4469 if (_state->strval->len > 0 &&
4470 _state->strval->data[_state->strval->len - 1] != '[')
4471 {
4472 appendStringInfoCharMacro(_state->strval, ',');
4473 }
4474
4475 return JSON_SUCCESS;
4476}
4477
4478static JsonParseErrorType
4479sn_scalar(void *state, char *token, JsonTokenType tokentype)
4480{
4482
4483 if (_state->skip_next_null)
4484 {
4485 Assert(tokentype == JSON_TOKEN_NULL);
4486 _state->skip_next_null = false;
4487 return JSON_SUCCESS;
4488 }
4489
4490 if (tokentype == JSON_TOKEN_STRING)
4491 escape_json(_state->strval, token);
4492 else
4494
4495 return JSON_SUCCESS;
4496}
4497
4498/*
4499 * SQL function json_strip_nulls(json) -> json
4500 */
4501Datum
4503{
4504 text *json = PG_GETARG_TEXT_PP(0);
4505 bool strip_in_arrays = PG_NARGS() == 2 ? PG_GETARG_BOOL(1) : false;
4508 JsonLexContext lex;
4510
4514
4515 state->lex = makeJsonLexContext(&lex, json, true);
4516 state->strval = &strbuf;
4517 state->skip_next_null = false;
4518 state->strip_in_arrays = strip_in_arrays;
4519
4520 sem->semstate = state;
4525 sem->scalar = sn_scalar;
4528
4530
4532 state->strval->len));
4533}
4534
4535/*
4536 * SQL function jsonb_strip_nulls(jsonb, bool) -> jsonb
4537 */
4538Datum
4540{
4542 bool strip_in_arrays = false;
4544 JsonbInState parseState = {0};
4545 JsonbValue v,
4546 k;
4548 bool last_was_key = false;
4549
4550 if (PG_NARGS() == 2)
4551 strip_in_arrays = PG_GETARG_BOOL(1);
4552
4553 if (JB_ROOT_IS_SCALAR(jb))
4555
4556 it = JsonbIteratorInit(&jb->root);
4557
4558 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
4559 {
4560 Assert(!(type == WJB_KEY && last_was_key));
4561
4562 if (type == WJB_KEY)
4563 {
4564 /* stash the key until we know if it has a null value */
4565 k = v;
4566 last_was_key = true;
4567 continue;
4568 }
4569
4570 if (last_was_key)
4571 {
4572 /* if the last element was a key this one can't be */
4573 last_was_key = false;
4574
4575 /* skip this field if value is null */
4576 if (type == WJB_VALUE && v.type == jbvNull)
4577 continue;
4578
4579 /* otherwise, do a delayed push of the key */
4580 pushJsonbValue(&parseState, WJB_KEY, &k);
4581 }
4582
4583 /* if strip_in_arrays is set, also skip null array elements */
4584 if (strip_in_arrays)
4585 if (type == WJB_ELEM && v.type == jbvNull)
4586 continue;
4587
4588 if (type == WJB_VALUE || type == WJB_ELEM)
4589 pushJsonbValue(&parseState, type, &v);
4590 else
4591 pushJsonbValue(&parseState, type, NULL);
4592 }
4593
4595}
4596
4597/*
4598 * SQL function jsonb_pretty (jsonb)
4599 *
4600 * Pretty-printed text for the jsonb
4601 */
4602Datum
4604{
4607
4609 JsonbToCStringIndent(&str, &jb->root, VARSIZE(jb));
4610
4612}
4613
4614/*
4615 * SQL function jsonb_concat (jsonb, jsonb)
4616 *
4617 * function for || operator
4618 */
4619Datum
4621{
4624 JsonbInState state = {0};
4626 *it2;
4627
4628 /*
4629 * If one of the jsonb is empty, just return the other if it's not scalar
4630 * and both are of the same kind. If it's a scalar or they are of
4631 * different kinds we need to perform the concatenation even if one is
4632 * empty.
4633 */
4635 {
4636 if (JB_ROOT_COUNT(jb1) == 0 && !JB_ROOT_IS_SCALAR(jb2))
4638 else if (JB_ROOT_COUNT(jb2) == 0 && !JB_ROOT_IS_SCALAR(jb1))
4640 }
4641
4642 it1 = JsonbIteratorInit(&jb1->root);
4643 it2 = JsonbIteratorInit(&jb2->root);
4644
4646
4648}
4649
4650
4651/*
4652 * SQL function jsonb_delete (jsonb, text)
4653 *
4654 * return a copy of the jsonb with the indicated item
4655 * removed.
4656 */
4657Datum
4659{
4660 Jsonb *in = PG_GETARG_JSONB_P(0);
4662 char *keyptr = VARDATA_ANY(key);
4663 int keylen = VARSIZE_ANY_EXHDR(key);
4664 JsonbInState pstate = {0};
4666 JsonbValue v;
4667 bool skipNested = false;
4669
4670 if (JB_ROOT_IS_SCALAR(in))
4671 ereport(ERROR,
4673 errmsg("cannot delete from scalar")));
4674
4675 if (JB_ROOT_COUNT(in) == 0)
4677
4678 it = JsonbIteratorInit(&in->root);
4679
4680 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4681 {
4682 skipNested = true;
4683
4684 if ((r == WJB_ELEM || r == WJB_KEY) &&
4685 (v.type == jbvString && keylen == v.val.string.len &&
4686 memcmp(keyptr, v.val.string.val, keylen) == 0))
4687 {
4688 /* skip corresponding value as well */
4689 if (r == WJB_KEY)
4690 (void) JsonbIteratorNext(&it, &v, true);
4691
4692 continue;
4693 }
4694
4695 pushJsonbValue(&pstate, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4696 }
4697
4699}
4700
4701/*
4702 * SQL function jsonb_delete (jsonb, variadic text[])
4703 *
4704 * return a copy of the jsonb with the indicated items
4705 * removed.
4706 */
4707Datum
4709{
4710 Jsonb *in = PG_GETARG_JSONB_P(0);
4713 bool *keys_nulls;
4714 int keys_len;
4715 JsonbInState pstate = {0};
4717 JsonbValue v;
4718 bool skipNested = false;
4720
4721 if (ARR_NDIM(keys) > 1)
4722 ereport(ERROR,
4724 errmsg("wrong number of array subscripts")));
4725
4726 if (JB_ROOT_IS_SCALAR(in))
4727 ereport(ERROR,
4729 errmsg("cannot delete from scalar")));
4730
4731 if (JB_ROOT_COUNT(in) == 0)
4733
4735
4736 if (keys_len == 0)
4738
4739 it = JsonbIteratorInit(&in->root);
4740
4741 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4742 {
4743 skipNested = true;
4744
4745 if ((r == WJB_ELEM || r == WJB_KEY) && v.type == jbvString)
4746 {
4747 int i;
4748 bool found = false;
4749
4750 for (i = 0; i < keys_len; i++)
4751 {
4752 char *keyptr;
4753 int keylen;
4754
4755 if (keys_nulls[i])
4756 continue;
4757
4758 /* We rely on the array elements not being toasted */
4761 if (keylen == v.val.string.len &&
4762 memcmp(keyptr, v.val.string.val, keylen) == 0)
4763 {
4764 found = true;
4765 break;
4766 }
4767 }
4768 if (found)
4769 {
4770 /* skip corresponding value as well */
4771 if (r == WJB_KEY)
4772 (void) JsonbIteratorNext(&it, &v, true);
4773
4774 continue;
4775 }
4776 }
4777
4778 pushJsonbValue(&pstate, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4779 }
4780
4782}
4783
4784/*
4785 * SQL function jsonb_delete (jsonb, int)
4786 *
4787 * return a copy of the jsonb with the indicated item
4788 * removed. Negative int means count back from the
4789 * end of the items.
4790 */
4791Datum
4793{
4794 Jsonb *in = PG_GETARG_JSONB_P(0);
4795 int idx = PG_GETARG_INT32(1);
4796 JsonbInState pstate = {0};
4798 uint32 i = 0,
4799 n;
4800 JsonbValue v;
4802
4803 if (JB_ROOT_IS_SCALAR(in))
4804 ereport(ERROR,
4806 errmsg("cannot delete from scalar")));
4807
4808 if (JB_ROOT_IS_OBJECT(in))
4809 ereport(ERROR,
4811 errmsg("cannot delete from object using integer index")));
4812
4813 if (JB_ROOT_COUNT(in) == 0)
4815
4816 it = JsonbIteratorInit(&in->root);
4817
4818 r = JsonbIteratorNext(&it, &v, false);
4819 Assert(r == WJB_BEGIN_ARRAY);
4820 n = v.val.array.nElems;
4821
4822 if (idx < 0)
4823 {
4824 if (pg_abs_s32(idx) > n)
4825 idx = n;
4826 else
4827 idx = n + idx;
4828 }
4829
4830 if (idx >= n)
4832
4833 pushJsonbValue(&pstate, r, NULL);
4834
4835 while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
4836 {
4837 if (r == WJB_ELEM)
4838 {
4839 if (i++ == idx)
4840 continue;
4841 }
4842
4843 pushJsonbValue(&pstate, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4844 }
4845
4847}
4848
4849/*
4850 * SQL function jsonb_set(jsonb, text[], jsonb, boolean)
4851 */
4852Datum
4854{
4855 Jsonb *in = PG_GETARG_JSONB_P(0);
4859 bool create = PG_GETARG_BOOL(3);
4861 bool *path_nulls;
4862 int path_len;
4864 JsonbInState st = {0};
4865
4867
4868 if (ARR_NDIM(path) > 1)
4869 ereport(ERROR,
4871 errmsg("wrong number of array subscripts")));
4872
4873 if (JB_ROOT_IS_SCALAR(in))
4874 ereport(ERROR,
4876 errmsg("cannot set path in scalar")));
4877
4878 if (JB_ROOT_COUNT(in) == 0 && !create)
4880
4882
4883 if (path_len == 0)
4885
4886 it = JsonbIteratorInit(&in->root);
4887
4889 0, &newval, create ? JB_PATH_CREATE : JB_PATH_REPLACE);
4890
4892}
4893
4894
4895/*
4896 * SQL function jsonb_set_lax(jsonb, text[], jsonb, boolean, text)
4897 */
4898Datum
4900{
4902 char *handle_val;
4903
4904 if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(3))
4906
4907 /* could happen if they pass in an explicit NULL */
4908 if (PG_ARGISNULL(4))
4909 ereport(ERROR,
4911 errmsg("null_value_treatment must be \"delete_key\", \"return_target\", \"use_json_null\", or \"raise_exception\"")));
4912
4913 /* if the new value isn't an SQL NULL just call jsonb_set */
4914 if (!PG_ARGISNULL(2))
4915 return jsonb_set(fcinfo);
4916
4919
4920 if (strcmp(handle_val, "raise_exception") == 0)
4921 {
4922 ereport(ERROR,
4924 errmsg("JSON value must not be null"),
4925 errdetail("Exception was raised because null_value_treatment is \"raise_exception\"."),
4926 errhint("To avoid, either change the null_value_treatment argument or ensure that an SQL NULL is not passed.")));
4927 return (Datum) 0; /* silence stupider compilers */
4928 }
4929 else if (strcmp(handle_val, "use_json_null") == 0)
4930 {
4931 Datum newval;
4932
4934
4935 fcinfo->args[2].value = newval;
4936 fcinfo->args[2].isnull = false;
4937 return jsonb_set(fcinfo);
4938 }
4939 else if (strcmp(handle_val, "delete_key") == 0)
4940 {
4941 return jsonb_delete_path(fcinfo);
4942 }
4943 else if (strcmp(handle_val, "return_target") == 0)
4944 {
4945 Jsonb *in = PG_GETARG_JSONB_P(0);
4946
4948 }
4949 else
4950 {
4951 ereport(ERROR,
4953 errmsg("null_value_treatment must be \"delete_key\", \"return_target\", \"use_json_null\", or \"raise_exception\"")));
4954 return (Datum) 0; /* silence stupider compilers */
4955 }
4956}
4957
4958/*
4959 * SQL function jsonb_delete_path(jsonb, text[])
4960 */
4961Datum
4963{
4964 Jsonb *in = PG_GETARG_JSONB_P(0);
4967 bool *path_nulls;
4968 int path_len;
4970 JsonbInState st = {0};
4971
4972 if (ARR_NDIM(path) > 1)
4973 ereport(ERROR,
4975 errmsg("wrong number of array subscripts")));
4976
4977 if (JB_ROOT_IS_SCALAR(in))
4978 ereport(ERROR,
4980 errmsg("cannot delete path in scalar")));
4981
4982 if (JB_ROOT_COUNT(in) == 0)
4984
4986
4987 if (path_len == 0)
4989
4990 it = JsonbIteratorInit(&in->root);
4991
4993 0, NULL, JB_PATH_DELETE);
4994
4996}
4997
4998/*
4999 * SQL function jsonb_insert(jsonb, text[], jsonb, boolean)
5000 */
5001Datum
5003{
5004 Jsonb *in = PG_GETARG_JSONB_P(0);
5008 bool after = PG_GETARG_BOOL(3);
5010 bool *path_nulls;
5011 int path_len;
5013 JsonbInState st = {0};
5014
5016
5017 if (ARR_NDIM(path) > 1)
5018 ereport(ERROR,
5020 errmsg("wrong number of array subscripts")));
5021
5022 if (JB_ROOT_IS_SCALAR(in))
5023 ereport(ERROR,
5025 errmsg("cannot set path in scalar")));
5026
5028
5029 if (path_len == 0)
5031
5032 it = JsonbIteratorInit(&in->root);
5033
5036
5038}
5039
5040/*
5041 * Iterate over all jsonb objects and merge them into one.
5042 * The logic of this function copied from the same hstore function,
5043 * except the case, when it1 & it2 represents jbvObject.
5044 * In that case we just append the content of it2 to it1 without any
5045 * verifications.
5046 */
5047static void
5050{
5051 JsonbValue v1,
5052 v2;
5054 r2,
5055 rk1,
5056 rk2;
5057
5058 rk1 = JsonbIteratorNext(it1, &v1, false);
5059 rk2 = JsonbIteratorNext(it2, &v2, false);
5060
5061 /*
5062 * JsonbIteratorNext reports raw scalars as if they were single-element
5063 * arrays; hence we only need consider "object" and "array" cases here.
5064 */
5066 {
5067 /*
5068 * Both inputs are objects.
5069 *
5070 * Append all the tokens from v1 to res, except last WJB_END_OBJECT
5071 * (because res will not be finished yet).
5072 */
5074 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_OBJECT)
5076
5077 /*
5078 * Append all the tokens from v2 to res, including last WJB_END_OBJECT
5079 * (the concatenation will be completed). Any duplicate keys will
5080 * automatically override the value from the first object.
5081 */
5082 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5084 }
5085 else if (rk1 == WJB_BEGIN_ARRAY && rk2 == WJB_BEGIN_ARRAY)
5086 {
5087 /*
5088 * Both inputs are arrays.
5089 */
5091
5092 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_ARRAY)
5093 {
5094 Assert(r1 == WJB_ELEM);
5096 }
5097
5098 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_END_ARRAY)
5099 {
5100 Assert(r2 == WJB_ELEM);
5102 }
5103
5104 pushJsonbValue(state, WJB_END_ARRAY, NULL /* signal to sort */ );
5105 }
5106 else if (rk1 == WJB_BEGIN_OBJECT)
5107 {
5108 /*
5109 * We have object || array.
5110 */
5112
5114
5116 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_DONE)
5118
5119 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5121 }
5122 else
5123 {
5124 /*
5125 * We have array || object.
5126 */
5129
5131
5132 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_ARRAY)
5134
5136 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5138
5140 }
5141}
5142
5143/*
5144 * Do most of the heavy work for jsonb_set/jsonb_insert
5145 *
5146 * If JB_PATH_DELETE bit is set in op_type, the element is to be removed.
5147 *
5148 * If any bit mentioned in JB_PATH_CREATE_OR_INSERT is set in op_type,
5149 * we create the new value if the key or array index does not exist.
5150 *
5151 * Bits JB_PATH_INSERT_BEFORE and JB_PATH_INSERT_AFTER in op_type
5152 * behave as JB_PATH_CREATE if new value is inserted in JsonbObject.
5153 *
5154 * If JB_PATH_FILL_GAPS bit is set, this will change an assignment logic in
5155 * case if target is an array. The assignment index will not be restricted by
5156 * number of elements in the array, and if there are any empty slots between
5157 * last element of the array and a new one they will be filled with nulls. If
5158 * the index is negative, it still will be considered an index from the end
5159 * of the array. Of a part of the path is not present and this part is more
5160 * than just one last element, this flag will instruct to create the whole
5161 * chain of corresponding objects and insert the value.
5162 *
5163 * JB_PATH_CONSISTENT_POSITION for an array indicates that the caller wants to
5164 * keep values with fixed indices. Indices for existing elements could be
5165 * changed (shifted forward) in case if the array is prepended with a new value
5166 * and a negative index out of the range, so this behavior will be prevented
5167 * and return an error.
5168 *
5169 * All path elements before the last must already exist
5170 * whatever bits in op_type are set, or nothing is done.
5171 */
5172static void
5174 const bool *path_nulls, int path_len,
5175 JsonbInState *st, int level, JsonbValue *newval, int op_type)
5176{
5177 JsonbValue v;
5179
5181
5182 if (path_nulls[level])
5183 ereport(ERROR,
5185 errmsg("path element at position %d is null",
5186 level + 1)));
5187
5188 r = JsonbIteratorNext(it, &v, false);
5189
5190 switch (r)
5191 {
5192 case WJB_BEGIN_ARRAY:
5193
5194 /*
5195 * If instructed complain about attempts to replace within a raw
5196 * scalar value. This happens even when current level is equal to
5197 * path_len, because the last path key should also correspond to
5198 * an object or an array, not raw scalar.
5199 */
5200 if ((op_type & JB_PATH_FILL_GAPS) && (level <= path_len - 1) &&
5201 v.val.array.rawScalar)
5202 ereport(ERROR,
5204 errmsg("cannot replace existing key"),
5205 errdetail("The path assumes key is a composite object, "
5206 "but it is a scalar value.")));
5207
5208 pushJsonbValue(st, r, NULL);
5210 newval, v.val.array.nElems, op_type);
5211 r = JsonbIteratorNext(it, &v, false);
5212 Assert(r == WJB_END_ARRAY);
5213 pushJsonbValue(st, r, NULL);
5214 break;
5215 case WJB_BEGIN_OBJECT:
5216 pushJsonbValue(st, r, NULL);
5218 newval, v.val.object.nPairs, op_type);
5219 r = JsonbIteratorNext(it, &v, true);
5220 Assert(r == WJB_END_OBJECT);
5221 pushJsonbValue(st, r, NULL);
5222 break;
5223 case WJB_ELEM:
5224 case WJB_VALUE:
5225
5226 /*
5227 * If instructed complain about attempts to replace within a
5228 * scalar value. This happens even when current level is equal to
5229 * path_len, because the last path key should also correspond to
5230 * an object or an array, not an element or value.
5231 */
5232 if ((op_type & JB_PATH_FILL_GAPS) && (level <= path_len - 1))
5233 ereport(ERROR,
5235 errmsg("cannot replace existing key"),
5236 errdetail("The path assumes key is a composite object, "
5237 "but it is a scalar value.")));
5238
5239 pushJsonbValue(st, r, &v);
5240 break;
5241 default:
5242 elog(ERROR, "unrecognized iterator result: %d", (int) r);
5243 break;
5244 }
5245}
5246
5247/*
5248 * Object walker for setPath
5249 */
5250static void
5252 int path_len, JsonbInState *st, int level,
5254{
5255 text *pathelem = NULL;
5256 int i;
5257 JsonbValue k,
5258 v;
5259 bool done = false;
5260
5261 if (level >= path_len || path_nulls[level])
5262 done = true;
5263 else
5264 {
5265 /* The path Datum could be toasted, in which case we must detoast it */
5267 }
5268
5269 /* empty object is a special case for create */
5270 if ((npairs == 0) && (op_type & JB_PATH_CREATE_OR_INSERT) &&
5271 (level == path_len - 1))
5272 {
5274
5276 newkey.val.string.val = VARDATA_ANY(pathelem);
5277 newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
5278
5281 }
5282
5283 for (i = 0; i < npairs; i++)
5284 {
5286
5287 Assert(r == WJB_KEY);
5288
5289 if (!done &&
5290 k.val.string.len == VARSIZE_ANY_EXHDR(pathelem) &&
5291 memcmp(k.val.string.val, VARDATA_ANY(pathelem),
5292 k.val.string.len) == 0)
5293 {
5294 done = true;
5295
5296 if (level == path_len - 1)
5297 {
5298 /*
5299 * called from jsonb_insert(), it forbids redefining an
5300 * existing value
5301 */
5303 ereport(ERROR,
5305 errmsg("cannot replace existing key"),
5306 errhint("Try using the function jsonb_set "
5307 "to replace key value.")));
5308
5309 r = JsonbIteratorNext(it, &v, true); /* skip value */
5310 if (!(op_type & JB_PATH_DELETE))
5311 {
5312 pushJsonbValue(st, WJB_KEY, &k);
5314 }
5315 }
5316 else
5317 {
5318 pushJsonbValue(st, r, &k);
5320 st, level + 1, newval, op_type);
5321 }
5322 }
5323 else
5324 {
5325 if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done &&
5326 level == path_len - 1 && i == npairs - 1)
5327 {
5329
5331 newkey.val.string.val = VARDATA_ANY(pathelem);
5332 newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
5333
5336 }
5337
5338 pushJsonbValue(st, r, &k);
5339 r = JsonbIteratorNext(it, &v, false);
5340 pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5341 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5342 {
5343 int walking_level = 1;
5344
5345 while (walking_level != 0)
5346 {
5347 r = JsonbIteratorNext(it, &v, false);
5348
5349 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5350 ++walking_level;
5351 if (r == WJB_END_ARRAY || r == WJB_END_OBJECT)
5352 --walking_level;
5353
5354 pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5355 }
5356 }
5357 }
5358 }
5359
5360 /*--
5361 * If we got here there are only few possibilities:
5362 * - no target path was found, and an open object with some keys/values was
5363 * pushed into the state
5364 * - an object is empty, only WJB_BEGIN_OBJECT is pushed
5365 *
5366 * In both cases if instructed to create the path when not present,
5367 * generate the whole chain of empty objects and insert the new value
5368 * there.
5369 */
5370 if (!done && (op_type & JB_PATH_FILL_GAPS) && (level < path_len - 1))
5371 {
5373
5375 newkey.val.string.val = VARDATA_ANY(pathelem);
5376 newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
5377
5380
5381 /* Result is closed with WJB_END_OBJECT outside of this function */
5382 }
5383}
5384
5385/*
5386 * Array walker for setPath
5387 */
5388static void
5390 int path_len, JsonbInState *st, int level,
5391 JsonbValue *newval, uint32 nelems, int op_type)
5392{
5393 JsonbValue v;
5394 int idx,
5395 i;
5396 bool done = false;
5397
5398 /* pick correct index */
5399 if (level < path_len && !path_nulls[level])
5400 {
5401 char *c = TextDatumGetCString(path_elems[level]);
5402 char *badp;
5403
5404 errno = 0;
5405 idx = strtoint(c, &badp, 10);
5406 if (badp == c || *badp != '\0' || errno != 0)
5407 ereport(ERROR,
5409 errmsg("path element at position %d is not an integer: \"%s\"",
5410 level + 1, c)));
5411 }
5412 else
5413 idx = nelems;
5414
5415 if (idx < 0)
5416 {
5417 if (pg_abs_s32(idx) > nelems)
5418 {
5419 /*
5420 * If asked to keep elements position consistent, it's not allowed
5421 * to prepend the array.
5422 */
5424 ereport(ERROR,
5426 errmsg("path element at position %d is out of range: %d",
5427 level + 1, idx)));
5428 else
5429 idx = PG_INT32_MIN;
5430 }
5431 else
5432 idx = nelems + idx;
5433 }
5434
5435 /*
5436 * Filling the gaps means there are no limits on the positive index are
5437 * imposed, we can set any element. Otherwise limit the index by nelems.
5438 */
5439 if (!(op_type & JB_PATH_FILL_GAPS))
5440 {
5441 if (idx > 0 && idx > nelems)
5442 idx = nelems;
5443 }
5444
5445 /*
5446 * if we're creating, and idx == INT_MIN, we prepend the new value to the
5447 * array also if the array is empty - in which case we don't really care
5448 * what the idx value is
5449 */
5450 if ((idx == INT_MIN || nelems == 0) && (level == path_len - 1) &&
5452 {
5453 Assert(newval != NULL);
5454
5455 if (op_type & JB_PATH_FILL_GAPS && nelems == 0 && idx > 0)
5457
5459
5460 done = true;
5461 }
5462
5463 /* iterate over the array elements */
5464 for (i = 0; i < nelems; i++)
5465 {
5467
5468 if (i == idx && level < path_len)
5469 {
5470 done = true;
5471
5472 if (level == path_len - 1)
5473 {
5474 r = JsonbIteratorNext(it, &v, true); /* skip */
5475
5478
5479 /*
5480 * We should keep current value only in case of
5481 * JB_PATH_INSERT_BEFORE or JB_PATH_INSERT_AFTER because
5482 * otherwise it should be deleted or replaced
5483 */
5485 pushJsonbValue(st, r, &v);
5486
5489 }
5490 else
5492 st, level + 1, newval, op_type);
5493 }
5494 else
5495 {
5496 r = JsonbIteratorNext(it, &v, false);
5497
5498 pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5499
5500 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5501 {
5502 int walking_level = 1;
5503
5504 while (walking_level != 0)
5505 {
5506 r = JsonbIteratorNext(it, &v, false);
5507
5508 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5509 ++walking_level;
5510 if (r == WJB_END_ARRAY || r == WJB_END_OBJECT)
5511 --walking_level;
5512
5513 pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5514 }
5515 }
5516 }
5517 }
5518
5519 if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done && level == path_len - 1)
5520 {
5521 /*
5522 * If asked to fill the gaps, idx could be bigger than nelems, so
5523 * prepend the new element with nulls if that's the case.
5524 */
5525 if (op_type & JB_PATH_FILL_GAPS && idx > nelems)
5526 push_null_elements(st, idx - nelems);
5527
5529 done = true;
5530 }
5531
5532 /*--
5533 * If we got here there are only few possibilities:
5534 * - no target path was found, and an open array with some keys/values was
5535 * pushed into the state
5536 * - an array is empty, only WJB_BEGIN_ARRAY is pushed
5537 *
5538 * In both cases if instructed to create the path when not present,
5539 * generate the whole chain of empty objects and insert the new value
5540 * there.
5541 */
5542 if (!done && (op_type & JB_PATH_FILL_GAPS) && (level < path_len - 1))
5543 {
5544 if (idx > 0)
5545 push_null_elements(st, idx - nelems);
5546
5548
5549 /* Result is closed with WJB_END_OBJECT outside of this function */
5550 }
5551}
5552
5553/*
5554 * Parse information about what elements of a jsonb document we want to iterate
5555 * in functions iterate_json(b)_values. This information is presented in jsonb
5556 * format, so that it can be easily extended in the future.
5557 */
5558uint32
5560{
5562 JsonbValue v;
5564 uint32 flags = 0;
5565
5566 it = JsonbIteratorInit(&jb->root);
5567
5568 type = JsonbIteratorNext(&it, &v, false);
5569
5570 /*
5571 * We iterate over array (scalar internally is represented as array, so,
5572 * we will accept it too) to check all its elements. Flag names are
5573 * chosen the same as jsonb_typeof uses.
5574 */
5575 if (type != WJB_BEGIN_ARRAY)
5577 errmsg("wrong flag type, only arrays and scalars are allowed")));
5578
5579 while ((type = JsonbIteratorNext(&it, &v, false)) == WJB_ELEM)
5580 {
5581 if (v.type != jbvString)
5582 ereport(ERROR,
5584 errmsg("flag array element is not a string"),
5585 errhint("Possible values are: \"string\", \"numeric\", \"boolean\", \"key\", and \"all\".")));
5586
5587 if (v.val.string.len == 3 &&
5588 pg_strncasecmp(v.val.string.val, "all", 3) == 0)
5589 flags |= jtiAll;
5590 else if (v.val.string.len == 3 &&
5591 pg_strncasecmp(v.val.string.val, "key", 3) == 0)
5592 flags |= jtiKey;
5593 else if (v.val.string.len == 6 &&
5594 pg_strncasecmp(v.val.string.val, "string", 6) == 0)
5595 flags |= jtiString;
5596 else if (v.val.string.len == 7 &&
5597 pg_strncasecmp(v.val.string.val, "numeric", 7) == 0)
5598 flags |= jtiNumeric;
5599 else if (v.val.string.len == 7 &&
5600 pg_strncasecmp(v.val.string.val, "boolean", 7) == 0)
5601 flags |= jtiBool;
5602 else
5603 ereport(ERROR,
5605 errmsg("wrong flag in flag array: \"%s\"",
5606 pnstrdup(v.val.string.val, v.val.string.len)),
5607 errhint("Possible values are: \"string\", \"numeric\", \"boolean\", \"key\", and \"all\".")));
5608 }
5609
5610 /* expect end of array now */
5611 if (type != WJB_END_ARRAY)
5612 elog(ERROR, "unexpected end of flag array");
5613
5614 /* get final WJB_DONE and free iterator */
5615 type = JsonbIteratorNext(&it, &v, false);
5616 if (type != WJB_DONE)
5617 elog(ERROR, "unexpected end of flag array");
5618
5619 return flags;
5620}
5621
5622/*
5623 * Iterate over jsonb values or elements, specified by flags, and pass them
5624 * together with an iteration state to a specified JsonIterateStringValuesAction.
5625 */
5626void
5629{
5631 JsonbValue v;
5633
5634 it = JsonbIteratorInit(&jb->root);
5635
5636 /*
5637 * Just recursively iterating over jsonb and call callback on all
5638 * corresponding elements
5639 */
5640 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
5641 {
5642 if (type == WJB_KEY)
5643 {
5644 if (flags & jtiKey)
5645 action(state, v.val.string.val, v.val.string.len);
5646
5647 continue;
5648 }
5649 else if (!(type == WJB_VALUE || type == WJB_ELEM))
5650 {
5651 /* do not call callback for composite JsonbValue */
5652 continue;
5653 }
5654
5655 /* JsonbValue is a value of object or element of array */
5656 switch (v.type)
5657 {
5658 case jbvString:
5659 if (flags & jtiString)
5660 action(state, v.val.string.val, v.val.string.len);
5661 break;
5662 case jbvNumeric:
5663 if (flags & jtiNumeric)
5664 {
5665 char *val;
5666
5668 NumericGetDatum(v.val.numeric)));
5669
5671 pfree(val);
5672 }
5673 break;
5674 case jbvBool:
5675 if (flags & jtiBool)
5676 {
5677 if (v.val.boolean)
5678 action(state, "true", 4);
5679 else
5680 action(state, "false", 5);
5681 }
5682 break;
5683 default:
5684 /* do not call callback for composite JsonbValue */
5685 break;
5686 }
5687 }
5688}
5689
5690/*
5691 * Iterate over json values and elements, specified by flags, and pass them
5692 * together with an iteration state to a specified JsonIterateStringValuesAction.
5693 */
5694void
5695iterate_json_values(text *json, uint32 flags, void *action_state,
5697{
5698 JsonLexContext lex;
5701
5702 state->lex = makeJsonLexContext(&lex, json, true);
5703 state->action = action;
5704 state->action_state = action_state;
5705 state->flags = flags;
5706
5707 sem->semstate = state;
5710
5712 freeJsonLexContext(&lex);
5713}
5714
5715/*
5716 * An auxiliary function for iterate_json_values to invoke a specified
5717 * JsonIterateStringValuesAction for specified values.
5718 */
5719static JsonParseErrorType
5720iterate_values_scalar(void *state, char *token, JsonTokenType tokentype)
5721{
5723
5724 switch (tokentype)
5725 {
5726 case JSON_TOKEN_STRING:
5727 if (_state->flags & jtiString)
5728 _state->action(_state->action_state, token, strlen(token));
5729 break;
5730 case JSON_TOKEN_NUMBER:
5731 if (_state->flags & jtiNumeric)
5732 _state->action(_state->action_state, token, strlen(token));
5733 break;
5734 case JSON_TOKEN_TRUE:
5735 case JSON_TOKEN_FALSE:
5736 if (_state->flags & jtiBool)
5737 _state->action(_state->action_state, token, strlen(token));
5738 break;
5739 default:
5740 /* do not call callback for any other token */
5741 break;
5742 }
5743
5744 return JSON_SUCCESS;
5745}
5746
5747static JsonParseErrorType
5748iterate_values_object_field_start(void *state, char *fname, bool isnull)
5749{
5751
5752 if (_state->flags & jtiKey)
5753 {
5754 char *val = pstrdup(fname);
5755
5756 _state->action(_state->action_state, val, strlen(val));
5757 }
5758
5759 return JSON_SUCCESS;
5760}
5761
5762/*
5763 * Iterate over a jsonb, and apply a specified JsonTransformStringValuesAction
5764 * to every string value or element. Any necessary context for a
5765 * JsonTransformStringValuesAction can be passed in the action_state variable.
5766 * Function returns a copy of an original jsonb object with transformed values.
5767 */
5768Jsonb *
5769transform_jsonb_string_values(Jsonb *jsonb, void *action_state,
5771{
5773 JsonbValue v;
5775 JsonbInState st = {0};
5776 text *out;
5777 bool is_scalar = false;
5778
5779 it = JsonbIteratorInit(&jsonb->root);
5780 is_scalar = it->isScalar;
5781
5782 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
5783 {
5784 if ((type == WJB_VALUE || type == WJB_ELEM) && v.type == jbvString)
5785 {
5786 out = transform_action(action_state, v.val.string.val, v.val.string.len);
5787 /* out is probably not toasted, but let's be sure */
5788 out = pg_detoast_datum_packed(out);
5789 v.val.string.val = VARDATA_ANY(out);
5790 v.val.string.len = VARSIZE_ANY_EXHDR(out);
5792 }
5793 else
5794 {
5795 pushJsonbValue(&st, type, (type == WJB_KEY ||
5796 type == WJB_VALUE ||
5797 type == WJB_ELEM) ? &v : NULL);
5798 }
5799 }
5800
5801 if (st.result->type == jbvArray)
5802 st.result->val.array.rawScalar = is_scalar;
5803
5804 return JsonbValueToJsonb(st.result);
5805}
5806
5807/*
5808 * Iterate over a json, and apply a specified JsonTransformStringValuesAction
5809 * to every string value or element. Any necessary context for a
5810 * JsonTransformStringValuesAction can be passed in the action_state variable.
5811 * Function returns a Text Datum, which is a copy of an original json with
5812 * transformed values.
5813 */
5814text *
5815transform_json_string_values(text *json, void *action_state,
5817{
5818 JsonLexContext lex;
5822
5824
5825 state->lex = makeJsonLexContext(&lex, json, true);
5826 state->strval = &strbuf;
5827 state->action = transform_action;
5828 state->action_state = action_state;
5829
5830 sem->semstate = state;
5838
5840 freeJsonLexContext(&lex);
5841
5842 return cstring_to_text_with_len(state->strval->data, state->strval->len);
5843}
5844
5845/*
5846 * Set of auxiliary functions for transform_json_string_values to invoke a
5847 * specified JsonTransformStringValuesAction for all values and left everything
5848 * else untouched.
5849 */
5850static JsonParseErrorType
5852{
5854
5855 appendStringInfoCharMacro(_state->strval, '{');
5856
5857 return JSON_SUCCESS;
5858}
5859
5860static JsonParseErrorType
5862{
5864
5865 appendStringInfoCharMacro(_state->strval, '}');
5866
5867 return JSON_SUCCESS;
5868}
5869
5870static JsonParseErrorType
5872{
5874
5875 appendStringInfoCharMacro(_state->strval, '[');
5876
5877 return JSON_SUCCESS;
5878}
5879
5880static JsonParseErrorType
5882{
5884
5885 appendStringInfoCharMacro(_state->strval, ']');
5886
5887 return JSON_SUCCESS;
5888}
5889
5890static JsonParseErrorType
5891transform_string_values_object_field_start(void *state, char *fname, bool isnull)
5892{
5894
5895 if (_state->strval->data[_state->strval->len - 1] != '{')
5896 appendStringInfoCharMacro(_state->strval, ',');
5897
5898 /*
5899 * Unfortunately we don't have the quoted and escaped string any more, so
5900 * we have to re-escape it.
5901 */
5902 escape_json(_state->strval, fname);
5903 appendStringInfoCharMacro(_state->strval, ':');
5904
5905 return JSON_SUCCESS;
5906}
5907
5908static JsonParseErrorType
5910{
5912
5913 if (_state->strval->data[_state->strval->len - 1] != '[')
5914 appendStringInfoCharMacro(_state->strval, ',');
5915
5916 return JSON_SUCCESS;
5917}
5918
5919static JsonParseErrorType
5921{
5923
5924 if (tokentype == JSON_TOKEN_STRING)
5925 {
5926 text *out = _state->action(_state->action_state, token, strlen(token));
5927
5928 escape_json_text(_state->strval, out);
5929 }
5930 else
5932
5933 return JSON_SUCCESS;
5934}
5935
5938{
5939 JsonLexContext lex;
5940 JsonParseErrorType result;
5941
5942 makeJsonLexContext(&lex, json, false);
5943
5944 /* Lex exactly one token from the input and check its type. */
5945 result = json_lex(&lex);
5946
5947 if (result == JSON_SUCCESS)
5948 return lex.token_type;
5949
5950 if (throw_error)
5951 json_errsave_error(result, &lex, NULL);
5952
5953 return JSON_TOKEN_INVALID; /* invalid json */
5954}
5955
5956/*
5957 * Determine how we want to print values of a given type in datum_to_json(b).
5958 *
5959 * Given the datatype OID, return its JsonTypeCategory, as well as the type's
5960 * output function OID. If the returned category is JSONTYPE_CAST, we return
5961 * the OID of the type->JSON cast function instead.
5962 */
5963void
5964json_categorize_type(Oid typoid, bool is_jsonb,
5966{
5967 bool typisvarlena;
5968
5969 /* Look through any domain */
5970 typoid = getBaseType(typoid);
5971
5973
5974 switch (typoid)
5975 {
5976 case BOOLOID:
5979 break;
5980
5981 case INT2OID:
5982 case INT4OID:
5983 case INT8OID:
5984 case FLOAT4OID:
5985 case FLOAT8OID:
5986 case NUMERICOID:
5987 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
5989 break;
5990
5991 case DATEOID:
5994 break;
5995
5996 case TIMESTAMPOID:
5999 break;
6000
6001 case TIMESTAMPTZOID:
6004 break;
6005
6006 case JSONOID:
6007 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6009 break;
6010
6011 case JSONBOID:
6012 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6014 break;
6015
6016 default:
6017 /* Check for arrays and composites */
6018 if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
6019 || typoid == ANYCOMPATIBLEARRAYOID || typoid == RECORDARRAYOID)
6020 {
6023 }
6024 else if (type_is_rowtype(typoid)) /* includes RECORDOID */
6025 {
6028 }
6029 else
6030 {
6031 /*
6032 * It's probably the general case. But let's look for a cast
6033 * to json (note: not to jsonb even if is_jsonb is true), if
6034 * it's not built-in.
6035 */
6037 if (typoid >= FirstNormalObjectId)
6038 {
6039 Oid castfunc;
6040 CoercionPathType ctype;
6041
6042 ctype = find_coercion_pathway(JSONOID, typoid,
6044 &castfunc);
6045 if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc))
6046 {
6047 *outfuncoid = castfunc;
6049 }
6050 else
6051 {
6052 /* non builtin type with no cast */
6053 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6054 }
6055 }
6056 else
6057 {
6058 /* any other builtin type */
6059 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6060 }
6061 }
6062 break;
6063 }
6064}
Datum idx(PG_FUNCTION_ARGS)
Definition _int_op.c:262
#define ARR_NDIM(a)
Definition array.h:290
#define PG_GETARG_ARRAYTYPE_P(n)
Definition array.h:263
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
bool array_contains_nulls(const ArrayType *array)
Datum makeMdArrayResult(ArrayBuildState *astate, int ndims, int *dims, int *lbs, MemoryContext rcontext, bool release)
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
void deconstruct_array_builtin(const ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Datum numeric_out(PG_FUNCTION_ARGS)
Definition numeric.c:799
static Datum values[MAXATTR]
Definition bootstrap.c:155
#define CStringGetTextDatum(s)
Definition builtins.h:97
#define TextDatumGetCString(d)
Definition builtins.h:98
#define NameStr(name)
Definition c.h:765
#define unconstify(underlying_type, expr)
Definition c.h:1234
#define IS_HIGHBIT_SET(ch)
Definition c.h:1144
#define VARHDRSZ
Definition c.h:711
#define Assert(condition)
Definition c.h:873
#define FLEXIBLE_ARRAY_MEMBER
Definition c.h:480
int32_t int32
Definition c.h:542
uint32_t uint32
Definition c.h:546
#define PG_INT32_MIN
Definition c.h:602
#define MemSet(start, val, len)
Definition c.h:1013
#define OidIsValid(objectId)
Definition c.h:788
bool domain_check_safe(Datum value, bool isnull, Oid domainType, void **extra, MemoryContext mcxt, Node *escontext)
Definition domains.c:355
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:952
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition dynahash.c:358
void hash_destroy(HTAB *hashp)
Definition dynahash.c:865
int errdetail_internal(const char *fmt,...)
Definition elog.c:1243
int errdetail(const char *fmt,...)
Definition elog.c:1216
int errhint(const char *fmt,...)
Definition elog.c:1330
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define ereturn(context, dummy_value,...)
Definition elog.h:278
#define errsave(context,...)
Definition elog.h:262
#define errcontext
Definition elog.h:198
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple)
@ SFRM_Materialize_Random
Definition execnodes.h:344
@ SFRM_Materialize
Definition execnodes.h:343
#define palloc_object(type)
Definition fe_memutils.h:74
#define palloc_array(type, count)
Definition fe_memutils.h:76
#define palloc0_array(type, count)
Definition fe_memutils.h:77
#define palloc0_object(type)
Definition fe_memutils.h:75
struct varlena * pg_detoast_datum_packed(struct varlena *datum)
Definition fmgr.c:1829
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition fmgr.c:138
bool InputFunctionCallSafe(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod, Node *escontext, Datum *result)
Definition fmgr.c:1585
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition fmgr.c:1875
#define PG_GETARG_TEXT_PP(n)
Definition fmgr.h:310
#define DatumGetHeapTupleHeader(X)
Definition fmgr.h:296
#define DatumGetTextPP(X)
Definition fmgr.h:293
#define PG_ARGISNULL(n)
Definition fmgr.h:209
#define DirectFunctionCall1(func, arg1)
Definition fmgr.h:684
#define PG_NARGS()
Definition fmgr.h:203
#define PG_RETURN_NULL()
Definition fmgr.h:346
#define PG_GETARG_HEAPTUPLEHEADER(n)
Definition fmgr.h:313
#define PG_RETURN_TEXT_P(x)
Definition fmgr.h:374
#define PG_RETURN_INT32(x)
Definition fmgr.h:355
#define PG_GETARG_INT32(n)
Definition fmgr.h:269
#define PG_GETARG_BOOL(n)
Definition fmgr.h:274
#define PG_RETURN_DATUM(x)
Definition fmgr.h:354
#define PG_RETURN_POINTER(x)
Definition fmgr.h:363
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
#define PG_GETARG_TEXT_P(n)
Definition fmgr.h:337
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition funcapi.c:76
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition funcapi.c:276
#define SRF_IS_FIRSTCALL()
Definition funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition funcapi.h:308
@ TYPEFUNC_COMPOSITE
Definition funcapi.h:149
#define MAT_SRF_BLESS
Definition funcapi.h:297
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition funcapi.h:306
#define SRF_RETURN_DONE(_funcctx)
Definition funcapi.h:328
#define MAT_SRF_USE_EXPECTED_DESC
Definition funcapi.h:296
int work_mem
Definition globals.c:131
#define newval
return str start
const char * str
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1117
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition heaptuple.c:1346
#define HASH_STRINGS
Definition hsearch.h:96
@ HASH_FIND
Definition hsearch.h:113
@ HASH_ENTER
Definition hsearch.h:114
#define HASH_CONTEXT
Definition hsearch.h:102
#define HASH_ELEM
Definition hsearch.h:95
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static int32 HeapTupleHeaderGetTypMod(const HeapTupleHeaderData *tup)
static uint32 HeapTupleHeaderGetDatumLength(const HeapTupleHeaderData *tup)
static void * GETSTRUCT(const HeapTupleData *tuple)
static Oid HeapTupleHeaderGetTypeId(const HeapTupleHeaderData *tup)
#define funcname
#define token
#define false
struct parser_state ps
long val
Definition informix.c:689
static uint32 pg_abs_s32(int32 a)
Definition int.h:221
int i
Definition isn.c:77
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition itemptr.h:184
void escape_json_text(StringInfo buf, const text *txt)
Definition json.c:1738
void escape_json_with_len(StringInfo buf, const char *str, int len)
Definition json.c:1633
void escape_json(StringInfo buf, const char *str)
Definition json.c:1604
JsonParseErrorType pg_parse_json(JsonLexContext *lex, const JsonSemAction *sem)
Definition jsonapi.c:744
JsonLexContext * makeJsonLexContextCstringLen(JsonLexContext *lex, const char *json, size_t len, int encoding, bool need_escapes)
Definition jsonapi.c:392
JsonParseErrorType json_lex(JsonLexContext *lex)
Definition jsonapi.c:1588
char * json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
Definition jsonapi.c:2404
JsonParseErrorType json_count_array_elements(JsonLexContext *lex, int *elements)
Definition jsonapi.c:803
void freeJsonLexContext(JsonLexContext *lex)
Definition jsonapi.c:687
JsonParseErrorType
Definition jsonapi.h:35
@ JSON_SEM_ACTION_FAILED
Definition jsonapi.h:59
@ JSON_UNICODE_CODE_POINT_ZERO
Definition jsonapi.h:53
@ JSON_SUCCESS
Definition jsonapi.h:36
@ JSON_UNICODE_UNTRANSLATABLE
Definition jsonapi.h:56
@ JSON_UNICODE_HIGH_ESCAPE
Definition jsonapi.h:55
JsonTokenType
Definition jsonapi.h:18
@ JSON_TOKEN_INVALID
Definition jsonapi.h:19
@ JSON_TOKEN_FALSE
Definition jsonapi.h:29
@ JSON_TOKEN_END
Definition jsonapi.h:31
@ JSON_TOKEN_TRUE
Definition jsonapi.h:28
@ JSON_TOKEN_NULL
Definition jsonapi.h:30
@ JSON_TOKEN_OBJECT_START
Definition jsonapi.h:22
@ JSON_TOKEN_NUMBER
Definition jsonapi.h:21
@ JSON_TOKEN_STRING
Definition jsonapi.h:20
@ JSON_TOKEN_ARRAY_START
Definition jsonapi.h:24
char * JsonbUnquote(Jsonb *jb)
Definition jsonb.c:2042
Datum jsonb_in(PG_FUNCTION_ARGS)
Definition jsonb.c:65
char * JsonbToCString(StringInfo out, JsonbContainer *in, int estimated_len)
Definition jsonb.c:466
char * JsonbToCStringIndent(StringInfo out, JsonbContainer *in, int estimated_len)
Definition jsonb.c:475
jbvType
Definition jsonb.h:228
@ jbvObject
Definition jsonb.h:236
@ jbvNumeric
Definition jsonb.h:232
@ jbvBool
Definition jsonb.h:233
@ jbvArray
Definition jsonb.h:235
@ jbvBinary
Definition jsonb.h:238
@ jbvNull
Definition jsonb.h:230
@ jbvString
Definition jsonb.h:231
#define JsonContainerIsScalar(jc)
Definition jsonb.h:209
#define JsonContainerIsArray(jc)
Definition jsonb.h:211
#define JsonContainerSize(jc)
Definition jsonb.h:208
#define JB_ROOT_IS_OBJECT(jbp_)
Definition jsonb.h:223
static Datum JsonbPGetDatum(const Jsonb *p)
Definition jsonb.h:413
#define IsAJsonbScalar(jsonbval)
Definition jsonb.h:299
#define PG_RETURN_JSONB_P(x)
Definition jsonb.h:420
#define JB_ROOT_IS_ARRAY(jbp_)
Definition jsonb.h:224
#define PG_GETARG_JSONB_P(x)
Definition jsonb.h:418
#define JsonContainerIsObject(jc)
Definition jsonb.h:210
static Jsonb * DatumGetJsonbP(Datum d)
Definition jsonb.h:401
#define JB_ROOT_IS_SCALAR(jbp_)
Definition jsonb.h:222
JsonbIteratorToken
Definition jsonb.h:21
@ WJB_KEY
Definition jsonb.h:23
@ WJB_DONE
Definition jsonb.h:22
@ WJB_END_ARRAY
Definition jsonb.h:27
@ WJB_VALUE
Definition jsonb.h:24
@ WJB_END_OBJECT
Definition jsonb.h:29
@ WJB_ELEM
Definition jsonb.h:25
@ WJB_BEGIN_OBJECT
Definition jsonb.h:28
@ WJB_BEGIN_ARRAY
Definition jsonb.h:26
#define JB_ROOT_COUNT(jbp_)
Definition jsonb.h:221
void pushJsonbValue(JsonbInState *pstate, JsonbIteratorToken seq, JsonbValue *jbval)
Definition jsonb_util.c:583
JsonbValue * getKeyJsonValueFromContainer(JsonbContainer *container, const char *keyVal, int keyLen, JsonbValue *res)
Definition jsonb_util.c:402
JsonbIterator * JsonbIteratorInit(JsonbContainer *container)
Definition jsonb_util.c:935
void JsonbToJsonbValue(Jsonb *jsonb, JsonbValue *val)
Definition jsonb_util.c:76
JsonbIteratorToken JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested)
Definition jsonb_util.c:973
JsonbValue * getIthJsonbValueFromContainer(JsonbContainer *container, uint32 i)
Definition jsonb_util.c:472
Jsonb * JsonbValueToJsonb(JsonbValue *val)
Definition jsonb_util.c:96
Datum jsonb_populate_recordset(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:3971
JsonLexContext * makeJsonLexContext(JsonLexContext *lex, text *json, bool need_escapes)
Definition jsonfuncs.c:540
static JsonParseErrorType get_array_element_end(void *state, bool isnull)
Definition jsonfuncs.c:1401
static Datum elements_worker(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
Definition jsonfuncs.c:2305
static JsonParseErrorType hash_array_start(void *state)
Definition jsonfuncs.c:3927
Datum jsonb_object_keys(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:568
static JsonParseErrorType populate_recordset_array_start(void *state)
Definition jsonfuncs.c:4280
static JsonParseErrorType transform_string_values_array_start(void *state)
Definition jsonfuncs.c:5871
static JsonParseErrorType get_object_field_start(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:1197
static JsonParseErrorType elements_object_start(void *state)
Definition jsonfuncs.c:2415
static JsonParseErrorType transform_string_values_object_field_start(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:5891
Datum jsonb_array_elements(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:2205
static JsonParseErrorType iterate_values_object_field_start(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:5748
static void IteratorConcat(JsonbIterator **it1, JsonbIterator **it2, JsonbInState *state)
Definition jsonfuncs.c:5048
Datum json_each_text(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:1959
static void push_path(JsonbInState *st, int level, const Datum *path_elems, const bool *path_nulls, int path_len, JsonbValue *newval)
Definition jsonfuncs.c:1720
Datum json_populate_recordset(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:3985
static JsonParseErrorType populate_array_scalar(void *_state, char *token, JsonTokenType tokentype)
Definition jsonfuncs.c:2750
text * transform_json_string_values(text *json, void *action_state, JsonTransformStringValuesAction transform_action)
Definition jsonfuncs.c:5815
Datum jsonb_delete(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:4658
Datum json_populate_type(Datum json_val, Oid json_type, Oid typid, int32 typmod, void **cache, MemoryContext mcxt, bool *isnull, bool omit_quotes, Node *escontext)
Definition jsonfuncs.c:3342
Datum jsonb_delete_array(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:4708
Datum jsonb_pretty(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:4603
static void setPathArray(JsonbIterator **it, const Datum *path_elems, const bool *path_nulls, int path_len, JsonbInState *st, int level, JsonbValue *newval, uint32 nelems, int op_type)
Definition jsonfuncs.c:5389
static JsonParseErrorType transform_string_values_array_end(void *state)
Definition jsonfuncs.c:5881
static JsonParseErrorType populate_recordset_object_start(void *state)
Definition jsonfuncs.c:4212
static RecordIOData * allocate_record_info(MemoryContext mcxt, int ncolumns)
Definition jsonfuncs.c:3473
static JsonParseErrorType iterate_values_scalar(void *state, char *token, JsonTokenType tokentype)
Definition jsonfuncs.c:5720
static text * JsonbValueAsText(JsonbValue *v)
Definition jsonfuncs.c:1802
Datum jsonb_insert(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:5002
static JsonParseErrorType get_object_start(void *state)
Definition jsonfuncs.c:1160
static JsonParseErrorType populate_recordset_object_field_start(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:4304
static JsonParseErrorType populate_recordset_object_field_end(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:4327
static JsonParseErrorType populate_array_object_start(void *_state)
Definition jsonfuncs.c:2642
#define JsObjectIsEmpty(jso)
Definition jsonfuncs.c:329
static void get_record_type_from_argument(FunctionCallInfo fcinfo, const char *funcname, PopulateRecordCache *cache)
Definition jsonfuncs.c:3633
Datum json_array_element(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:922
Datum jsonb_delete_idx(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:4792
#define JB_PATH_DELETE
Definition jsonfuncs.c:45
static JsonParseErrorType sn_object_end(void *state)
Definition jsonfuncs.c:4397
#define JB_PATH_CREATE_OR_INSERT
Definition jsonfuncs.c:49
Datum jsonb_populate_record_valid(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:2474
Datum json_array_elements_text(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:2299
#define JB_PATH_CREATE
Definition jsonfuncs.c:44
static JsonParseErrorType hash_scalar(void *state, char *token, JsonTokenType tokentype)
Definition jsonfuncs.c:3940
static JsonParseErrorType sn_array_element_start(void *state, bool isnull)
Definition jsonfuncs.c:4457
static Datum populate_record_worker(FunctionCallInfo fcinfo, const char *funcname, bool is_json, bool have_record_arg, Node *escontext)
Definition jsonfuncs.c:3696
static HTAB * get_json_object_as_hash(const char *json, int len, const char *funcname, Node *escontext)
Definition jsonfuncs.c:3808
static bool populate_array_json(PopulateArrayContext *ctx, const char *json, int len)
Definition jsonfuncs.c:2786
#define JsValueIsString(jsv)
Definition jsonfuncs.c:325
static JsonParseErrorType populate_recordset_object_end(void *state)
Definition jsonfuncs.c:4242
static Datum populate_record_field(ColumnIOData *col, Oid typid, int32 typmod, const char *colname, MemoryContext mcxt, Datum defaultval, JsValue *jsv, bool *isnull, Node *escontext, bool omit_scalar_quotes)
Definition jsonfuncs.c:3403
Datum jsonb_delete_path(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:4962
static JsonParseErrorType each_object_field_end(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:2117
Datum jsonb_object_field_text(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:900
static Datum each_worker(FunctionCallInfo fcinfo, bool as_text)
Definition jsonfuncs.c:2055
static JsonParseErrorType get_array_start(void *state)
Definition jsonfuncs.c:1295
static JsonParseErrorType each_scalar(void *state, char *token, JsonTokenType tokentype)
Definition jsonfuncs.c:2179
static int report_json_context(JsonLexContext *lex)
Definition jsonfuncs.c:677
Datum json_strip_nulls(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:4502
Datum json_array_elements(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:2293
Datum jsonb_concat(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:4620
static JsonParseErrorType okeys_array_start(void *state)
Definition jsonfuncs.c:809
Datum json_object_field_text(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:884
uint32 parse_jsonb_index_flags(Jsonb *jb)
Definition jsonfuncs.c:5559
Datum jsonb_extract_path_text(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:1494
Datum json_each(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:1947
static JsonParseErrorType alen_scalar(void *state, char *token, JsonTokenType tokentype)
Definition jsonfuncs.c:1911
Datum jsonb_set_element(Jsonb *jb, const Datum *path, int path_len, JsonbValue *newval)
Definition jsonfuncs.c:1679
static JsonParseErrorType sn_object_start(void *state)
Definition jsonfuncs.c:4387
static JsonParseErrorType sn_array_start(void *state)
Definition jsonfuncs.c:4407
static bool populate_array_check_dimension(PopulateArrayContext *ctx, int ndim)
Definition jsonfuncs.c:2587
static Datum each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
Definition jsonfuncs.c:1971
static JsonParseErrorType sn_array_end(void *state)
Definition jsonfuncs.c:4417
static void setPathObject(JsonbIterator **it, const Datum *path_elems, const bool *path_nulls, int path_len, JsonbInState *st, int level, JsonbValue *newval, uint32 npairs, int op_type)
Definition jsonfuncs.c:5251
Datum json_to_recordset(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:3992
static JsonParseErrorType get_scalar(void *state, char *token, JsonTokenType tokentype)
Definition jsonfuncs.c:1445
#define JB_PATH_CONSISTENT_POSITION
Definition jsonfuncs.c:52
static bool populate_array_assign_ndims(PopulateArrayContext *ctx, int ndims)
Definition jsonfuncs.c:2557
JsonTokenType json_get_first_token(text *json, bool throw_error)
Definition jsonfuncs.c:5937
Datum jsonb_set(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:4853
#define JsValueIsNull(jsv)
Definition jsonfuncs.c:320
static void update_cached_tupdesc(CompositeIOData *io, MemoryContext mcxt)
Definition jsonfuncs.c:3026
struct ColumnIOData ColumnIOData
Definition jsonfuncs.c:162
void iterate_jsonb_values(Jsonb *jb, uint32 flags, void *state, JsonIterateStringValuesAction action)
Definition jsonfuncs.c:5627
static JsonParseErrorType populate_array_element_end(void *_state, bool isnull)
Definition jsonfuncs.c:2707
Datum jsonb_set_lax(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:4899
static JsonParseErrorType elements_array_element_end(void *state, bool isnull)
Definition jsonfuncs.c:2369
static JsonParseErrorType sn_object_field_start(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:4427
Datum jsonb_each_text(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:1965
static JsonParseErrorType elements_scalar(void *state, char *token, JsonTokenType tokentype)
Definition jsonfuncs.c:2430
static JsonParseErrorType each_object_field_start(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:2095
Datum jsonb_strip_nulls(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:4539
Datum jsonb_extract_path(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:1488
void json_categorize_type(Oid typoid, bool is_jsonb, JsonTypeCategory *tcategory, Oid *outfuncoid)
Definition jsonfuncs.c:5964
static Datum populate_array(ArrayIOData *aio, const char *colname, MemoryContext mcxt, JsValue *jsv, bool *isnull, Node *escontext)
Definition jsonfuncs.c:2912
static JsonParseErrorType okeys_object_field_start(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:786
Datum jsonb_get_element(Jsonb *jb, const Datum *path, int npath, bool *isnull, bool as_text)
Definition jsonfuncs.c:1531
Datum json_array_length(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:1849
void json_errsave_error(JsonParseErrorType error, JsonLexContext *lex, Node *escontext)
Definition jsonfuncs.c:641
Datum jsonb_array_length(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:1875
Datum jsonb_object_field(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:862
static Datum elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
Definition jsonfuncs.c:2217
void iterate_json_values(text *json, uint32 flags, void *action_state, JsonIterateStringValuesAction action)
Definition jsonfuncs.c:5695
Datum jsonb_populate_record(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:2461
Datum json_extract_path(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:1009
static void push_null_elements(JsonbInState *ps, int num)
Definition jsonfuncs.c:1701
Datum json_extract_path_text(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:1015
static JsonParseErrorType elements_array_element_start(void *state, bool isnull)
Definition jsonfuncs.c:2347
static void get_record_type_from_query(FunctionCallInfo fcinfo, const char *funcname, PopulateRecordCache *cache)
Definition jsonfuncs.c:3659
Datum json_populate_record(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:2492
static JsonParseErrorType populate_recordset_array_element_start(void *state, bool isnull)
Definition jsonfuncs.c:4265
#define JB_PATH_FILL_GAPS
Definition jsonfuncs.c:51
Jsonb * transform_jsonb_string_values(Jsonb *jsonb, void *action_state, JsonTransformStringValuesAction transform_action)
Definition jsonfuncs.c:5769
static JsonParseErrorType transform_string_values_object_end(void *state)
Definition jsonfuncs.c:5861
static bool JsValueToJsObject(JsValue *jsv, JsObject *jso, Node *escontext)
Definition jsonfuncs.c:2979
Datum json_object_field(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:846
static JsonParseErrorType okeys_scalar(void *state, char *token, JsonTokenType tokentype)
Definition jsonfuncs.c:824
static Datum get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
Definition jsonfuncs.c:1500
static void populate_array_report_expected_array(PopulateArrayContext *ctx, int ndim)
Definition jsonfuncs.c:2507
static JsonParseErrorType get_object_end(void *state)
Definition jsonfuncs.c:1179
static Datum populate_composite(CompositeIOData *io, Oid typid, const char *colname, MemoryContext mcxt, HeapTupleHeader defaultval, JsValue *jsv, bool *isnull, Node *escontext)
Definition jsonfuncs.c:3055
Datum jsonb_to_record(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:2485
Datum jsonb_array_element(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:937
Datum json_object_keys(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:732
#define JB_PATH_INSERT_BEFORE
Definition jsonfuncs.c:47
static JsonParseErrorType populate_recordset_scalar(void *state, char *token, JsonTokenType tokentype)
Definition jsonfuncs.c:4287
static JsonParseErrorType get_object_field_end(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:1244
bool pg_parse_json_or_errsave(JsonLexContext *lex, const JsonSemAction *sem, Node *escontext)
Definition jsonfuncs.c:519
static Datum get_path_all(FunctionCallInfo fcinfo, bool as_text)
Definition jsonfuncs.c:1024
static Datum populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname, bool is_json, bool have_record_arg)
Definition jsonfuncs.c:4038
static HeapTupleHeader populate_record(TupleDesc tupdesc, RecordIOData **record_p, HeapTupleHeader defaultval, MemoryContext mcxt, JsObject *obj, Node *escontext)
Definition jsonfuncs.c:3517
static void setPath(JsonbIterator **it, const Datum *path_elems, const bool *path_nulls, int path_len, JsonbInState *st, int level, JsonbValue *newval, int op_type)
Definition jsonfuncs.c:5173
static JsonParseErrorType alen_object_start(void *state)
Definition jsonfuncs.c:1897
static bool JsObjectGetField(JsObject *obj, char *field, JsValue *jsv)
Definition jsonfuncs.c:3489
static bool populate_array_element(PopulateArrayContext *ctx, int ndim, JsValue *jsv)
Definition jsonfuncs.c:2615
static JsonParseErrorType populate_array_element_start(void *_state, bool isnull)
Definition jsonfuncs.c:2689
static JsonParseErrorType populate_array_array_end(void *_state)
Definition jsonfuncs.c:2665
static void prepare_column_cache(ColumnIOData *column, Oid typid, int32 typmod, MemoryContext mcxt, bool need_scalar)
Definition jsonfuncs.c:3248
static JsonParseErrorType get_array_end(void *state)
Definition jsonfuncs.c:1335
Datum jsonb_to_recordset(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:3978
static JsonParseErrorType sn_scalar(void *state, char *token, JsonTokenType tokentype)
Definition jsonfuncs.c:4479
#define JB_PATH_INSERT_AFTER
Definition jsonfuncs.c:48
Datum jsonb_each(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:1953
static JsonParseErrorType get_array_element_start(void *state, bool isnull)
Definition jsonfuncs.c:1353
static JsonParseErrorType hash_object_field_end(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:3876
#define JB_PATH_REPLACE
Definition jsonfuncs.c:46
static void populate_recordset_record(PopulateRecordsetState *state, JsObject *obj)
Definition jsonfuncs.c:3999
#define JsObjectFree(jso)
Definition jsonfuncs.c:335
static JsonParseErrorType transform_string_values_object_start(void *state)
Definition jsonfuncs.c:5851
static JsonParseErrorType transform_string_values_array_element_start(void *state, bool isnull)
Definition jsonfuncs.c:5909
static JsonParseErrorType alen_array_element_start(void *state, bool isnull)
Definition jsonfuncs.c:1925
static Datum populate_scalar(ScalarIOData *io, Oid typid, int32 typmod, JsValue *jsv, bool *isnull, Node *escontext, bool omit_quotes)
Definition jsonfuncs.c:3122
static bool populate_array_dim_jsonb(PopulateArrayContext *ctx, JsonbValue *jbv, int ndim)
Definition jsonfuncs.c:2822
Datum jsonb_array_element_text(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:980
TypeCat
Definition jsonfuncs.c:200
@ TYPECAT_COMPOSITE
Definition jsonfuncs.c:203
@ TYPECAT_SCALAR
Definition jsonfuncs.c:201
@ TYPECAT_COMPOSITE_DOMAIN
Definition jsonfuncs.c:204
@ TYPECAT_DOMAIN
Definition jsonfuncs.c:205
@ TYPECAT_ARRAY
Definition jsonfuncs.c:202
Datum json_to_record(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:2499
static JsonParseErrorType each_array_start(void *state)
Definition jsonfuncs.c:2165
Datum json_array_element_text(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:965
static Datum populate_domain(DomainIOData *io, Oid typid, const char *colname, MemoryContext mcxt, JsValue *jsv, bool *isnull, Node *escontext, bool omit_quotes)
Definition jsonfuncs.c:3214
static JsonParseErrorType transform_string_values_scalar(void *state, char *token, JsonTokenType tokentype)
Definition jsonfuncs.c:5920
static JsonParseErrorType hash_object_field_start(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:3850
Datum jsonb_array_elements_text(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:2211
static text * get_worker(text *json, char **tpath, int *ipath, int npath, bool normalize_results)
Definition jsonfuncs.c:1103
#define pg_parse_json_or_ereport(lex, sem)
Definition jsonfuncs.h:47
@ jtiKey
Definition jsonfuncs.h:27
@ jtiAll
Definition jsonfuncs.h:31
@ jtiNumeric
Definition jsonfuncs.h:29
@ jtiBool
Definition jsonfuncs.h:30
@ jtiString
Definition jsonfuncs.h:28
text *(* JsonTransformStringValuesAction)(void *state, char *elem_value, int elem_len)
Definition jsonfuncs.h:38
void(* JsonIterateStringValuesAction)(void *state, char *elem_value, int elem_len)
Definition jsonfuncs.h:35
JsonTypeCategory
Definition jsonfuncs.h:69
@ JSONTYPE_JSON
Definition jsonfuncs.h:76
@ JSONTYPE_TIMESTAMP
Definition jsonfuncs.h:74
@ JSONTYPE_NUMERIC
Definition jsonfuncs.h:72
@ JSONTYPE_DATE
Definition jsonfuncs.h:73
@ JSONTYPE_BOOL
Definition jsonfuncs.h:71
@ JSONTYPE_OTHER
Definition jsonfuncs.h:81
@ JSONTYPE_CAST
Definition jsonfuncs.h:80
@ JSONTYPE_COMPOSITE
Definition jsonfuncs.h:79
@ JSONTYPE_ARRAY
Definition jsonfuncs.h:78
@ JSONTYPE_TIMESTAMPTZ
Definition jsonfuncs.h:75
@ JSONTYPE_JSONB
Definition jsonfuncs.h:77
Oid get_element_type(Oid typid)
Definition lsyscache.c:2909
bool type_is_rowtype(Oid typid)
Definition lsyscache.c:2805
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition lsyscache.c:3057
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition lsyscache.c:3024
char get_typtype(Oid typid)
Definition lsyscache.c:2779
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition lsyscache.c:2688
Oid getBaseType(Oid typid)
Definition lsyscache.c:2671
int GetDatabaseEncoding(void)
Definition mbutils.c:1264
int pg_mblen(const char *mbstr)
Definition mbutils.c:1026
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition mcxt.c:1232
void MemoryContextReset(MemoryContext context)
Definition mcxt.c:403
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition mcxt.c:1266
char * pstrdup(const char *in)
Definition mcxt.c:1781
void * repalloc(void *pointer, Size size)
Definition mcxt.c:1632
void pfree(void *pointer)
Definition mcxt.c:1616
void * palloc(Size size)
Definition mcxt.c:1387
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
char * pnstrdup(const char *in, Size len)
Definition mcxt.c:1792
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
#define SOFT_ERROR_OCCURRED(escontext)
Definition miscnodes.h:53
#define IsA(nodeptr, _type_)
Definition nodes.h:164
static Datum NumericGetDatum(Numeric X)
Definition numeric.h:76
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
CoercionPathType find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, CoercionContext ccontext, Oid *funcid)
CoercionPathType
@ COERCION_PATH_FUNC
FormData_pg_attribute * Form_pg_attribute
#define NAMEDATALEN
const void size_t len
const void * data
static char buf[DEFAULT_XLOG_SEG_SIZE]
FormData_pg_type * Form_pg_type
Definition pg_type.h:261
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
static Datum PointerGetDatum(const void *X)
Definition postgres.h:352
static Datum BoolGetDatum(bool X)
Definition postgres.h:112
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:262
static char * DatumGetCString(Datum X)
Definition postgres.h:365
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:342
static Datum CStringGetDatum(const char *X)
Definition postgres.h:380
#define InvalidOid
unsigned int Oid
char * c
static int fb(int x)
@ COERCION_EXPLICIT
Definition primnodes.h:749
tree ctl
Definition radixtree.h:1838
static chr element(struct vars *v, const chr *startp, const chr *endp)
static void error(void)
void check_stack_depth(void)
Definition stack_depth.c:95
int strtoint(const char *pg_restrict str, char **pg_restrict endptr, int base)
Definition string.c:50
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition stringinfo.c:145
void appendStringInfoString(StringInfo str, const char *s)
Definition stringinfo.c:230
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
#define appendStringInfoCharMacro(str, ch)
Definition stringinfo.h:231
JsonLexContext * lex
Definition jsonfuncs.c:104
int32 element_typmod
Definition jsonfuncs.c:170
ColumnIOData * element_info
Definition jsonfuncs.c:168
Oid element_type
Definition jsonfuncs.c:169
CompositeIOData composite
Definition jsonfuncs.c:221
TypeCat typcat
Definition jsonfuncs.c:215
union ColumnIOData::@26 io
ScalarIOData scalar_io
Definition jsonfuncs.c:216
ArrayIOData array
Definition jsonfuncs.c:220
DomainIOData domain
Definition jsonfuncs.c:222
RecordIOData * record_io
Definition jsonfuncs.c:180
void * domain_info
Definition jsonfuncs.c:186
TupleDesc tupdesc
Definition jsonfuncs.c:181
void * domain_info
Definition jsonfuncs.c:195
int32 base_typmod
Definition jsonfuncs.c:194
ColumnIOData * base_io
Definition jsonfuncs.c:192
bool normalize_results
Definition jsonfuncs.c:116
TupleDesc ret_tdesc
Definition jsonfuncs.c:113
char * normalized_scalar
Definition jsonfuncs.c:118
JsonLexContext * lex
Definition jsonfuncs.c:111
const char * result_start
Definition jsonfuncs.c:115
Tuplestorestate * tuple_store
Definition jsonfuncs.c:112
MemoryContext tmp_cxt
Definition jsonfuncs.c:114
bool next_scalar
Definition jsonfuncs.c:117
TupleDesc ret_tdesc
Definition jsonfuncs.c:127
Tuplestorestate * tuple_store
Definition jsonfuncs.c:126
bool normalize_results
Definition jsonfuncs.c:130
MemoryContext tmp_cxt
Definition jsonfuncs.c:128
JsonLexContext * lex
Definition jsonfuncs.c:124
const char * function_name
Definition jsonfuncs.c:125
const char * result_start
Definition jsonfuncs.c:129
char * normalized_scalar
Definition jsonfuncs.c:132
MemoryContext ecxt_per_query_memory
Definition execnodes.h:282
void * fn_extra
Definition fmgr.h:64
MemoryContext fn_mcxt
Definition fmgr.h:65
FmgrInfo * flinfo
Definition fmgr.h:87
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition fmgr.h:95
bool next_scalar
Definition jsonfuncs.c:92
int * path_indexes
Definition jsonfuncs.c:95
char ** path_names
Definition jsonfuncs.c:94
bool * pathok
Definition jsonfuncs.c:96
const char * result_start
Definition jsonfuncs.c:90
int * array_cur_index
Definition jsonfuncs.c:97
text * tresult
Definition jsonfuncs.c:89
JsonLexContext * lex
Definition jsonfuncs.c:88
bool normalize_results
Definition jsonfuncs.c:91
int npath
Definition jsonfuncs.c:93
ItemPointerData t_self
Definition htup.h:65
uint32 t_len
Definition htup.h:64
HeapTupleHeader t_data
Definition htup.h:68
Oid t_tableOid
Definition htup.h:66
JsonIterateStringValuesAction action
Definition jsonfuncs.c:68
char * saved_scalar
Definition jsonfuncs.c:141
const char * save_json_start
Definition jsonfuncs.c:142
const char * function_name
Definition jsonfuncs.c:139
JsonTokenType saved_token_type
Definition jsonfuncs.c:143
JsonLexContext * lex
Definition jsonfuncs.c:138
HTAB * hash
Definition jsonfuncs.c:140
bool is_json
Definition jsonfuncs.c:311
JsonbContainer * jsonb_cont
Definition jsonfuncs.c:315
HTAB * json_hash
Definition jsonfuncs.c:314
union JsObject::@29 val
const char * str
Definition jsonfuncs.c:300
union JsValue::@27 val
JsonbValue * jsonb
Definition jsonfuncs.c:305
int len
Definition jsonfuncs.c:301
JsonTokenType type
Definition jsonfuncs.c:302
struct JsValue::@27::@28 json
bool is_json
Definition jsonfuncs.c:295
char fname[NAMEDATALEN]
Definition jsonfuncs.c:149
JsonTokenType type
Definition jsonfuncs.c:151
const char * input
Definition jsonapi.h:102
size_t input_length
Definition jsonapi.h:103
const char * line_start
Definition jsonapi.h:113
JsonTokenType token_type
Definition jsonapi.h:109
const char * token_terminator
Definition jsonapi.h:106
json_struct_action array_end
Definition jsonapi.h:157
json_struct_action object_start
Definition jsonapi.h:154
json_ofield_action object_field_start
Definition jsonapi.h:158
json_aelem_action array_element_start
Definition jsonapi.h:160
json_scalar_action scalar
Definition jsonapi.h:162
void * semstate
Definition jsonapi.h:153
json_aelem_action array_element_end
Definition jsonapi.h:161
json_struct_action array_start
Definition jsonapi.h:156
json_struct_action object_end
Definition jsonapi.h:155
json_ofield_action object_field_end
Definition jsonapi.h:159
JsonbValue * result
Definition jsonb.h:333
enum jbvType type
Definition jsonb.h:257
char * val
Definition jsonb.h:266
Definition jsonb.h:215
JsonbContainer root
Definition jsonb.h:217
Definition nodes.h:135
Datum value
Definition postgres.h:87
ArrayBuildState * astate
Definition jsonfuncs.c:261
MemoryContext mcxt
Definition jsonfuncs.c:264
ArrayIOData * aio
Definition jsonfuncs.c:262
MemoryContext acxt
Definition jsonfuncs.c:263
const char * colname
Definition jsonfuncs.c:265
JsonTokenType element_type
Definition jsonfuncs.c:280
JsonLexContext * lex
Definition jsonfuncs.c:275
PopulateArrayContext * ctx
Definition jsonfuncs.c:276
const char * element_start
Definition jsonfuncs.c:277
ColumnIOData c
Definition jsonfuncs.c:240
MemoryContext fn_mcxt
Definition jsonfuncs.c:241
JsonLexContext * lex
Definition jsonfuncs.c:247
HeapTupleHeader rec
Definition jsonfuncs.c:254
const char * save_json_start
Definition jsonfuncs.c:251
const char * function_name
Definition jsonfuncs.c:248
Tuplestorestate * tuple_store
Definition jsonfuncs.c:253
PopulateRecordCache * cache
Definition jsonfuncs.c:255
JsonTokenType saved_token_type
Definition jsonfuncs.c:252
ColumnIOData columns[FLEXIBLE_ARRAY_MEMBER]
Definition hstore_io.c:829
int32 record_typmod
Definition hstore_io.c:825
SetFunctionReturnMode returnMode
Definition execnodes.h:362
ExprContext * econtext
Definition execnodes.h:358
TupleDesc setDesc
Definition execnodes.h:366
Tuplestorestate * setResult
Definition execnodes.h:365
FmgrInfo typiofunc
Definition jsonfuncs.c:158
bool skip_next_null
Definition jsonfuncs.c:288
bool strip_in_arrays
Definition jsonfuncs.c:289
JsonLexContext * lex
Definition jsonfuncs.c:286
StringInfo strval
Definition jsonfuncs.c:287
JsonTransformStringValuesAction action
Definition jsonfuncs.c:80
int32 tdtypmod
Definition tupdesc.h:139
Definition type.h:96
Definition c.h:706
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition syscache.c:220
static JsonSemAction sem
#define FirstNormalObjectId
Definition transam.h:197
void FreeTupleDesc(TupleDesc tupdesc)
Definition tupdesc.c:502
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition tupdesc.c:252
#define ReleaseTupleDesc(tupdesc)
Definition tupdesc.h:219
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:160
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition tuplestore.c:330
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition tuplestore.c:784
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
Definition tuplestore.c:764
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition typcache.c:1921
static Size VARSIZE_ANY_EXHDR(const void *PTR)
Definition varatt.h:472
static Size VARSIZE(const void *PTR)
Definition varatt.h:298
static char * VARDATA_ANY(const void *PTR)
Definition varatt.h:486
text * cstring_to_text_with_len(const char *s, int len)
Definition varlena.c:193
text * cstring_to_text(const char *s)
Definition varlena.c:181
char * text_to_cstring(const text *t)
Definition varlena.c:214
const char * type

◆ JB_PATH_DELETE

#define JB_PATH_DELETE   0x0002

Definition at line 45 of file jsonfuncs.c.

◆ JB_PATH_FILL_GAPS

#define JB_PATH_FILL_GAPS   0x0020

Definition at line 51 of file jsonfuncs.c.

◆ JB_PATH_INSERT_AFTER

#define JB_PATH_INSERT_AFTER   0x0010

Definition at line 48 of file jsonfuncs.c.

◆ JB_PATH_INSERT_BEFORE

#define JB_PATH_INSERT_BEFORE   0x0008

Definition at line 47 of file jsonfuncs.c.

◆ JB_PATH_REPLACE

#define JB_PATH_REPLACE   0x0004

Definition at line 46 of file jsonfuncs.c.

◆ JsObjectFree

#define JsObjectFree (   jso)
Value:
do { \
if ((jso)->is_json) \
hash_destroy((jso)->val.json_hash); \
} while (0)

Definition at line 335 of file jsonfuncs.c.

336 { \
337 if ((jso)->is_json) \
338 hash_destroy((jso)->val.json_hash); \
339 } while (0)

◆ JsObjectIsEmpty

#define JsObjectIsEmpty (   jso)
Value:
((jso)->is_json \
? hash_get_num_entries((jso)->val.json_hash) == 0 \
: ((jso)->val.jsonb_cont == NULL || \
JsonContainerSize((jso)->val.jsonb_cont) == 0))
int64 hash_get_num_entries(HTAB *hashp)
Definition dynahash.c:1336

Definition at line 329 of file jsonfuncs.c.

332 : ((jso)->val.jsonb_cont == NULL || \
333 JsonContainerSize((jso)->val.jsonb_cont) == 0))

◆ JsValueIsNull

#define JsValueIsNull (   jsv)
Value:
((jsv)->is_json ? \
(!(jsv)->val.json.str || (jsv)->val.json.type == JSON_TOKEN_NULL) : \
(!(jsv)->val.jsonb || (jsv)->val.jsonb->type == jbvNull))

Definition at line 320 of file jsonfuncs.c.

322 : \
323 (!(jsv)->val.jsonb || (jsv)->val.jsonb->type == jbvNull))

◆ JsValueIsString

#define JsValueIsString (   jsv)
Value:
((jsv)->is_json ? (jsv)->val.json.type == JSON_TOKEN_STRING \
: ((jsv)->val.jsonb && (jsv)->val.jsonb->type == jbvString))

Definition at line 325 of file jsonfuncs.c.

327 : ((jsv)->val.jsonb && (jsv)->val.jsonb->type == jbvString))

Typedef Documentation

◆ AlenState

◆ ArrayIOData

◆ ColumnIOData

Definition at line 162 of file jsonfuncs.c.

◆ CompositeIOData

◆ DomainIOData

◆ EachState

◆ ElementsState

◆ GetState

◆ IterateJsonStringValuesState

◆ JHashState

◆ JsObject

◆ JsonHashEntry

◆ JsValue

◆ OkeysState

◆ PopulateArrayContext

◆ PopulateArrayState

◆ PopulateRecordCache

◆ PopulateRecordsetState

◆ RecordIOData

Definition at line 163 of file jsonfuncs.c.

◆ ScalarIOData

◆ StripnullState

◆ TransformJsonStringValuesState

◆ TypeCat

Enumeration Type Documentation

◆ TypeCat

Enumerator
TYPECAT_SCALAR 
TYPECAT_ARRAY 
TYPECAT_COMPOSITE 
TYPECAT_COMPOSITE_DOMAIN 
TYPECAT_DOMAIN 

Definition at line 199 of file jsonfuncs.c.

200{
201 TYPECAT_SCALAR = 's',
202 TYPECAT_ARRAY = 'a',
203 TYPECAT_COMPOSITE = 'c',
205 TYPECAT_DOMAIN = 'd',
206} TypeCat;

Function Documentation

◆ alen_array_element_start()

static JsonParseErrorType alen_array_element_start ( void state,
bool  isnull 
)
static

Definition at line 1925 of file jsonfuncs.c.

1926{
1928
1929 /* just count up all the level 1 elements */
1930 if (_state->lex->lex_level == 1)
1931 _state->count++;
1932
1933 return JSON_SUCCESS;
1934}

References fb(), and JSON_SUCCESS.

Referenced by json_array_length().

◆ alen_object_start()

static JsonParseErrorType alen_object_start ( void state)
static

Definition at line 1897 of file jsonfuncs.c.

1898{
1900
1901 /* json structure check */
1902 if (_state->lex->lex_level == 0)
1903 ereport(ERROR,
1905 errmsg("cannot get array length of a non-array")));
1906
1907 return JSON_SUCCESS;
1908}

References ereport, errcode(), errmsg(), ERROR, fb(), and JSON_SUCCESS.

Referenced by json_array_length().

◆ alen_scalar()

static JsonParseErrorType alen_scalar ( void state,
char token,
JsonTokenType  tokentype 
)
static

Definition at line 1911 of file jsonfuncs.c.

1912{
1914
1915 /* json structure check */
1916 if (_state->lex->lex_level == 0)
1917 ereport(ERROR,
1919 errmsg("cannot get array length of a scalar")));
1920
1921 return JSON_SUCCESS;
1922}

References ereport, errcode(), errmsg(), ERROR, fb(), and JSON_SUCCESS.

Referenced by json_array_length().

◆ allocate_record_info()

static RecordIOData * allocate_record_info ( MemoryContext  mcxt,
int  ncolumns 
)
static

Definition at line 3473 of file jsonfuncs.c.

3474{
3476 MemoryContextAlloc(mcxt,
3477 offsetof(RecordIOData, columns) +
3478 ncolumns * sizeof(ColumnIOData));
3479
3481 data->record_typmod = 0;
3482 data->ncolumns = ncolumns;
3483 MemSet(data->columns, 0, sizeof(ColumnIOData) * ncolumns);
3484
3485 return data;
3486}

References data, fb(), InvalidOid, MemoryContextAlloc(), MemSet, and RecordIOData::record_type.

Referenced by populate_record().

◆ each_array_start()

static JsonParseErrorType each_array_start ( void state)
static

Definition at line 2165 of file jsonfuncs.c.

2166{
2168
2169 /* json structure check */
2170 if (_state->lex->lex_level == 0)
2171 ereport(ERROR,
2173 errmsg("cannot deconstruct an array as an object")));
2174
2175 return JSON_SUCCESS;
2176}

References ereport, errcode(), errmsg(), ERROR, fb(), and JSON_SUCCESS.

Referenced by each_worker().

◆ each_object_field_end()

static JsonParseErrorType each_object_field_end ( void state,
char fname,
bool  isnull 
)
static

Definition at line 2117 of file jsonfuncs.c.

2118{
2121 int len;
2122 text *val;
2123 HeapTuple tuple;
2124 Datum values[2];
2125 bool nulls[2] = {false, false};
2126
2127 /* skip over nested objects */
2128 if (_state->lex->lex_level != 1)
2129 return JSON_SUCCESS;
2130
2131 /* use the tmp context so we can clean up after each tuple is done */
2133
2134 values[0] = CStringGetTextDatum(fname);
2135
2136 if (isnull && _state->normalize_results)
2137 {
2138 nulls[1] = true;
2139 values[1] = (Datum) 0;
2140 }
2141 else if (_state->next_scalar)
2142 {
2143 values[1] = CStringGetTextDatum(_state->normalized_scalar);
2144 _state->next_scalar = false;
2145 }
2146 else
2147 {
2148 len = _state->lex->prev_token_terminator - _state->result_start;
2149 val = cstring_to_text_with_len(_state->result_start, len);
2151 }
2152
2153 tuple = heap_form_tuple(_state->ret_tdesc, values, nulls);
2154
2155 tuplestore_puttuple(_state->tuple_store, tuple);
2156
2157 /* clean up and switch back */
2159 MemoryContextReset(_state->tmp_cxt);
2160
2161 return JSON_SUCCESS;
2162}

References cstring_to_text_with_len(), CStringGetTextDatum, fb(), heap_form_tuple(), JSON_SUCCESS, len, MemoryContextReset(), MemoryContextSwitchTo(), PointerGetDatum(), tuplestore_puttuple(), val, and values.

Referenced by each_worker().

◆ each_object_field_start()

static JsonParseErrorType each_object_field_start ( void state,
char fname,
bool  isnull 
)
static

Definition at line 2095 of file jsonfuncs.c.

2096{
2098
2099 /* save a pointer to where the value starts */
2100 if (_state->lex->lex_level == 1)
2101 {
2102 /*
2103 * next_scalar will be reset in the object_field_end handler, and
2104 * since we know the value is a scalar there is no danger of it being
2105 * on while recursing down the tree.
2106 */
2107 if (_state->normalize_results && _state->lex->token_type == JSON_TOKEN_STRING)
2108 _state->next_scalar = true;
2109 else
2110 _state->result_start = _state->lex->token_start;
2111 }
2112
2113 return JSON_SUCCESS;
2114}

References fb(), JSON_SUCCESS, and JSON_TOKEN_STRING.

Referenced by each_worker().

◆ each_scalar()

static JsonParseErrorType each_scalar ( void state,
char token,
JsonTokenType  tokentype 
)
static

Definition at line 2179 of file jsonfuncs.c.

2180{
2182
2183 /* json structure check */
2184 if (_state->lex->lex_level == 0)
2185 ereport(ERROR,
2187 errmsg("cannot deconstruct a scalar")));
2188
2189 /* supply de-escaped value if required */
2190 if (_state->next_scalar)
2191 _state->normalized_scalar = token;
2192
2193 return JSON_SUCCESS;
2194}

References ereport, errcode(), errmsg(), ERROR, fb(), JSON_SUCCESS, and token.

Referenced by each_worker().

◆ each_worker()

static Datum each_worker ( FunctionCallInfo  fcinfo,
bool  as_text 
)
static

Definition at line 2055 of file jsonfuncs.c.

2056{
2057 text *json = PG_GETARG_TEXT_PP(0);
2058 JsonLexContext lex;
2060 ReturnSetInfo *rsi;
2062
2065
2066 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2067
2069 state->tuple_store = rsi->setResult;
2070 state->ret_tdesc = rsi->setDesc;
2071
2072 sem->semstate = state;
2077
2078 state->normalize_results = as_text;
2079 state->next_scalar = false;
2080 state->lex = makeJsonLexContext(&lex, json, true);
2082 "json_each temporary cxt",
2084
2086
2087 MemoryContextDelete(state->tmp_cxt);
2088 freeJsonLexContext(&lex);
2089
2091}

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, JsonSemAction::array_start, CurrentMemoryContext, each_array_start(), each_object_field_end(), each_object_field_start(), each_scalar(), fb(), freeJsonLexContext(), InitMaterializedSRF(), makeJsonLexContext(), MAT_SRF_BLESS, MemoryContextDelete(), JsonSemAction::object_field_end, JsonSemAction::object_field_start, palloc0_object, PG_GETARG_TEXT_PP, pg_parse_json_or_ereport, PG_RETURN_NULL, FunctionCallInfoBaseData::resultinfo, JsonSemAction::scalar, sem, JsonSemAction::semstate, ReturnSetInfo::setDesc, and ReturnSetInfo::setResult.

Referenced by json_each(), and json_each_text().

◆ each_worker_jsonb()

static Datum each_worker_jsonb ( FunctionCallInfo  fcinfo,
const char funcname,
bool  as_text 
)
static

Definition at line 1971 of file jsonfuncs.c.

1972{
1974 ReturnSetInfo *rsi;
1976 tmp_cxt;
1977 bool skipNested = false;
1979 JsonbValue v;
1981
1982 if (!JB_ROOT_IS_OBJECT(jb))
1983 ereport(ERROR,
1985 errmsg("cannot call %s on a non-object",
1986 funcname)));
1987
1988 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
1990
1992 "jsonb_each temporary cxt",
1994
1995 it = JsonbIteratorInit(&jb->root);
1996
1997 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
1998 {
1999 skipNested = true;
2000
2001 if (r == WJB_KEY)
2002 {
2003 text *key;
2004 Datum values[2];
2005 bool nulls[2] = {false, false};
2006
2007 /* Use the tmp context so we can clean up after each tuple is done */
2008 old_cxt = MemoryContextSwitchTo(tmp_cxt);
2009
2010 key = cstring_to_text_with_len(v.val.string.val, v.val.string.len);
2011
2012 /*
2013 * The next thing the iterator fetches should be the value, no
2014 * matter what shape it is.
2015 */
2016 r = JsonbIteratorNext(&it, &v, skipNested);
2017 Assert(r != WJB_DONE);
2018
2019 values[0] = PointerGetDatum(key);
2020
2021 if (as_text)
2022 {
2023 if (v.type == jbvNull)
2024 {
2025 /* a json null is an sql null in text mode */
2026 nulls[1] = true;
2027 values[1] = (Datum) 0;
2028 }
2029 else
2031 }
2032 else
2033 {
2034 /* Not in text mode, just return the Jsonb */
2036
2038 }
2039
2040 tuplestore_putvalues(rsi->setResult, rsi->setDesc, values, nulls);
2041
2042 /* clean up and switch back */
2044 MemoryContextReset(tmp_cxt);
2045 }
2046 }
2047
2048 MemoryContextDelete(tmp_cxt);
2049
2051}

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, cstring_to_text_with_len(), CurrentMemoryContext, ereport, errcode(), errmsg(), ERROR, fb(), funcname, InitMaterializedSRF(), JB_ROOT_IS_OBJECT, jbvNull, JsonbIteratorInit(), JsonbIteratorNext(), JsonbValueAsText(), JsonbValueToJsonb(), MAT_SRF_BLESS, MemoryContextDelete(), MemoryContextReset(), MemoryContextSwitchTo(), PG_GETARG_JSONB_P, PG_RETURN_NULL, PointerGetDatum(), FunctionCallInfoBaseData::resultinfo, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, tuplestore_putvalues(), JsonbValue::type, JsonbValue::val, val, values, WJB_DONE, and WJB_KEY.

Referenced by jsonb_each(), and jsonb_each_text().

◆ elements_array_element_end()

static JsonParseErrorType elements_array_element_end ( void state,
bool  isnull 
)
static

Definition at line 2369 of file jsonfuncs.c.

2370{
2373 int len;
2374 text *val;
2375 HeapTuple tuple;
2376 Datum values[1];
2377 bool nulls[1] = {false};
2378
2379 /* skip over nested objects */
2380 if (_state->lex->lex_level != 1)
2381 return JSON_SUCCESS;
2382
2383 /* use the tmp context so we can clean up after each tuple is done */
2385
2386 if (isnull && _state->normalize_results)
2387 {
2388 nulls[0] = true;
2389 values[0] = (Datum) 0;
2390 }
2391 else if (_state->next_scalar)
2392 {
2393 values[0] = CStringGetTextDatum(_state->normalized_scalar);
2394 _state->next_scalar = false;
2395 }
2396 else
2397 {
2398 len = _state->lex->prev_token_terminator - _state->result_start;
2399 val = cstring_to_text_with_len(_state->result_start, len);
2401 }
2402
2403 tuple = heap_form_tuple(_state->ret_tdesc, values, nulls);
2404
2405 tuplestore_puttuple(_state->tuple_store, tuple);
2406
2407 /* clean up and switch back */
2409 MemoryContextReset(_state->tmp_cxt);
2410
2411 return JSON_SUCCESS;
2412}

References cstring_to_text_with_len(), CStringGetTextDatum, fb(), heap_form_tuple(), JSON_SUCCESS, len, MemoryContextReset(), MemoryContextSwitchTo(), PointerGetDatum(), tuplestore_puttuple(), val, and values.

Referenced by elements_worker().

◆ elements_array_element_start()

static JsonParseErrorType elements_array_element_start ( void state,
bool  isnull 
)
static

Definition at line 2347 of file jsonfuncs.c.

2348{
2350
2351 /* save a pointer to where the value starts */
2352 if (_state->lex->lex_level == 1)
2353 {
2354 /*
2355 * next_scalar will be reset in the array_element_end handler, and
2356 * since we know the value is a scalar there is no danger of it being
2357 * on while recursing down the tree.
2358 */
2359 if (_state->normalize_results && _state->lex->token_type == JSON_TOKEN_STRING)
2360 _state->next_scalar = true;
2361 else
2362 _state->result_start = _state->lex->token_start;
2363 }
2364
2365 return JSON_SUCCESS;
2366}

References fb(), JSON_SUCCESS, and JSON_TOKEN_STRING.

Referenced by elements_worker().

◆ elements_object_start()

static JsonParseErrorType elements_object_start ( void state)
static

Definition at line 2415 of file jsonfuncs.c.

2416{
2418
2419 /* json structure check */
2420 if (_state->lex->lex_level == 0)
2421 ereport(ERROR,
2423 errmsg("cannot call %s on a non-array",
2424 _state->function_name)));
2425
2426 return JSON_SUCCESS;
2427}

References ereport, errcode(), errmsg(), ERROR, fb(), and JSON_SUCCESS.

Referenced by elements_worker().

◆ elements_scalar()

static JsonParseErrorType elements_scalar ( void state,
char token,
JsonTokenType  tokentype 
)
static

Definition at line 2430 of file jsonfuncs.c.

2431{
2433
2434 /* json structure check */
2435 if (_state->lex->lex_level == 0)
2436 ereport(ERROR,
2438 errmsg("cannot call %s on a scalar",
2439 _state->function_name)));
2440
2441 /* supply de-escaped value if required */
2442 if (_state->next_scalar)
2443 _state->normalized_scalar = token;
2444
2445 return JSON_SUCCESS;
2446}

References ereport, errcode(), errmsg(), ERROR, fb(), JSON_SUCCESS, and token.

Referenced by elements_worker().

◆ elements_worker()

static Datum elements_worker ( FunctionCallInfo  fcinfo,
const char funcname,
bool  as_text 
)
static

Definition at line 2305 of file jsonfuncs.c.

2306{
2307 text *json = PG_GETARG_TEXT_PP(0);
2308 JsonLexContext lex;
2310 ReturnSetInfo *rsi;
2312
2313 /* elements only needs escaped strings when as_text */
2314 makeJsonLexContext(&lex, json, as_text);
2315
2318
2320 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2321 state->tuple_store = rsi->setResult;
2322 state->ret_tdesc = rsi->setDesc;
2323
2324 sem->semstate = state;
2329
2330 state->function_name = funcname;
2331 state->normalize_results = as_text;
2332 state->next_scalar = false;
2333 state->lex = &lex;
2335 "json_array_elements temporary cxt",
2337
2339
2340 MemoryContextDelete(state->tmp_cxt);
2341 freeJsonLexContext(&lex);
2342
2344}

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, JsonSemAction::array_element_end, JsonSemAction::array_element_start, CurrentMemoryContext, elements_array_element_end(), elements_array_element_start(), elements_object_start(), elements_scalar(), fb(), freeJsonLexContext(), funcname, InitMaterializedSRF(), makeJsonLexContext(), MAT_SRF_BLESS, MAT_SRF_USE_EXPECTED_DESC, MemoryContextDelete(), JsonSemAction::object_start, palloc0_object, PG_GETARG_TEXT_PP, pg_parse_json_or_ereport, PG_RETURN_NULL, FunctionCallInfoBaseData::resultinfo, JsonSemAction::scalar, sem, JsonSemAction::semstate, ReturnSetInfo::setDesc, and ReturnSetInfo::setResult.

Referenced by json_array_elements(), and json_array_elements_text().

◆ elements_worker_jsonb()

static Datum elements_worker_jsonb ( FunctionCallInfo  fcinfo,
const char funcname,
bool  as_text 
)
static

Definition at line 2217 of file jsonfuncs.c.

2219{
2221 ReturnSetInfo *rsi;
2223 tmp_cxt;
2224 bool skipNested = false;
2226 JsonbValue v;
2228
2229 if (JB_ROOT_IS_SCALAR(jb))
2230 ereport(ERROR,
2232 errmsg("cannot extract elements from a scalar")));
2233 else if (!JB_ROOT_IS_ARRAY(jb))
2234 ereport(ERROR,
2236 errmsg("cannot extract elements from an object")));
2237
2238 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2239
2241
2243 "jsonb_array_elements temporary cxt",
2245
2246 it = JsonbIteratorInit(&jb->root);
2247
2248 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
2249 {
2250 skipNested = true;
2251
2252 if (r == WJB_ELEM)
2253 {
2254 Datum values[1];
2255 bool nulls[1] = {false};
2256
2257 /* use the tmp context so we can clean up after each tuple is done */
2258 old_cxt = MemoryContextSwitchTo(tmp_cxt);
2259
2260 if (as_text)
2261 {
2262 if (v.type == jbvNull)
2263 {
2264 /* a json null is an sql null in text mode */
2265 nulls[0] = true;
2266 values[0] = (Datum) 0;
2267 }
2268 else
2270 }
2271 else
2272 {
2273 /* Not in text mode, just return the Jsonb */
2275
2277 }
2278
2279 tuplestore_putvalues(rsi->setResult, rsi->setDesc, values, nulls);
2280
2281 /* clean up and switch back */
2283 MemoryContextReset(tmp_cxt);
2284 }
2285 }
2286
2287 MemoryContextDelete(tmp_cxt);
2288
2290}

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, CurrentMemoryContext, ereport, errcode(), errmsg(), ERROR, fb(), InitMaterializedSRF(), JB_ROOT_IS_ARRAY, JB_ROOT_IS_SCALAR, jbvNull, JsonbIteratorInit(), JsonbIteratorNext(), JsonbValueAsText(), JsonbValueToJsonb(), MAT_SRF_BLESS, MAT_SRF_USE_EXPECTED_DESC, MemoryContextDelete(), MemoryContextReset(), MemoryContextSwitchTo(), PG_GETARG_JSONB_P, PG_RETURN_NULL, PointerGetDatum(), FunctionCallInfoBaseData::resultinfo, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, tuplestore_putvalues(), JsonbValue::type, val, values, WJB_DONE, and WJB_ELEM.

Referenced by jsonb_array_elements(), and jsonb_array_elements_text().

◆ get_array_element_end()

static JsonParseErrorType get_array_element_end ( void state,
bool  isnull 
)
static

Definition at line 1401 of file jsonfuncs.c.

1402{
1404 bool get_last = false;
1405 int lex_level = _state->lex->lex_level;
1406
1407 /* same tests as in get_array_element_start */
1408 if (lex_level <= _state->npath &&
1409 _state->pathok[lex_level - 1] &&
1410 _state->path_indexes != NULL &&
1411 _state->array_cur_index[lex_level - 1] == _state->path_indexes[lex_level - 1])
1412 {
1413 if (lex_level < _state->npath)
1414 {
1415 /* done with this element so reset pathok */
1416 _state->pathok[lex_level] = false;
1417 }
1418 else
1419 {
1420 /* end of path, so we want this value */
1421 get_last = true;
1422 }
1423 }
1424
1425 /* same logic as for objects */
1426 if (get_last && _state->result_start != NULL)
1427 {
1428 if (isnull && _state->normalize_results)
1429 _state->tresult = (text *) NULL;
1430 else
1431 {
1432 const char *start = _state->result_start;
1433 int len = _state->lex->prev_token_terminator - start;
1434
1436 }
1437
1438 _state->result_start = NULL;
1439 }
1440
1441 return JSON_SUCCESS;
1442}

References cstring_to_text_with_len(), fb(), JSON_SUCCESS, len, and start.

Referenced by get_worker().

◆ get_array_element_start()

static JsonParseErrorType get_array_element_start ( void state,
bool  isnull 
)
static

Definition at line 1353 of file jsonfuncs.c.

1354{
1356 bool get_next = false;
1357 int lex_level = _state->lex->lex_level;
1358
1359 /* Update array element counter */
1360 if (lex_level <= _state->npath)
1361 _state->array_cur_index[lex_level - 1]++;
1362
1363 if (lex_level <= _state->npath &&
1364 _state->pathok[lex_level - 1] &&
1365 _state->path_indexes != NULL &&
1366 _state->array_cur_index[lex_level - 1] == _state->path_indexes[lex_level - 1])
1367 {
1368 if (lex_level < _state->npath)
1369 {
1370 /* if not at end of path just mark path ok */
1371 _state->pathok[lex_level] = true;
1372 }
1373 else
1374 {
1375 /* end of path, so we want this value */
1376 get_next = true;
1377 }
1378 }
1379
1380 /* same logic as for objects */
1381 if (get_next)
1382 {
1383 _state->tresult = NULL;
1384 _state->result_start = NULL;
1385
1386 if (_state->normalize_results &&
1387 _state->lex->token_type == JSON_TOKEN_STRING)
1388 {
1389 _state->next_scalar = true;
1390 }
1391 else
1392 {
1393 _state->result_start = _state->lex->token_start;
1394 }
1395 }
1396
1397 return JSON_SUCCESS;
1398}

References fb(), JSON_SUCCESS, and JSON_TOKEN_STRING.

Referenced by get_worker().

◆ get_array_end()

static JsonParseErrorType get_array_end ( void state)
static

Definition at line 1335 of file jsonfuncs.c.

1336{
1338 int lex_level = _state->lex->lex_level;
1339
1340 if (lex_level == 0 && _state->npath == 0)
1341 {
1342 /* Special case: return the entire array */
1343 const char *start = _state->result_start;
1344 int len = _state->lex->prev_token_terminator - start;
1345
1347 }
1348
1349 return JSON_SUCCESS;
1350}

References cstring_to_text_with_len(), fb(), JSON_SUCCESS, len, and start.

Referenced by get_worker().

◆ get_array_start()

static JsonParseErrorType get_array_start ( void state)
static

Definition at line 1295 of file jsonfuncs.c.

1296{
1298 int lex_level = _state->lex->lex_level;
1299
1300 if (lex_level < _state->npath)
1301 {
1302 /* Initialize counting of elements in this array */
1303 _state->array_cur_index[lex_level] = -1;
1304
1305 /* INT_MIN value is reserved to represent invalid subscript */
1306 if (_state->path_indexes[lex_level] < 0 &&
1307 _state->path_indexes[lex_level] != INT_MIN)
1308 {
1309 /* Negative subscript -- convert to positive-wise subscript */
1311 int nelements;
1312
1313 error = json_count_array_elements(_state->lex, &nelements);
1314 if (error != JSON_SUCCESS)
1316
1317 if (-_state->path_indexes[lex_level] <= nelements)
1318 _state->path_indexes[lex_level] += nelements;
1319 }
1320 }
1321 else if (lex_level == 0 && _state->npath == 0)
1322 {
1323 /*
1324 * Special case: we should match the entire array. We only need this
1325 * at the outermost level because at nested levels the match will have
1326 * been started by the outer field or array element callback.
1327 */
1328 _state->result_start = _state->lex->token_start;
1329 }
1330
1331 return JSON_SUCCESS;
1332}

References error(), fb(), json_count_array_elements(), json_errsave_error(), and JSON_SUCCESS.

Referenced by get_worker().

◆ get_json_object_as_hash()

static HTAB * get_json_object_as_hash ( const char json,
int  len,
const char funcname,
Node escontext 
)
static

Definition at line 3808 of file jsonfuncs.c.

3810{
3811 HASHCTL ctl;
3812 HTAB *tab;
3815
3816 ctl.keysize = NAMEDATALEN;
3817 ctl.entrysize = sizeof(JsonHashEntry);
3819 tab = hash_create("json object hashtable",
3820 100,
3821 &ctl,
3823
3826
3827 state->function_name = funcname;
3828 state->hash = tab;
3830 GetDatabaseEncoding(), true);
3831
3832 sem->semstate = state;
3837
3838 if (!pg_parse_json_or_errsave(state->lex, sem, escontext))
3839 {
3840 hash_destroy(state->hash);
3841 tab = NULL;
3842 }
3843
3845
3846 return tab;
3847}

References JsonSemAction::array_start, ctl, CurrentMemoryContext, fb(), freeJsonLexContext(), funcname, GetDatabaseEncoding(), hash_array_start(), HASH_CONTEXT, hash_create(), hash_destroy(), HASH_ELEM, hash_object_field_end(), hash_object_field_start(), hash_scalar(), HASH_STRINGS, len, makeJsonLexContextCstringLen(), NAMEDATALEN, JsonSemAction::object_field_end, JsonSemAction::object_field_start, palloc0_object, pg_parse_json_or_errsave(), JsonSemAction::scalar, sem, and JsonSemAction::semstate.

Referenced by JsValueToJsObject().

◆ get_jsonb_path_all()

static Datum get_jsonb_path_all ( FunctionCallInfo  fcinfo,
bool  as_text 
)
static

Definition at line 1500 of file jsonfuncs.c.

1501{
1504 Datum *pathtext;
1505 bool *pathnulls;
1506 bool isnull;
1507 int npath;
1508 Datum res;
1509
1510 /*
1511 * If the array contains any null elements, return NULL, on the grounds
1512 * that you'd have gotten NULL if any RHS value were NULL in a nested
1513 * series of applications of the -> operator. (Note: because we also
1514 * return NULL for error cases such as no-such-field, this is true
1515 * regardless of the contents of the rest of the array.)
1516 */
1517 if (array_contains_nulls(path))
1519
1521
1522 res = jsonb_get_element(jb, pathtext, npath, &isnull, as_text);
1523
1524 if (isnull)
1526 else
1527 PG_RETURN_DATUM(res);
1528}

References array_contains_nulls(), deconstruct_array_builtin(), fb(), jsonb_get_element(), PG_GETARG_ARRAYTYPE_P, PG_GETARG_JSONB_P, PG_RETURN_DATUM, and PG_RETURN_NULL.

Referenced by jsonb_extract_path(), and jsonb_extract_path_text().

◆ get_object_end()

static JsonParseErrorType get_object_end ( void state)
static

Definition at line 1179 of file jsonfuncs.c.

1180{
1182 int lex_level = _state->lex->lex_level;
1183
1184 if (lex_level == 0 && _state->npath == 0)
1185 {
1186 /* Special case: return the entire object */
1187 const char *start = _state->result_start;
1188 int len = _state->lex->prev_token_terminator - start;
1189
1191 }
1192
1193 return JSON_SUCCESS;
1194}

References cstring_to_text_with_len(), fb(), JSON_SUCCESS, len, and start.

Referenced by get_worker().

◆ get_object_field_end()

static JsonParseErrorType get_object_field_end ( void state,
char fname,
bool  isnull 
)
static

Definition at line 1244 of file jsonfuncs.c.

1245{
1247 bool get_last = false;
1248 int lex_level = _state->lex->lex_level;
1249
1250 /* same tests as in get_object_field_start */
1251 if (lex_level <= _state->npath &&
1252 _state->pathok[lex_level - 1] &&
1253 _state->path_names != NULL &&
1254 _state->path_names[lex_level - 1] != NULL &&
1255 strcmp(fname, _state->path_names[lex_level - 1]) == 0)
1256 {
1257 if (lex_level < _state->npath)
1258 {
1259 /* done with this field so reset pathok */
1260 _state->pathok[lex_level] = false;
1261 }
1262 else
1263 {
1264 /* end of path, so we want this value */
1265 get_last = true;
1266 }
1267 }
1268
1269 /* for as_text scalar case, our work is already done */
1270 if (get_last && _state->result_start != NULL)
1271 {
1272 /*
1273 * make a text object from the string from the previously noted json
1274 * start up to the end of the previous token (the lexer is by now
1275 * ahead of us on whatever came after what we're interested in).
1276 */
1277 if (isnull && _state->normalize_results)
1278 _state->tresult = (text *) NULL;
1279 else
1280 {
1281 const char *start = _state->result_start;
1282 int len = _state->lex->prev_token_terminator - start;
1283
1285 }
1286
1287 /* this should be unnecessary but let's do it for cleanliness: */
1288 _state->result_start = NULL;
1289 }
1290
1291 return JSON_SUCCESS;
1292}

References cstring_to_text_with_len(), fb(), JSON_SUCCESS, len, and start.

Referenced by get_worker().

◆ get_object_field_start()

static JsonParseErrorType get_object_field_start ( void state,
char fname,
bool  isnull 
)
static

Definition at line 1197 of file jsonfuncs.c.

1198{
1200 bool get_next = false;
1201 int lex_level = _state->lex->lex_level;
1202
1203 if (lex_level <= _state->npath &&
1204 _state->pathok[lex_level - 1] &&
1205 _state->path_names != NULL &&
1206 _state->path_names[lex_level - 1] != NULL &&
1207 strcmp(fname, _state->path_names[lex_level - 1]) == 0)
1208 {
1209 if (lex_level < _state->npath)
1210 {
1211 /* if not at end of path just mark path ok */
1212 _state->pathok[lex_level] = true;
1213 }
1214 else
1215 {
1216 /* end of path, so we want this value */
1217 get_next = true;
1218 }
1219 }
1220
1221 if (get_next)
1222 {
1223 /* this object overrides any previous matching object */
1224 _state->tresult = NULL;
1225 _state->result_start = NULL;
1226
1227 if (_state->normalize_results &&
1228 _state->lex->token_type == JSON_TOKEN_STRING)
1229 {
1230 /* for as_text variants, tell get_scalar to set it for us */
1231 _state->next_scalar = true;
1232 }
1233 else
1234 {
1235 /* for non-as_text variants, just note the json starting point */
1236 _state->result_start = _state->lex->token_start;
1237 }
1238 }
1239
1240 return JSON_SUCCESS;
1241}

References fb(), JSON_SUCCESS, and JSON_TOKEN_STRING.

Referenced by get_worker().

◆ get_object_start()

static JsonParseErrorType get_object_start ( void state)
static

Definition at line 1160 of file jsonfuncs.c.

1161{
1163 int lex_level = _state->lex->lex_level;
1164
1165 if (lex_level == 0 && _state->npath == 0)
1166 {
1167 /*
1168 * Special case: we should match the entire object. We only need this
1169 * at outermost level because at nested levels the match will have
1170 * been started by the outer field or array element callback.
1171 */
1172 _state->result_start = _state->lex->token_start;
1173 }
1174
1175 return JSON_SUCCESS;
1176}

References fb(), and JSON_SUCCESS.

Referenced by get_worker().

◆ get_path_all()

static Datum get_path_all ( FunctionCallInfo  fcinfo,
bool  as_text 
)
static

Definition at line 1024 of file jsonfuncs.c.

1025{
1026 text *json = PG_GETARG_TEXT_PP(0);
1028 text *result;
1029 Datum *pathtext;
1030 bool *pathnulls;
1031 int npath;
1032 char **tpath;
1033 int *ipath;
1034 int i;
1035
1036 /*
1037 * If the array contains any null elements, return NULL, on the grounds
1038 * that you'd have gotten NULL if any RHS value were NULL in a nested
1039 * series of applications of the -> operator. (Note: because we also
1040 * return NULL for error cases such as no-such-field, this is true
1041 * regardless of the contents of the rest of the array.)
1042 */
1043 if (array_contains_nulls(path))
1045
1047
1048 tpath = palloc_array(char *, npath);
1049 ipath = palloc_array(int, npath);
1050
1051 for (i = 0; i < npath; i++)
1052 {
1053 Assert(!pathnulls[i]);
1055
1056 /*
1057 * we have no idea at this stage what structure the document is so
1058 * just convert anything in the path that we can to an integer and set
1059 * all the other integers to INT_MIN which will never match.
1060 */
1061 if (*tpath[i] != '\0')
1062 {
1063 int ind;
1064 char *endptr;
1065
1066 errno = 0;
1067 ind = strtoint(tpath[i], &endptr, 10);
1068 if (endptr == tpath[i] || *endptr != '\0' || errno != 0)
1069 ipath[i] = INT_MIN;
1070 else
1071 ipath[i] = ind;
1072 }
1073 else
1074 ipath[i] = INT_MIN;
1075 }
1076
1077 result = get_worker(json, tpath, ipath, npath, as_text);
1078
1079 if (result != NULL)
1080 PG_RETURN_TEXT_P(result);
1081 else
1083}

References array_contains_nulls(), Assert, deconstruct_array_builtin(), fb(), get_worker(), i, palloc_array, PG_GETARG_ARRAYTYPE_P, PG_GETARG_TEXT_PP, PG_RETURN_NULL, PG_RETURN_TEXT_P, strtoint(), and TextDatumGetCString.

Referenced by json_extract_path(), and json_extract_path_text().

◆ get_record_type_from_argument()

static void get_record_type_from_argument ( FunctionCallInfo  fcinfo,
const char funcname,
PopulateRecordCache cache 
)
static

Definition at line 3633 of file jsonfuncs.c.

3636{
3637 cache->argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
3638 prepare_column_cache(&cache->c,
3639 cache->argtype, -1,
3640 cache->fn_mcxt, false);
3641 if (cache->c.typcat != TYPECAT_COMPOSITE &&
3643 ereport(ERROR,
3645 /* translator: %s is a function name, eg json_to_record */
3646 errmsg("first argument of %s must be a row type",
3647 funcname)));
3648}

References PopulateRecordCache::argtype, PopulateRecordCache::c, ereport, errcode(), errmsg(), ERROR, fb(), FunctionCallInfoBaseData::flinfo, PopulateRecordCache::fn_mcxt, funcname, get_fn_expr_argtype(), prepare_column_cache(), ColumnIOData::typcat, TYPECAT_COMPOSITE, and TYPECAT_COMPOSITE_DOMAIN.

Referenced by populate_record_worker(), and populate_recordset_worker().

◆ get_record_type_from_query()

static void get_record_type_from_query ( FunctionCallInfo  fcinfo,
const char funcname,
PopulateRecordCache cache 
)
static

Definition at line 3659 of file jsonfuncs.c.

3662{
3663 TupleDesc tupdesc;
3665
3666 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
3667 ereport(ERROR,
3669 /* translator: %s is a function name, eg json_to_record */
3670 errmsg("could not determine row type for result of %s",
3671 funcname),
3672 errhint("Provide a non-null record argument, "
3673 "or call the function in the FROM clause "
3674 "using a column definition list.")));
3675
3676 Assert(tupdesc);
3677 cache->argtype = tupdesc->tdtypeid;
3678
3679 /* If we go through this more than once, avoid memory leak */
3680 if (cache->c.io.composite.tupdesc)
3682
3683 /* Save identified tupdesc */
3685 cache->c.io.composite.tupdesc = CreateTupleDescCopy(tupdesc);
3686 cache->c.io.composite.base_typid = tupdesc->tdtypeid;
3687 cache->c.io.composite.base_typmod = tupdesc->tdtypmod;
3689}

References PopulateRecordCache::argtype, Assert, CompositeIOData::base_typid, CompositeIOData::base_typmod, PopulateRecordCache::c, ColumnIOData::composite, CreateTupleDescCopy(), ereport, errcode(), errhint(), errmsg(), ERROR, fb(), PopulateRecordCache::fn_mcxt, FreeTupleDesc(), funcname, get_call_result_type(), ColumnIOData::io, MemoryContextSwitchTo(), TupleDescData::tdtypeid, TupleDescData::tdtypmod, CompositeIOData::tupdesc, and TYPEFUNC_COMPOSITE.

Referenced by populate_record_worker(), and populate_recordset_worker().

◆ get_scalar()

static JsonParseErrorType get_scalar ( void state,
char token,
JsonTokenType  tokentype 
)
static

Definition at line 1445 of file jsonfuncs.c.

1446{
1448 int lex_level = _state->lex->lex_level;
1449
1450 /* Check for whole-object match */
1451 if (lex_level == 0 && _state->npath == 0)
1452 {
1453 if (_state->normalize_results && tokentype == JSON_TOKEN_STRING)
1454 {
1455 /* we want the de-escaped string */
1456 _state->next_scalar = true;
1457 }
1458 else if (_state->normalize_results && tokentype == JSON_TOKEN_NULL)
1459 {
1460 _state->tresult = (text *) NULL;
1461 }
1462 else
1463 {
1464 /*
1465 * This is a bit hokey: we will suppress whitespace after the
1466 * scalar token, but not whitespace before it. Probably not worth
1467 * doing our own space-skipping to avoid that.
1468 */
1469 const char *start = _state->lex->input;
1470 int len = _state->lex->prev_token_terminator - start;
1471
1473 }
1474 }
1475
1476 if (_state->next_scalar)
1477 {
1478 /* a de-escaped text value is wanted, so supply it */
1479 _state->tresult = cstring_to_text(token);
1480 /* make sure the next call to get_scalar doesn't overwrite it */
1481 _state->next_scalar = false;
1482 }
1483
1484 return JSON_SUCCESS;
1485}

References cstring_to_text(), cstring_to_text_with_len(), fb(), JSON_SUCCESS, JSON_TOKEN_NULL, JSON_TOKEN_STRING, len, and start.

Referenced by get_worker().

◆ get_worker()

static text * get_worker ( text json,
char **  tpath,
int ipath,
int  npath,
bool  normalize_results 
)
static

Definition at line 1103 of file jsonfuncs.c.

1108{
1111
1112 Assert(npath >= 0);
1113
1114 state->lex = makeJsonLexContext(NULL, json, true);
1115
1116 /* is it "_as_text" variant? */
1117 state->normalize_results = normalize_results;
1118 state->npath = npath;
1119 state->path_names = tpath;
1120 state->path_indexes = ipath;
1121 state->pathok = palloc0_array(bool, npath);
1122 state->array_cur_index = palloc_array(int, npath);
1123
1124 if (npath > 0)
1125 state->pathok[0] = true;
1126
1127 sem->semstate = state;
1128
1129 /*
1130 * Not all variants need all the semantic routines. Only set the ones that
1131 * are actually needed for maximum efficiency.
1132 */
1134 if (npath == 0)
1135 {
1140 }
1141 if (tpath != NULL)
1142 {
1145 }
1146 if (ipath != NULL)
1147 {
1151 }
1152
1155
1156 return state->tresult;
1157}

References JsonSemAction::array_element_end, JsonSemAction::array_element_start, JsonSemAction::array_end, JsonSemAction::array_start, Assert, fb(), freeJsonLexContext(), get_array_element_end(), get_array_element_start(), get_array_end(), get_array_start(), get_object_end(), get_object_field_end(), get_object_field_start(), get_object_start(), get_scalar(), makeJsonLexContext(), JsonSemAction::object_end, JsonSemAction::object_field_end, JsonSemAction::object_field_start, JsonSemAction::object_start, palloc0_array, palloc0_object, palloc_array, pg_parse_json_or_ereport, JsonSemAction::scalar, sem, and JsonSemAction::semstate.

Referenced by get_path_all(), json_array_element(), json_array_element_text(), json_object_field(), and json_object_field_text().

◆ hash_array_start()

static JsonParseErrorType hash_array_start ( void state)
static

Definition at line 3927 of file jsonfuncs.c.

3928{
3930
3931 if (_state->lex->lex_level == 0)
3932 ereport(ERROR,
3934 errmsg("cannot call %s on an array", _state->function_name)));
3935
3936 return JSON_SUCCESS;
3937}

References ereport, errcode(), errmsg(), ERROR, fb(), and JSON_SUCCESS.

Referenced by get_json_object_as_hash().

◆ hash_object_field_end()

static JsonParseErrorType hash_object_field_end ( void state,
char fname,
bool  isnull 
)
static

Definition at line 3876 of file jsonfuncs.c.

3877{
3880 bool found;
3881
3882 /*
3883 * Ignore nested fields.
3884 */
3885 if (_state->lex->lex_level > 1)
3886 return JSON_SUCCESS;
3887
3888 /*
3889 * Ignore field names >= NAMEDATALEN - they can't match a record field.
3890 * (Note: without this test, the hash code would truncate the string at
3891 * NAMEDATALEN-1, and could then match against a similarly-truncated
3892 * record field name. That would be a reasonable behavior, but this code
3893 * has previously insisted on exact equality, so we keep this behavior.)
3894 */
3895 if (strlen(fname) >= NAMEDATALEN)
3896 return JSON_SUCCESS;
3897
3898 hashentry = hash_search(_state->hash, fname, HASH_ENTER, &found);
3899
3900 /*
3901 * found being true indicates a duplicate. We don't do anything about
3902 * that, a later field with the same name overrides the earlier field.
3903 */
3904
3905 hashentry->type = _state->saved_token_type;
3906 Assert(isnull == (hashentry->type == JSON_TOKEN_NULL));
3907
3908 if (_state->save_json_start != NULL)
3909 {
3910 int len = _state->lex->prev_token_terminator - _state->save_json_start;
3911 char *val = palloc((len + 1) * sizeof(char));
3912
3913 memcpy(val, _state->save_json_start, len);
3914 val[len] = '\0';
3915 hashentry->val = val;
3916 }
3917 else
3918 {
3919 /* must have had a scalar instead */
3920 hashentry->val = _state->saved_scalar;
3921 }
3922
3923 return JSON_SUCCESS;
3924}

References Assert, fb(), HASH_ENTER, hash_search(), JSON_SUCCESS, JSON_TOKEN_NULL, len, NAMEDATALEN, palloc(), and val.

Referenced by get_json_object_as_hash().

◆ hash_object_field_start()

static JsonParseErrorType hash_object_field_start ( void state,
char fname,
bool  isnull 
)
static

Definition at line 3850 of file jsonfuncs.c.

3851{
3853
3854 if (_state->lex->lex_level > 1)
3855 return JSON_SUCCESS;
3856
3857 /* remember token type */
3858 _state->saved_token_type = _state->lex->token_type;
3859
3860 if (_state->lex->token_type == JSON_TOKEN_ARRAY_START ||
3861 _state->lex->token_type == JSON_TOKEN_OBJECT_START)
3862 {
3863 /* remember start position of the whole text of the subobject */
3864 _state->save_json_start = _state->lex->token_start;
3865 }
3866 else
3867 {
3868 /* must be a scalar */
3869 _state->save_json_start = NULL;
3870 }
3871
3872 return JSON_SUCCESS;
3873}

References fb(), JSON_SUCCESS, JSON_TOKEN_ARRAY_START, and JSON_TOKEN_OBJECT_START.

Referenced by get_json_object_as_hash().

◆ hash_scalar()

static JsonParseErrorType hash_scalar ( void state,
char token,
JsonTokenType  tokentype 
)
static

Definition at line 3940 of file jsonfuncs.c.

3941{
3943
3944 if (_state->lex->lex_level == 0)
3945 ereport(ERROR,
3947 errmsg("cannot call %s on a scalar", _state->function_name)));
3948
3949 if (_state->lex->lex_level == 1)
3950 {
3951 _state->saved_scalar = token;
3952 /* saved_token_type must already be set in hash_object_field_start() */
3953 Assert(_state->saved_token_type == tokentype);
3954 }
3955
3956 return JSON_SUCCESS;
3957}

References Assert, ereport, errcode(), errmsg(), ERROR, fb(), JSON_SUCCESS, and token.

Referenced by get_json_object_as_hash().

◆ iterate_json_values()

◆ iterate_jsonb_values()

void iterate_jsonb_values ( Jsonb jb,
uint32  flags,
void state,
JsonIterateStringValuesAction  action 
)

Definition at line 5627 of file jsonfuncs.c.

5629{
5631 JsonbValue v;
5633
5634 it = JsonbIteratorInit(&jb->root);
5635
5636 /*
5637 * Just recursively iterating over jsonb and call callback on all
5638 * corresponding elements
5639 */
5640 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
5641 {
5642 if (type == WJB_KEY)
5643 {
5644 if (flags & jtiKey)
5645 action(state, v.val.string.val, v.val.string.len);
5646
5647 continue;
5648 }
5649 else if (!(type == WJB_VALUE || type == WJB_ELEM))
5650 {
5651 /* do not call callback for composite JsonbValue */
5652 continue;
5653 }
5654
5655 /* JsonbValue is a value of object or element of array */
5656 switch (v.type)
5657 {
5658 case jbvString:
5659 if (flags & jtiString)
5660 action(state, v.val.string.val, v.val.string.len);
5661 break;
5662 case jbvNumeric:
5663 if (flags & jtiNumeric)
5664 {
5665 char *val;
5666
5668 NumericGetDatum(v.val.numeric)));
5669
5671 pfree(val);
5672 }
5673 break;
5674 case jbvBool:
5675 if (flags & jtiBool)
5676 {
5677 if (v.val.boolean)
5678 action(state, "true", 4);
5679 else
5680 action(state, "false", 5);
5681 }
5682 break;
5683 default:
5684 /* do not call callback for composite JsonbValue */
5685 break;
5686 }
5687 }
5688}

References DatumGetCString(), DirectFunctionCall1, fb(), jbvBool, jbvNumeric, jbvString, JsonbIteratorInit(), JsonbIteratorNext(), jtiBool, jtiKey, jtiNumeric, jtiString, numeric_out(), NumericGetDatum(), pfree(), type, JsonbValue::type, JsonbValue::val, val, WJB_DONE, WJB_ELEM, WJB_KEY, and WJB_VALUE.

Referenced by jsonb_to_tsvector_worker().

◆ iterate_values_object_field_start()

static JsonParseErrorType iterate_values_object_field_start ( void state,
char fname,
bool  isnull 
)
static

Definition at line 5748 of file jsonfuncs.c.

5749{
5751
5752 if (_state->flags & jtiKey)
5753 {
5754 char *val = pstrdup(fname);
5755
5756 _state->action(_state->action_state, val, strlen(val));
5757 }
5758
5759 return JSON_SUCCESS;
5760}

References fb(), JSON_SUCCESS, jtiKey, pstrdup(), and val.

Referenced by iterate_json_values().

◆ iterate_values_scalar()

static JsonParseErrorType iterate_values_scalar ( void state,
char token,
JsonTokenType  tokentype 
)
static

Definition at line 5720 of file jsonfuncs.c.

5721{
5723
5724 switch (tokentype)
5725 {
5726 case JSON_TOKEN_STRING:
5727 if (_state->flags & jtiString)
5728 _state->action(_state->action_state, token, strlen(token));
5729 break;
5730 case JSON_TOKEN_NUMBER:
5731 if (_state->flags & jtiNumeric)
5732 _state->action(_state->action_state, token, strlen(token));
5733 break;
5734 case JSON_TOKEN_TRUE:
5735 case JSON_TOKEN_FALSE:
5736 if (_state->flags & jtiBool)
5737 _state->action(_state->action_state, token, strlen(token));
5738 break;
5739 default:
5740 /* do not call callback for any other token */
5741 break;
5742 }
5743
5744 return JSON_SUCCESS;
5745}

References fb(), JSON_SUCCESS, JSON_TOKEN_FALSE, JSON_TOKEN_NUMBER, JSON_TOKEN_STRING, JSON_TOKEN_TRUE, jtiBool, jtiNumeric, and jtiString.

Referenced by iterate_json_values().

◆ IteratorConcat()

static void IteratorConcat ( JsonbIterator **  it1,
JsonbIterator **  it2,
JsonbInState state 
)
static

Definition at line 5048 of file jsonfuncs.c.

5050{
5051 JsonbValue v1,
5052 v2;
5054 r2,
5055 rk1,
5056 rk2;
5057
5058 rk1 = JsonbIteratorNext(it1, &v1, false);
5059 rk2 = JsonbIteratorNext(it2, &v2, false);
5060
5061 /*
5062 * JsonbIteratorNext reports raw scalars as if they were single-element
5063 * arrays; hence we only need consider "object" and "array" cases here.
5064 */
5066 {
5067 /*
5068 * Both inputs are objects.
5069 *
5070 * Append all the tokens from v1 to res, except last WJB_END_OBJECT
5071 * (because res will not be finished yet).
5072 */
5074 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_OBJECT)
5076
5077 /*
5078 * Append all the tokens from v2 to res, including last WJB_END_OBJECT
5079 * (the concatenation will be completed). Any duplicate keys will
5080 * automatically override the value from the first object.
5081 */
5082 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5084 }
5085 else if (rk1 == WJB_BEGIN_ARRAY && rk2 == WJB_BEGIN_ARRAY)
5086 {
5087 /*
5088 * Both inputs are arrays.
5089 */
5091
5092 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_ARRAY)
5093 {
5094 Assert(r1 == WJB_ELEM);
5096 }
5097
5098 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_END_ARRAY)
5099 {
5100 Assert(r2 == WJB_ELEM);
5102 }
5103
5104 pushJsonbValue(state, WJB_END_ARRAY, NULL /* signal to sort */ );
5105 }
5106 else if (rk1 == WJB_BEGIN_OBJECT)
5107 {
5108 /*
5109 * We have object || array.
5110 */
5112
5114
5116 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_DONE)
5118
5119 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5121 }
5122 else
5123 {
5124 /*
5125 * We have array || object.
5126 */
5129
5131
5132 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_ARRAY)
5134
5136 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5138
5140 }
5141}

References Assert, fb(), JsonbIteratorNext(), pushJsonbValue(), WJB_BEGIN_ARRAY, WJB_BEGIN_OBJECT, WJB_DONE, WJB_ELEM, WJB_END_ARRAY, and WJB_END_OBJECT.

Referenced by jsonb_concat().

◆ JsObjectGetField()

static bool JsObjectGetField ( JsObject obj,
char field,
JsValue jsv 
)
static

Definition at line 3489 of file jsonfuncs.c.

3490{
3491 jsv->is_json = obj->is_json;
3492
3493 if (jsv->is_json)
3494 {
3496 HASH_FIND, NULL);
3497
3498 jsv->val.json.type = hashentry ? hashentry->type : JSON_TOKEN_NULL;
3499 jsv->val.json.str = jsv->val.json.type == JSON_TOKEN_NULL ? NULL :
3500 hashentry->val;
3501 jsv->val.json.len = jsv->val.json.str ? -1 : 0; /* null-terminated */
3502
3503 return hashentry != NULL;
3504 }
3505 else
3506 {
3507 jsv->val.jsonb = !obj->val.jsonb_cont ? NULL :
3509 NULL);
3510
3511 return jsv->val.jsonb != NULL;
3512 }
3513}

References fb(), getKeyJsonValueFromContainer(), HASH_FIND, hash_search(), JsObject::is_json, JsObject::json_hash, JSON_TOKEN_NULL, JsObject::jsonb_cont, and JsObject::val.

Referenced by populate_record().

◆ json_array_element()

Datum json_array_element ( PG_FUNCTION_ARGS  )

Definition at line 922 of file jsonfuncs.c.

923{
924 text *json = PG_GETARG_TEXT_PP(0);
925 int element = PG_GETARG_INT32(1);
926 text *result;
927
928 result = get_worker(json, NULL, &element, 1, false);
929
930 if (result != NULL)
931 PG_RETURN_TEXT_P(result);
932 else
934}

References element(), fb(), get_worker(), PG_GETARG_INT32, PG_GETARG_TEXT_PP, PG_RETURN_NULL, and PG_RETURN_TEXT_P.

◆ json_array_element_text()

Datum json_array_element_text ( PG_FUNCTION_ARGS  )

Definition at line 965 of file jsonfuncs.c.

966{
967 text *json = PG_GETARG_TEXT_PP(0);
968 int element = PG_GETARG_INT32(1);
969 text *result;
970
971 result = get_worker(json, NULL, &element, 1, true);
972
973 if (result != NULL)
974 PG_RETURN_TEXT_P(result);
975 else
977}

References element(), fb(), get_worker(), PG_GETARG_INT32, PG_GETARG_TEXT_PP, PG_RETURN_NULL, and PG_RETURN_TEXT_P.

◆ json_array_elements()

Datum json_array_elements ( PG_FUNCTION_ARGS  )

Definition at line 2293 of file jsonfuncs.c.

2294{
2295 return elements_worker(fcinfo, "json_array_elements", false);
2296}

References elements_worker().

◆ json_array_elements_text()

Datum json_array_elements_text ( PG_FUNCTION_ARGS  )

Definition at line 2299 of file jsonfuncs.c.

2300{
2301 return elements_worker(fcinfo, "json_array_elements_text", true);
2302}

References elements_worker().

◆ json_array_length()

◆ json_categorize_type()

void json_categorize_type ( Oid  typoid,
bool  is_jsonb,
JsonTypeCategory tcategory,
Oid outfuncoid 
)

Definition at line 5964 of file jsonfuncs.c.

5966{
5967 bool typisvarlena;
5968
5969 /* Look through any domain */
5970 typoid = getBaseType(typoid);
5971
5973
5974 switch (typoid)
5975 {
5976 case BOOLOID:
5979 break;
5980
5981 case INT2OID:
5982 case INT4OID:
5983 case INT8OID:
5984 case FLOAT4OID:
5985 case FLOAT8OID:
5986 case NUMERICOID:
5987 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
5989 break;
5990
5991 case DATEOID:
5994 break;
5995
5996 case TIMESTAMPOID:
5999 break;
6000
6001 case TIMESTAMPTZOID:
6004 break;
6005
6006 case JSONOID:
6007 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6009 break;
6010
6011 case JSONBOID:
6012 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6014 break;
6015
6016 default:
6017 /* Check for arrays and composites */
6018 if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
6019 || typoid == ANYCOMPATIBLEARRAYOID || typoid == RECORDARRAYOID)
6020 {
6023 }
6024 else if (type_is_rowtype(typoid)) /* includes RECORDOID */
6025 {
6028 }
6029 else
6030 {
6031 /*
6032 * It's probably the general case. But let's look for a cast
6033 * to json (note: not to jsonb even if is_jsonb is true), if
6034 * it's not built-in.
6035 */
6037 if (typoid >= FirstNormalObjectId)
6038 {
6039 Oid castfunc;
6040 CoercionPathType ctype;
6041
6042 ctype = find_coercion_pathway(JSONOID, typoid,
6044 &castfunc);
6045 if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc))
6046 {
6047 *outfuncoid = castfunc;
6049 }
6050 else
6051 {
6052 /* non builtin type with no cast */
6053 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6054 }
6055 }
6056 else
6057 {
6058 /* any other builtin type */
6059 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6060 }
6061 }
6062 break;
6063 }
6064}

References COERCION_EXPLICIT, COERCION_PATH_FUNC, fb(), find_coercion_pathway(), FirstNormalObjectId, get_element_type(), getBaseType(), getTypeOutputInfo(), InvalidOid, JSONTYPE_ARRAY, JSONTYPE_BOOL, JSONTYPE_CAST, JSONTYPE_COMPOSITE, JSONTYPE_DATE, JSONTYPE_JSON, JSONTYPE_JSONB, JSONTYPE_NUMERIC, JSONTYPE_OTHER, JSONTYPE_TIMESTAMP, JSONTYPE_TIMESTAMPTZ, OidIsValid, and type_is_rowtype().

Referenced by add_json(), add_jsonb(), array_to_json_internal(), array_to_jsonb_internal(), composite_to_json(), composite_to_jsonb(), ExecInitExprRec(), json_agg_transfn_worker(), json_object_agg_transfn_worker(), jsonb_agg_transfn_worker(), jsonb_object_agg_transfn_worker(), to_json(), to_json_is_immutable(), to_jsonb(), and to_jsonb_is_immutable().

◆ json_each()

Datum json_each ( PG_FUNCTION_ARGS  )

Definition at line 1947 of file jsonfuncs.c.

1948{
1949 return each_worker(fcinfo, false);
1950}

References each_worker().

◆ json_each_text()

Datum json_each_text ( PG_FUNCTION_ARGS  )

Definition at line 1959 of file jsonfuncs.c.

1960{
1961 return each_worker(fcinfo, true);
1962}

References each_worker().

◆ json_errsave_error()

void json_errsave_error ( JsonParseErrorType  error,
JsonLexContext lex,
Node escontext 
)

Definition at line 641 of file jsonfuncs.c.

643{
647 errsave(escontext,
649 errmsg("unsupported Unicode escape sequence"),
651 report_json_context(lex)));
652 else if (error == JSON_SEM_ACTION_FAILED)
653 {
654 /* semantic action function had better have reported something */
655 if (!SOFT_ERROR_OCCURRED(escontext))
656 elog(ERROR, "JSON semantic action function did not provide error information");
657 }
658 else
659 errsave(escontext,
661 errmsg("invalid input syntax for type %s", "json"),
663 report_json_context(lex)));
664}

References elog, errcode(), errdetail_internal(), errmsg(), ERROR, error(), errsave, fb(), json_errdetail(), JSON_SEM_ACTION_FAILED, JSON_UNICODE_CODE_POINT_ZERO, JSON_UNICODE_HIGH_ESCAPE, JSON_UNICODE_UNTRANSLATABLE, report_json_context(), and SOFT_ERROR_OCCURRED.

Referenced by get_array_start(), json_get_first_token(), json_typeof(), json_validate(), and pg_parse_json_or_errsave().

◆ json_extract_path()

Datum json_extract_path ( PG_FUNCTION_ARGS  )

Definition at line 1009 of file jsonfuncs.c.

1010{
1011 return get_path_all(fcinfo, false);
1012}

References get_path_all().

◆ json_extract_path_text()

Datum json_extract_path_text ( PG_FUNCTION_ARGS  )

Definition at line 1015 of file jsonfuncs.c.

1016{
1017 return get_path_all(fcinfo, true);
1018}

References get_path_all().

◆ json_get_first_token()

JsonTokenType json_get_first_token ( text json,
bool  throw_error 
)

Definition at line 5937 of file jsonfuncs.c.

5938{
5939 JsonLexContext lex;
5940 JsonParseErrorType result;
5941
5942 makeJsonLexContext(&lex, json, false);
5943
5944 /* Lex exactly one token from the input and check its type. */
5945 result = json_lex(&lex);
5946
5947 if (result == JSON_SUCCESS)
5948 return lex.token_type;
5949
5950 if (throw_error)
5951 json_errsave_error(result, &lex, NULL);
5952
5953 return JSON_TOKEN_INVALID; /* invalid json */
5954}

References fb(), json_errsave_error(), json_lex(), JSON_SUCCESS, JSON_TOKEN_INVALID, makeJsonLexContext(), and JsonLexContext::token_type.

Referenced by ExecEvalJsonIsPredicate().

◆ json_object_field()

Datum json_object_field ( PG_FUNCTION_ARGS  )

Definition at line 846 of file jsonfuncs.c.

847{
848 text *json = PG_GETARG_TEXT_PP(0);
849 text *fname = PG_GETARG_TEXT_PP(1);
850 char *fnamestr = text_to_cstring(fname);
851 text *result;
852
853 result = get_worker(json, &fnamestr, NULL, 1, false);
854
855 if (result != NULL)
856 PG_RETURN_TEXT_P(result);
857 else
859}

References fb(), get_worker(), PG_GETARG_TEXT_PP, PG_RETURN_NULL, PG_RETURN_TEXT_P, and text_to_cstring().

◆ json_object_field_text()

Datum json_object_field_text ( PG_FUNCTION_ARGS  )

Definition at line 884 of file jsonfuncs.c.

885{
886 text *json = PG_GETARG_TEXT_PP(0);
887 text *fname = PG_GETARG_TEXT_PP(1);
888 char *fnamestr = text_to_cstring(fname);
889 text *result;
890
891 result = get_worker(json, &fnamestr, NULL, 1, true);
892
893 if (result != NULL)
894 PG_RETURN_TEXT_P(result);
895 else
897}

References fb(), get_worker(), PG_GETARG_TEXT_PP, PG_RETURN_NULL, PG_RETURN_TEXT_P, and text_to_cstring().

◆ json_object_keys()

Datum json_object_keys ( PG_FUNCTION_ARGS  )

Definition at line 732 of file jsonfuncs.c.

733{
736
737 if (SRF_IS_FIRSTCALL())
738 {
739 text *json = PG_GETARG_TEXT_PP(0);
740 JsonLexContext lex;
742 MemoryContext oldcontext;
743
745 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
746
749
750 state->lex = makeJsonLexContext(&lex, json, true);
751 state->result_size = 256;
752 state->result_count = 0;
753 state->sent_count = 0;
754 state->result = palloc_array(char *, 256);
755
756 sem->semstate = state;
760 /* remainder are all NULL, courtesy of palloc0 above */
761
763 /* keys are now in state->result */
764
765 freeJsonLexContext(&lex);
766 pfree(sem);
767
768 MemoryContextSwitchTo(oldcontext);
769 funcctx->user_fctx = state;
770 }
771
773 state = (OkeysState *) funcctx->user_fctx;
774
775 if (state->sent_count < state->result_count)
776 {
777 char *nxt = state->result[state->sent_count++];
778
780 }
781
783}

References JsonSemAction::array_start, CStringGetTextDatum, fb(), freeJsonLexContext(), makeJsonLexContext(), MemoryContextSwitchTo(), JsonSemAction::object_field_start, okeys_array_start(), okeys_object_field_start(), okeys_scalar(), palloc0_object, palloc_array, palloc_object, pfree(), PG_GETARG_TEXT_PP, pg_parse_json_or_ereport, JsonSemAction::scalar, sem, JsonSemAction::semstate, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, and SRF_RETURN_NEXT.

◆ json_populate_record()

Datum json_populate_record ( PG_FUNCTION_ARGS  )

Definition at line 2492 of file jsonfuncs.c.

2493{
2494 return populate_record_worker(fcinfo, "json_populate_record",
2495 true, true, NULL);
2496}

References fb(), and populate_record_worker().

◆ json_populate_recordset()

Datum json_populate_recordset ( PG_FUNCTION_ARGS  )

Definition at line 3985 of file jsonfuncs.c.

3986{
3987 return populate_recordset_worker(fcinfo, "json_populate_recordset",
3988 true, true);
3989}

References populate_recordset_worker().

◆ json_populate_type()

Datum json_populate_type ( Datum  json_val,
Oid  json_type,
Oid  typid,
int32  typmod,
void **  cache,
MemoryContext  mcxt,
bool isnull,
bool  omit_quotes,
Node escontext 
)

Definition at line 3342 of file jsonfuncs.c.

3347{
3348 JsValue jsv = {0};
3350
3351 jsv.is_json = json_type == JSONOID;
3352
3353 if (*isnull)
3354 {
3355 if (jsv.is_json)
3356 jsv.val.json.str = NULL;
3357 else
3358 jsv.val.jsonb = NULL;
3359 }
3360 else if (jsv.is_json)
3361 {
3362 text *json = DatumGetTextPP(json_val);
3363
3364 jsv.val.json.str = VARDATA_ANY(json);
3365 jsv.val.json.len = VARSIZE_ANY_EXHDR(json);
3366 jsv.val.json.type = JSON_TOKEN_INVALID; /* not used in
3367 * populate_composite() */
3368 }
3369 else
3370 {
3371 Jsonb *jsonb = DatumGetJsonbP(json_val);
3372
3373 jsv.val.jsonb = &jbv;
3374
3375 if (omit_quotes)
3376 {
3378
3379 /* fill the quote-stripped string */
3380 jbv.type = jbvString;
3381 jbv.val.string.len = strlen(str);
3382 jbv.val.string.val = str;
3383 }
3384 else
3385 {
3386 /* fill binary jsonb value pointing to jb */
3387 jbv.type = jbvBinary;
3388 jbv.val.binary.data = &jsonb->root;
3389 jbv.val.binary.len = VARSIZE(jsonb) - VARHDRSZ;
3390 }
3391 }
3392
3393 if (*cache == NULL)
3394 *cache = MemoryContextAllocZero(mcxt, sizeof(ColumnIOData));
3395
3396 return populate_record_field(*cache, typid, typmod, NULL, mcxt,
3397 PointerGetDatum(NULL), &jsv, isnull,
3398 escontext, omit_quotes);
3399}

References DatumGetJsonbP(), DatumGetTextPP, fb(), jbvBinary, jbvString, JSON_TOKEN_INVALID, JsonbUnquote(), MemoryContextAllocZero(), PointerGetDatum(), populate_record_field(), Jsonb::root, str, JsonbValue::val, VARDATA_ANY(), VARHDRSZ, VARSIZE(), and VARSIZE_ANY_EXHDR().

Referenced by ExecEvalJsonCoercion().

◆ json_strip_nulls()

Datum json_strip_nulls ( PG_FUNCTION_ARGS  )

Definition at line 4502 of file jsonfuncs.c.

4503{
4504 text *json = PG_GETARG_TEXT_PP(0);
4505 bool strip_in_arrays = PG_NARGS() == 2 ? PG_GETARG_BOOL(1) : false;
4508 JsonLexContext lex;
4510
4514
4515 state->lex = makeJsonLexContext(&lex, json, true);
4516 state->strval = &strbuf;
4517 state->skip_next_null = false;
4518 state->strip_in_arrays = strip_in_arrays;
4519
4520 sem->semstate = state;
4525 sem->scalar = sn_scalar;
4528
4530
4532 state->strval->len));
4533}

References JsonSemAction::array_element_start, JsonSemAction::array_end, JsonSemAction::array_start, cstring_to_text_with_len(), fb(), initStringInfo(), makeJsonLexContext(), JsonSemAction::object_end, JsonSemAction::object_field_start, JsonSemAction::object_start, palloc0_object, PG_GETARG_BOOL, PG_GETARG_TEXT_PP, PG_NARGS, pg_parse_json_or_ereport, PG_RETURN_TEXT_P, JsonSemAction::scalar, sem, JsonSemAction::semstate, sn_array_element_start(), sn_array_end(), sn_array_start(), sn_object_end(), sn_object_field_start(), sn_object_start(), and sn_scalar().

◆ json_to_record()

Datum json_to_record ( PG_FUNCTION_ARGS  )

Definition at line 2499 of file jsonfuncs.c.

2500{
2501 return populate_record_worker(fcinfo, "json_to_record",
2502 true, false, NULL);
2503}

References fb(), and populate_record_worker().

◆ json_to_recordset()

Datum json_to_recordset ( PG_FUNCTION_ARGS  )

Definition at line 3992 of file jsonfuncs.c.

3993{
3994 return populate_recordset_worker(fcinfo, "json_to_recordset",
3995 true, false);
3996}

References populate_recordset_worker().

◆ jsonb_array_element()

Datum jsonb_array_element ( PG_FUNCTION_ARGS  )

Definition at line 937 of file jsonfuncs.c.

938{
940 int element = PG_GETARG_INT32(1);
941 JsonbValue *v;
942
943 if (!JB_ROOT_IS_ARRAY(jb))
945
946 /* Handle negative subscript */
947 if (element < 0)
948 {
949 uint32 nelements = JB_ROOT_COUNT(jb);
950
951 if (pg_abs_s32(element) > nelements)
953 else
954 element += nelements;
955 }
956
958 if (v != NULL)
960
962}

References element(), fb(), getIthJsonbValueFromContainer(), JB_ROOT_COUNT, JB_ROOT_IS_ARRAY, JsonbValueToJsonb(), pg_abs_s32(), PG_GETARG_INT32, PG_GETARG_JSONB_P, PG_RETURN_JSONB_P, and PG_RETURN_NULL.

◆ jsonb_array_element_text()

Datum jsonb_array_element_text ( PG_FUNCTION_ARGS  )

Definition at line 980 of file jsonfuncs.c.

981{
983 int element = PG_GETARG_INT32(1);
984 JsonbValue *v;
985
986 if (!JB_ROOT_IS_ARRAY(jb))
988
989 /* Handle negative subscript */
990 if (element < 0)
991 {
992 uint32 nelements = JB_ROOT_COUNT(jb);
993
994 if (pg_abs_s32(element) > nelements)
996 else
997 element += nelements;
998 }
999
1001
1002 if (v != NULL && v->type != jbvNull)
1004
1006}

References element(), fb(), getIthJsonbValueFromContainer(), JB_ROOT_COUNT, JB_ROOT_IS_ARRAY, jbvNull, JsonbValueAsText(), pg_abs_s32(), PG_GETARG_INT32, PG_GETARG_JSONB_P, PG_RETURN_NULL, PG_RETURN_TEXT_P, and JsonbValue::type.

◆ jsonb_array_elements()

Datum jsonb_array_elements ( PG_FUNCTION_ARGS  )

Definition at line 2205 of file jsonfuncs.c.

2206{
2207 return elements_worker_jsonb(fcinfo, "jsonb_array_elements", false);
2208}

References elements_worker_jsonb().

◆ jsonb_array_elements_text()

Datum jsonb_array_elements_text ( PG_FUNCTION_ARGS  )

Definition at line 2211 of file jsonfuncs.c.

2212{
2213 return elements_worker_jsonb(fcinfo, "jsonb_array_elements_text", true);
2214}

References elements_worker_jsonb().

◆ jsonb_array_length()

Datum jsonb_array_length ( PG_FUNCTION_ARGS  )

Definition at line 1875 of file jsonfuncs.c.

1876{
1878
1879 if (JB_ROOT_IS_SCALAR(jb))
1880 ereport(ERROR,
1882 errmsg("cannot get array length of a scalar")));
1883 else if (!JB_ROOT_IS_ARRAY(jb))
1884 ereport(ERROR,
1886 errmsg("cannot get array length of a non-array")));
1887
1889}

References ereport, errcode(), errmsg(), ERROR, fb(), JB_ROOT_COUNT, JB_ROOT_IS_ARRAY, JB_ROOT_IS_SCALAR, PG_GETARG_JSONB_P, and PG_RETURN_INT32.

◆ jsonb_concat()

Datum jsonb_concat ( PG_FUNCTION_ARGS  )

Definition at line 4620 of file jsonfuncs.c.

4621{
4624 JsonbInState state = {0};
4626 *it2;
4627
4628 /*
4629 * If one of the jsonb is empty, just return the other if it's not scalar
4630 * and both are of the same kind. If it's a scalar or they are of
4631 * different kinds we need to perform the concatenation even if one is
4632 * empty.
4633 */
4635 {
4636 if (JB_ROOT_COUNT(jb1) == 0 && !JB_ROOT_IS_SCALAR(jb2))
4638 else if (JB_ROOT_COUNT(jb2) == 0 && !JB_ROOT_IS_SCALAR(jb1))
4640 }
4641
4642 it1 = JsonbIteratorInit(&jb1->root);
4643 it2 = JsonbIteratorInit(&jb2->root);
4644
4646
4648}

References fb(), IteratorConcat(), JB_ROOT_COUNT, JB_ROOT_IS_OBJECT, JB_ROOT_IS_SCALAR, JsonbIteratorInit(), JsonbValueToJsonb(), PG_GETARG_JSONB_P, and PG_RETURN_JSONB_P.

◆ jsonb_delete()

Datum jsonb_delete ( PG_FUNCTION_ARGS  )

Definition at line 4658 of file jsonfuncs.c.

4659{
4660 Jsonb *in = PG_GETARG_JSONB_P(0);
4662 char *keyptr = VARDATA_ANY(key);
4663 int keylen = VARSIZE_ANY_EXHDR(key);
4664 JsonbInState pstate = {0};
4666 JsonbValue v;
4667 bool skipNested = false;
4669
4670 if (JB_ROOT_IS_SCALAR(in))
4671 ereport(ERROR,
4673 errmsg("cannot delete from scalar")));
4674
4675 if (JB_ROOT_COUNT(in) == 0)
4677
4678 it = JsonbIteratorInit(&in->root);
4679
4680 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4681 {
4682 skipNested = true;
4683
4684 if ((r == WJB_ELEM || r == WJB_KEY) &&
4685 (v.type == jbvString && keylen == v.val.string.len &&
4686 memcmp(keyptr, v.val.string.val, keylen) == 0))
4687 {
4688 /* skip corresponding value as well */
4689 if (r == WJB_KEY)
4690 (void) JsonbIteratorNext(&it, &v, true);
4691
4692 continue;
4693 }
4694
4695 pushJsonbValue(&pstate, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4696 }
4697
4699}

References ereport, errcode(), errmsg(), ERROR, fb(), JB_ROOT_COUNT, JB_ROOT_IS_SCALAR, jbvString, JsonbIteratorInit(), JsonbIteratorNext(), JsonbValueToJsonb(), PG_GETARG_JSONB_P, PG_GETARG_TEXT_PP, PG_RETURN_JSONB_P, pushJsonbValue(), JsonbInState::result, Jsonb::root, JsonbValue::type, JsonbValue::val, VARDATA_ANY(), VARSIZE_ANY_EXHDR(), WJB_BEGIN_ARRAY, WJB_DONE, WJB_ELEM, and WJB_KEY.

◆ jsonb_delete_array()

Datum jsonb_delete_array ( PG_FUNCTION_ARGS  )

Definition at line 4708 of file jsonfuncs.c.

4709{
4710 Jsonb *in = PG_GETARG_JSONB_P(0);
4713 bool *keys_nulls;
4714 int keys_len;
4715 JsonbInState pstate = {0};
4717 JsonbValue v;
4718 bool skipNested = false;
4720
4721 if (ARR_NDIM(keys) > 1)
4722 ereport(ERROR,
4724 errmsg("wrong number of array subscripts")));
4725
4726 if (JB_ROOT_IS_SCALAR(in))
4727 ereport(ERROR,
4729 errmsg("cannot delete from scalar")));
4730
4731 if (JB_ROOT_COUNT(in) == 0)
4733
4735
4736 if (keys_len == 0)
4738
4739 it = JsonbIteratorInit(&in->root);
4740
4741 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4742 {
4743 skipNested = true;
4744
4745 if ((r == WJB_ELEM || r == WJB_KEY) && v.type == jbvString)
4746 {
4747 int i;
4748 bool found = false;
4749
4750 for (i = 0; i < keys_len; i++)
4751 {
4752 char *keyptr;
4753 int keylen;
4754
4755 if (keys_nulls[i])
4756 continue;
4757
4758 /* We rely on the array elements not being toasted */
4761 if (keylen == v.val.string.len &&
4762 memcmp(keyptr, v.val.string.val, keylen) == 0)
4763 {
4764 found = true;
4765 break;
4766 }
4767 }
4768 if (found)
4769 {
4770 /* skip corresponding value as well */
4771 if (r == WJB_KEY)
4772 (void) JsonbIteratorNext(&it, &v, true);
4773
4774 continue;
4775 }
4776 }
4777
4778 pushJsonbValue(&pstate, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4779 }
4780
4782}

References ARR_NDIM, DatumGetPointer(), deconstruct_array_builtin(), ereport, errcode(), errmsg(), ERROR, fb(), i, JB_ROOT_COUNT, JB_ROOT_IS_SCALAR, jbvString, JsonbIteratorInit(), JsonbIteratorNext(), JsonbValueToJsonb(), PG_GETARG_ARRAYTYPE_P, PG_GETARG_JSONB_P, PG_RETURN_JSONB_P, pushJsonbValue(), JsonbInState::result, Jsonb::root, JsonbValue::type, JsonbValue::val, VARDATA_ANY(), VARSIZE_ANY_EXHDR(), WJB_BEGIN_ARRAY, WJB_DONE, WJB_ELEM, and WJB_KEY.

◆ jsonb_delete_idx()

Datum jsonb_delete_idx ( PG_FUNCTION_ARGS  )

Definition at line 4792 of file jsonfuncs.c.

4793{
4794 Jsonb *in = PG_GETARG_JSONB_P(0);
4795 int idx = PG_GETARG_INT32(1);
4796 JsonbInState pstate = {0};
4798 uint32 i = 0,
4799 n;
4800 JsonbValue v;
4802
4803 if (JB_ROOT_IS_SCALAR(in))
4804 ereport(ERROR,
4806 errmsg("cannot delete from scalar")));
4807
4808 if (JB_ROOT_IS_OBJECT(in))
4809 ereport(ERROR,
4811 errmsg("cannot delete from object using integer index")));
4812
4813 if (JB_ROOT_COUNT(in) == 0)
4815
4816 it = JsonbIteratorInit(&in->root);
4817
4818 r = JsonbIteratorNext(&it, &v, false);
4819 Assert(r == WJB_BEGIN_ARRAY);
4820 n = v.val.array.nElems;
4821
4822 if (idx < 0)
4823 {
4824 if (pg_abs_s32(idx) > n)
4825 idx = n;
4826 else
4827 idx = n + idx;
4828 }
4829
4830 if (idx >= n)
4832
4833 pushJsonbValue(&pstate, r, NULL);
4834
4835 while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
4836 {
4837 if (r == WJB_ELEM)
4838 {
4839 if (i++ == idx)
4840 continue;
4841 }
4842
4843 pushJsonbValue(&pstate, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4844 }
4845
4847}

References Assert, ereport, errcode(), errmsg(), ERROR, fb(), i, idx(), JB_ROOT_COUNT, JB_ROOT_IS_OBJECT, JB_ROOT_IS_SCALAR, JsonbIteratorInit(), JsonbIteratorNext(), JsonbValueToJsonb(), pg_abs_s32(), PG_GETARG_INT32, PG_GETARG_JSONB_P, PG_RETURN_JSONB_P, pushJsonbValue(), JsonbInState::result, Jsonb::root, JsonbValue::val, WJB_BEGIN_ARRAY, WJB_DONE, and WJB_ELEM.

◆ jsonb_delete_path()

Datum jsonb_delete_path ( PG_FUNCTION_ARGS  )

Definition at line 4962 of file jsonfuncs.c.

4963{
4964 Jsonb *in = PG_GETARG_JSONB_P(0);
4967 bool *path_nulls;
4968 int path_len;
4970 JsonbInState st = {0};
4971
4972 if (ARR_NDIM(path) > 1)
4973 ereport(ERROR,
4975 errmsg("wrong number of array subscripts")));
4976
4977 if (JB_ROOT_IS_SCALAR(in))
4978 ereport(ERROR,
4980 errmsg("cannot delete path in scalar")));
4981
4982 if (JB_ROOT_COUNT(in) == 0)
4984
4986
4987 if (path_len == 0)
4989
4990 it = JsonbIteratorInit(&in->root);
4991
4993 0, NULL, JB_PATH_DELETE);
4994
4996}

References ARR_NDIM, deconstruct_array_builtin(), ereport, errcode(), errmsg(), ERROR, fb(), JB_PATH_DELETE, JB_ROOT_COUNT, JB_ROOT_IS_SCALAR, JsonbIteratorInit(), JsonbValueToJsonb(), PG_GETARG_ARRAYTYPE_P, PG_GETARG_JSONB_P, PG_RETURN_JSONB_P, JsonbInState::result, Jsonb::root, and setPath().

Referenced by jsonb_set_lax().

◆ jsonb_each()

Datum jsonb_each ( PG_FUNCTION_ARGS  )

Definition at line 1953 of file jsonfuncs.c.

1954{
1955 return each_worker_jsonb(fcinfo, "jsonb_each", false);
1956}

References each_worker_jsonb().

◆ jsonb_each_text()

Datum jsonb_each_text ( PG_FUNCTION_ARGS  )

Definition at line 1965 of file jsonfuncs.c.

1966{
1967 return each_worker_jsonb(fcinfo, "jsonb_each_text", true);
1968}

References each_worker_jsonb().

◆ jsonb_extract_path()

Datum jsonb_extract_path ( PG_FUNCTION_ARGS  )

Definition at line 1488 of file jsonfuncs.c.

1489{
1490 return get_jsonb_path_all(fcinfo, false);
1491}

References get_jsonb_path_all().

◆ jsonb_extract_path_text()

Datum jsonb_extract_path_text ( PG_FUNCTION_ARGS  )

Definition at line 1494 of file jsonfuncs.c.

1495{
1496 return get_jsonb_path_all(fcinfo, true);
1497}

References get_jsonb_path_all().

◆ jsonb_get_element()

Datum jsonb_get_element ( Jsonb jb,
const Datum path,
int  npath,
bool isnull,
bool  as_text 
)

Definition at line 1531 of file jsonfuncs.c.

1532{
1533 JsonbContainer *container = &jb->root;
1534 JsonbValue *jbvp = NULL;
1535 int i;
1536 bool have_object = false,
1537 have_array = false;
1538
1539 *isnull = false;
1540
1541 /* Identify whether we have object, array, or scalar at top-level */
1542 if (JB_ROOT_IS_OBJECT(jb))
1543 have_object = true;
1544 else if (JB_ROOT_IS_ARRAY(jb) && !JB_ROOT_IS_SCALAR(jb))
1545 have_array = true;
1546 else
1547 {
1549 /* Extract the scalar value, if it is what we'll return */
1550 if (npath <= 0)
1551 jbvp = getIthJsonbValueFromContainer(container, 0);
1552 }
1553
1554 /*
1555 * If the array is empty, return the entire LHS object, on the grounds
1556 * that we should do zero field or element extractions. For the
1557 * non-scalar case we can just hand back the object without much work. For
1558 * the scalar case, fall through and deal with the value below the loop.
1559 * (This inconsistency arises because there's no easy way to generate a
1560 * JsonbValue directly for root-level containers.)
1561 */
1562 if (npath <= 0 && jbvp == NULL)
1563 {
1564 if (as_text)
1565 {
1567 container,
1568 VARSIZE(jb))));
1569 }
1570 else
1571 {
1572 /* not text mode - just hand back the jsonb */
1574 }
1575 }
1576
1577 for (i = 0; i < npath; i++)
1578 {
1579 if (have_object)
1580 {
1581 text *subscr = DatumGetTextPP(path[i]);
1582
1586 NULL);
1587 }
1588 else if (have_array)
1589 {
1590 int lindex;
1591 uint32 index;
1592 char *indextext = TextDatumGetCString(path[i]);
1593 char *endptr;
1594
1595 errno = 0;
1596 lindex = strtoint(indextext, &endptr, 10);
1597 if (endptr == indextext || *endptr != '\0' || errno != 0)
1598 {
1599 *isnull = true;
1600 return PointerGetDatum(NULL);
1601 }
1602
1603 if (lindex >= 0)
1604 {
1605 index = (uint32) lindex;
1606 }
1607 else
1608 {
1609 /* Handle negative subscript */
1610 uint32 nelements;
1611
1612 /* Container must be array, but make sure */
1613 if (!JsonContainerIsArray(container))
1614 elog(ERROR, "not a jsonb array");
1615
1616 nelements = JsonContainerSize(container);
1617
1618 if (lindex == INT_MIN || -lindex > nelements)
1619 {
1620 *isnull = true;
1621 return PointerGetDatum(NULL);
1622 }
1623 else
1624 index = nelements + lindex;
1625 }
1626
1628 }
1629 else
1630 {
1631 /* scalar, extraction yields a null */
1632 *isnull = true;
1633 return PointerGetDatum(NULL);
1634 }
1635
1636 if (jbvp == NULL)
1637 {
1638 *isnull = true;
1639 return PointerGetDatum(NULL);
1640 }
1641 else if (i == npath - 1)
1642 break;
1643
1644 if (jbvp->type == jbvBinary)
1645 {
1646 container = jbvp->val.binary.data;
1648 have_array = JsonContainerIsArray(container);
1649 Assert(!JsonContainerIsScalar(container));
1650 }
1651 else
1652 {
1654 have_object = false;
1655 have_array = false;
1656 }
1657 }
1658
1659 if (as_text)
1660 {
1661 if (jbvp->type == jbvNull)
1662 {
1663 *isnull = true;
1664 return PointerGetDatum(NULL);
1665 }
1666
1668 }
1669 else
1670 {
1672
1673 /* not text mode - just hand back the jsonb */
1674 PG_RETURN_JSONB_P(res);
1675 }
1676}

References Assert, cstring_to_text(), DatumGetTextPP, elog, ERROR, fb(), getIthJsonbValueFromContainer(), getKeyJsonValueFromContainer(), i, IsAJsonbScalar, JB_ROOT_IS_ARRAY, JB_ROOT_IS_OBJECT, JB_ROOT_IS_SCALAR, jbvBinary, jbvNull, JsonbToCString(), JsonbValueAsText(), JsonbValueToJsonb(), JsonContainerIsArray, JsonContainerIsObject, JsonContainerIsScalar, JsonContainerSize, PG_RETURN_JSONB_P, PointerGetDatum(), strtoint(), TextDatumGetCString, VARDATA_ANY(), VARSIZE(), and VARSIZE_ANY_EXHDR().

Referenced by get_jsonb_path_all(), jsonb_subscript_fetch(), and jsonb_subscript_fetch_old().

◆ jsonb_insert()

◆ jsonb_object_field()

◆ jsonb_object_field_text()

◆ jsonb_object_keys()

Datum jsonb_object_keys ( PG_FUNCTION_ARGS  )

Definition at line 568 of file jsonfuncs.c.

569{
572
573 if (SRF_IS_FIRSTCALL())
574 {
575 MemoryContext oldcontext;
577 bool skipNested = false;
579 JsonbValue v;
581
585 errmsg("cannot call %s on a scalar",
586 "jsonb_object_keys")));
587 else if (JB_ROOT_IS_ARRAY(jb))
590 errmsg("cannot call %s on an array",
591 "jsonb_object_keys")));
592
594 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
595
597
598 state->result_size = JB_ROOT_COUNT(jb);
599 state->result_count = 0;
600 state->sent_count = 0;
601 state->result = palloc_array(char *, state->result_size);
602
603 it = JsonbIteratorInit(&jb->root);
604
605 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
606 {
607 skipNested = true;
608
609 if (r == WJB_KEY)
610 {
611 char *cstr;
612
613 cstr = palloc(v.val.string.len + 1 * sizeof(char));
614 memcpy(cstr, v.val.string.val, v.val.string.len);
615 cstr[v.val.string.len] = '\0';
616 state->result[state->result_count++] = cstr;
617 }
618 }
619
620 MemoryContextSwitchTo(oldcontext);
621 funcctx->user_fctx = state;
622 }
623
625 state = (OkeysState *) funcctx->user_fctx;
626
627 if (state->sent_count < state->result_count)
628 {
629 char *nxt = state->result[state->sent_count++];
630
632 }
633
635}

References CStringGetTextDatum, ereport, errcode(), errmsg(), ERROR, fb(), JB_ROOT_COUNT, JB_ROOT_IS_ARRAY, JB_ROOT_IS_SCALAR, JsonbIteratorInit(), JsonbIteratorNext(), MemoryContextSwitchTo(), palloc(), palloc_array, palloc_object, PG_GETARG_JSONB_P, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, JsonbValue::val, WJB_DONE, and WJB_KEY.

◆ jsonb_populate_record()

Datum jsonb_populate_record ( PG_FUNCTION_ARGS  )

Definition at line 2461 of file jsonfuncs.c.

2462{
2463 return populate_record_worker(fcinfo, "jsonb_populate_record",
2464 false, true, NULL);
2465}

References fb(), and populate_record_worker().

◆ jsonb_populate_record_valid()

Datum jsonb_populate_record_valid ( PG_FUNCTION_ARGS  )

Definition at line 2474 of file jsonfuncs.c.

2475{
2477
2478 (void) populate_record_worker(fcinfo, "jsonb_populate_record",
2479 false, true, (Node *) &escontext);
2480
2481 return BoolGetDatum(!escontext.error_occurred);
2482}

References BoolGetDatum(), ErrorSaveContext::error_occurred, fb(), and populate_record_worker().

◆ jsonb_populate_recordset()

Datum jsonb_populate_recordset ( PG_FUNCTION_ARGS  )

Definition at line 3971 of file jsonfuncs.c.

3972{
3973 return populate_recordset_worker(fcinfo, "jsonb_populate_recordset",
3974 false, true);
3975}

References populate_recordset_worker().

◆ jsonb_pretty()

◆ jsonb_set()

Datum jsonb_set ( PG_FUNCTION_ARGS  )

Definition at line 4853 of file jsonfuncs.c.

4854{
4855 Jsonb *in = PG_GETARG_JSONB_P(0);
4859 bool create = PG_GETARG_BOOL(3);
4861 bool *path_nulls;
4862 int path_len;
4864 JsonbInState st = {0};
4865
4867
4868 if (ARR_NDIM(path) > 1)
4869 ereport(ERROR,
4871 errmsg("wrong number of array subscripts")));
4872
4873 if (JB_ROOT_IS_SCALAR(in))
4874 ereport(ERROR,
4876 errmsg("cannot set path in scalar")));
4877
4878 if (JB_ROOT_COUNT(in) == 0 && !create)
4880
4882
4883 if (path_len == 0)
4885
4886 it = JsonbIteratorInit(&in->root);
4887
4889 0, &newval, create ? JB_PATH_CREATE : JB_PATH_REPLACE);
4890
4892}

References ARR_NDIM, deconstruct_array_builtin(), ereport, errcode(), errmsg(), ERROR, fb(), JB_PATH_CREATE, JB_PATH_REPLACE, JB_ROOT_COUNT, JB_ROOT_IS_SCALAR, JsonbIteratorInit(), JsonbToJsonbValue(), JsonbValueToJsonb(), newval, PG_GETARG_ARRAYTYPE_P, PG_GETARG_BOOL, PG_GETARG_JSONB_P, PG_RETURN_JSONB_P, JsonbInState::result, Jsonb::root, and setPath().

Referenced by jsonb_set_lax().

◆ jsonb_set_element()

Datum jsonb_set_element ( Jsonb jb,
const Datum path,
int  path_len,
JsonbValue newval 
)

Definition at line 1679 of file jsonfuncs.c.

1681{
1682 JsonbInState state = {0};
1684 bool *path_nulls = palloc0_array(bool, path_len);
1685
1686 if (newval->type == jbvArray && newval->val.array.rawScalar)
1687 *newval = newval->val.array.elems[0];
1688
1689 it = JsonbIteratorInit(&jb->root);
1690
1691 setPath(&it, path, path_nulls, path_len, &state, 0, newval,
1694
1696
1698}

References fb(), JB_PATH_CONSISTENT_POSITION, JB_PATH_CREATE, JB_PATH_FILL_GAPS, jbvArray, JsonbIteratorInit(), JsonbValueToJsonb(), newval, palloc0_array, pfree(), PG_RETURN_JSONB_P, and setPath().

Referenced by jsonb_subscript_assign().

◆ jsonb_set_lax()

Datum jsonb_set_lax ( PG_FUNCTION_ARGS  )

Definition at line 4899 of file jsonfuncs.c.

4900{
4902 char *handle_val;
4903
4904 if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(3))
4906
4907 /* could happen if they pass in an explicit NULL */
4908 if (PG_ARGISNULL(4))
4909 ereport(ERROR,
4911 errmsg("null_value_treatment must be \"delete_key\", \"return_target\", \"use_json_null\", or \"raise_exception\"")));
4912
4913 /* if the new value isn't an SQL NULL just call jsonb_set */
4914 if (!PG_ARGISNULL(2))
4915 return jsonb_set(fcinfo);
4916
4919
4920 if (strcmp(handle_val, "raise_exception") == 0)
4921 {
4922 ereport(ERROR,
4924 errmsg("JSON value must not be null"),
4925 errdetail("Exception was raised because null_value_treatment is \"raise_exception\"."),
4926 errhint("To avoid, either change the null_value_treatment argument or ensure that an SQL NULL is not passed.")));
4927 return (Datum) 0; /* silence stupider compilers */
4928 }
4929 else if (strcmp(handle_val, "use_json_null") == 0)
4930 {
4931 Datum newval;
4932
4934
4935 fcinfo->args[2].value = newval;
4936 fcinfo->args[2].isnull = false;
4937 return jsonb_set(fcinfo);
4938 }
4939 else if (strcmp(handle_val, "delete_key") == 0)
4940 {
4941 return jsonb_delete_path(fcinfo);
4942 }
4943 else if (strcmp(handle_val, "return_target") == 0)
4944 {
4945 Jsonb *in = PG_GETARG_JSONB_P(0);
4946
4948 }
4949 else
4950 {
4951 ereport(ERROR,
4953 errmsg("null_value_treatment must be \"delete_key\", \"return_target\", \"use_json_null\", or \"raise_exception\"")));
4954 return (Datum) 0; /* silence stupider compilers */
4955 }
4956}

References CStringGetDatum(), DirectFunctionCall1, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, fb(), jsonb_delete_path(), jsonb_in(), jsonb_set(), newval, PG_ARGISNULL, PG_GETARG_JSONB_P, PG_GETARG_TEXT_P, PG_RETURN_JSONB_P, PG_RETURN_NULL, and text_to_cstring().

◆ jsonb_strip_nulls()

Datum jsonb_strip_nulls ( PG_FUNCTION_ARGS  )

Definition at line 4539 of file jsonfuncs.c.

4540{
4542 bool strip_in_arrays = false;
4544 JsonbInState parseState = {0};
4545 JsonbValue v,
4546 k;
4548 bool last_was_key = false;
4549
4550 if (PG_NARGS() == 2)
4551 strip_in_arrays = PG_GETARG_BOOL(1);
4552
4553 if (JB_ROOT_IS_SCALAR(jb))
4555
4556 it = JsonbIteratorInit(&jb->root);
4557
4558 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
4559 {
4560 Assert(!(type == WJB_KEY && last_was_key));
4561
4562 if (type == WJB_KEY)
4563 {
4564 /* stash the key until we know if it has a null value */
4565 k = v;
4566 last_was_key = true;
4567 continue;
4568 }
4569
4570 if (last_was_key)
4571 {
4572 /* if the last element was a key this one can't be */
4573 last_was_key = false;
4574
4575 /* skip this field if value is null */
4576 if (type == WJB_VALUE && v.type == jbvNull)
4577 continue;
4578
4579 /* otherwise, do a delayed push of the key */
4580 pushJsonbValue(&parseState, WJB_KEY, &k);
4581 }
4582
4583 /* if strip_in_arrays is set, also skip null array elements */
4584 if (strip_in_arrays)
4585 if (type == WJB_ELEM && v.type == jbvNull)
4586 continue;
4587
4588 if (type == WJB_VALUE || type == WJB_ELEM)
4589 pushJsonbValue(&parseState, type, &v);
4590 else
4591 pushJsonbValue(&parseState, type, NULL);
4592 }
4593
4595}

References Assert, fb(), JB_ROOT_IS_SCALAR, jbvNull, JsonbIteratorInit(), JsonbIteratorNext(), JsonbValueToJsonb(), PG_GETARG_BOOL, PG_GETARG_JSONB_P, PG_NARGS, PG_RETURN_POINTER, pushJsonbValue(), JsonbInState::result, type, JsonbValue::type, WJB_DONE, WJB_ELEM, WJB_KEY, and WJB_VALUE.

◆ jsonb_to_record()

Datum jsonb_to_record ( PG_FUNCTION_ARGS  )

Definition at line 2485 of file jsonfuncs.c.

2486{
2487 return populate_record_worker(fcinfo, "jsonb_to_record",
2488 false, false, NULL);
2489}

References fb(), and populate_record_worker().

◆ jsonb_to_recordset()

Datum jsonb_to_recordset ( PG_FUNCTION_ARGS  )

Definition at line 3978 of file jsonfuncs.c.

3979{
3980 return populate_recordset_worker(fcinfo, "jsonb_to_recordset",
3981 false, false);
3982}

References populate_recordset_worker().

◆ JsonbValueAsText()

static text * JsonbValueAsText ( JsonbValue v)
static

Definition at line 1802 of file jsonfuncs.c.

1803{
1804 switch (v->type)
1805 {
1806 case jbvNull:
1807 return NULL;
1808
1809 case jbvBool:
1810 return v->val.boolean ?
1811 cstring_to_text_with_len("true", 4) :
1812 cstring_to_text_with_len("false", 5);
1813
1814 case jbvString:
1815 return cstring_to_text_with_len(v->val.string.val,
1816 v->val.string.len);
1817
1818 case jbvNumeric:
1819 {
1820 Datum cstr;
1821
1823 PointerGetDatum(v->val.numeric));
1824
1826 }
1827
1828 case jbvBinary:
1829 {
1831
1833 (void) JsonbToCString(&jtext, v->val.binary.data,
1834 v->val.binary.len);
1835
1836 return cstring_to_text_with_len(jtext.data, jtext.len);
1837 }
1838
1839 default:
1840 elog(ERROR, "unrecognized jsonb type: %d", (int) v->type);
1841 return NULL;
1842 }
1843}

References cstring_to_text(), cstring_to_text_with_len(), DatumGetCString(), DirectFunctionCall1, elog, ERROR, fb(), initStringInfo(), jbvBinary, jbvBool, jbvNull, jbvNumeric, jbvString, JsonbToCString(), numeric_out(), PointerGetDatum(), JsonbValue::type, and JsonbValue::val.

Referenced by each_worker_jsonb(), elements_worker_jsonb(), jsonb_array_element_text(), jsonb_get_element(), and jsonb_object_field_text().

◆ JsValueToJsObject()

static bool JsValueToJsObject ( JsValue jsv,
JsObject jso,
Node escontext 
)
static

Definition at line 2979 of file jsonfuncs.c.

2980{
2981 jso->is_json = jsv->is_json;
2982
2983 if (jsv->is_json)
2984 {
2985 /* convert plain-text json into a hash table */
2986 jso->val.json_hash =
2987 get_json_object_as_hash(jsv->val.json.str,
2988 jsv->val.json.len >= 0
2989 ? jsv->val.json.len
2990 : strlen(jsv->val.json.str),
2991 "populate_composite",
2992 escontext);
2993 Assert(jso->val.json_hash != NULL || SOFT_ERROR_OCCURRED(escontext));
2994 }
2995 else
2996 {
2997 JsonbValue *jbv = jsv->val.jsonb;
2998
2999 if (jbv->type == jbvBinary &&
3000 JsonContainerIsObject(jbv->val.binary.data))
3001 {
3002 jso->val.jsonb_cont = jbv->val.binary.data;
3003 }
3004 else
3005 {
3006 bool is_scalar;
3007
3009 (jbv->type == jbvBinary &&
3010 JsonContainerIsScalar(jbv->val.binary.data));
3011 errsave(escontext,
3013 is_scalar
3014 ? errmsg("cannot call %s on a scalar",
3015 "populate_composite")
3016 : errmsg("cannot call %s on an array",
3017 "populate_composite")));
3018 }
3019 }
3020
3021 return !SOFT_ERROR_OCCURRED(escontext);
3022}

References Assert, errcode(), errmsg(), errsave, fb(), get_json_object_as_hash(), IsAJsonbScalar, jbvBinary, JsonContainerIsObject, JsonContainerIsScalar, SOFT_ERROR_OCCURRED, and JsonbValue::val.

Referenced by populate_composite().

◆ makeJsonLexContext()

JsonLexContext * makeJsonLexContext ( JsonLexContext lex,
text json,
bool  need_escapes 
)

Definition at line 540 of file jsonfuncs.c.

541{
542 /*
543 * Most callers pass a detoasted datum, but it's not clear that they all
544 * do. pg_detoast_datum_packed() is cheap insurance.
545 */
546 json = pg_detoast_datum_packed(json);
547
549 VARDATA_ANY(json),
550 VARSIZE_ANY_EXHDR(json),
552 need_escapes);
553}

References GetDatabaseEncoding(), makeJsonLexContextCstringLen(), pg_detoast_datum_packed(), VARDATA_ANY(), and VARSIZE_ANY_EXHDR().

Referenced by datum_to_jsonb_internal(), each_worker(), elements_worker(), get_worker(), iterate_json_values(), json_array_length(), json_get_first_token(), json_in(), json_object_keys(), json_strip_nulls(), json_typeof(), json_validate(), populate_recordset_worker(), and transform_json_string_values().

◆ okeys_array_start()

static JsonParseErrorType okeys_array_start ( void state)
static

Definition at line 809 of file jsonfuncs.c.

810{
812
813 /* top level must be a json object */
814 if (_state->lex->lex_level == 0)
817 errmsg("cannot call %s on an array",
818 "json_object_keys")));
819
820 return JSON_SUCCESS;
821}

References ereport, errcode(), errmsg(), ERROR, fb(), and JSON_SUCCESS.

Referenced by json_object_keys().

◆ okeys_object_field_start()

static JsonParseErrorType okeys_object_field_start ( void state,
char fname,
bool  isnull 
)
static

Definition at line 786 of file jsonfuncs.c.

787{
789
790 /* only collecting keys for the top level object */
791 if (_state->lex->lex_level != 1)
792 return JSON_SUCCESS;
793
794 /* enlarge result array if necessary */
795 if (_state->result_count >= _state->result_size)
796 {
797 _state->result_size *= 2;
798 _state->result = (char **)
799 repalloc(_state->result, sizeof(char *) * _state->result_size);
800 }
801
802 /* save a copy of the field name */
803 _state->result[_state->result_count++] = pstrdup(fname);
804
805 return JSON_SUCCESS;
806}

References fb(), JSON_SUCCESS, pstrdup(), and repalloc().

Referenced by json_object_keys().

◆ okeys_scalar()

static JsonParseErrorType okeys_scalar ( void state,
char token,
JsonTokenType  tokentype 
)
static

Definition at line 824 of file jsonfuncs.c.

825{
827
828 /* top level must be a json object */
829 if (_state->lex->lex_level == 0)
832 errmsg("cannot call %s on a scalar",
833 "json_object_keys")));
834
835 return JSON_SUCCESS;
836}

References ereport, errcode(), errmsg(), ERROR, fb(), and JSON_SUCCESS.

Referenced by json_object_keys().

◆ parse_jsonb_index_flags()

uint32 parse_jsonb_index_flags ( Jsonb jb)

Definition at line 5559 of file jsonfuncs.c.

5560{
5562 JsonbValue v;
5564 uint32 flags = 0;
5565
5566 it = JsonbIteratorInit(&jb->root);
5567
5568 type = JsonbIteratorNext(&it, &v, false);
5569
5570 /*
5571 * We iterate over array (scalar internally is represented as array, so,
5572 * we will accept it too) to check all its elements. Flag names are
5573 * chosen the same as jsonb_typeof uses.
5574 */
5575 if (type != WJB_BEGIN_ARRAY)
5577 errmsg("wrong flag type, only arrays and scalars are allowed")));
5578
5579 while ((type = JsonbIteratorNext(&it, &v, false)) == WJB_ELEM)
5580 {
5581 if (v.type != jbvString)
5582 ereport(ERROR,
5584 errmsg("flag array element is not a string"),
5585 errhint("Possible values are: \"string\", \"numeric\", \"boolean\", \"key\", and \"all\".")));
5586
5587 if (v.val.string.len == 3 &&
5588 pg_strncasecmp(v.val.string.val, "all", 3) == 0)
5589 flags |= jtiAll;
5590 else if (v.val.string.len == 3 &&
5591 pg_strncasecmp(v.val.string.val, "key", 3) == 0)
5592 flags |= jtiKey;
5593 else if (v.val.string.len == 6 &&
5594 pg_strncasecmp(v.val.string.val, "string", 6) == 0)
5595 flags |= jtiString;
5596 else if (v.val.string.len == 7 &&
5597 pg_strncasecmp(v.val.string.val, "numeric", 7) == 0)
5598 flags |= jtiNumeric;
5599 else if (v.val.string.len == 7 &&
5600 pg_strncasecmp(v.val.string.val, "boolean", 7) == 0)
5601 flags |= jtiBool;
5602 else
5603 ereport(ERROR,
5605 errmsg("wrong flag in flag array: \"%s\"",
5606 pnstrdup(v.val.string.val, v.val.string.len)),
5607 errhint("Possible values are: \"string\", \"numeric\", \"boolean\", \"key\", and \"all\".")));
5608 }
5609
5610 /* expect end of array now */
5611 if (type != WJB_END_ARRAY)
5612 elog(ERROR, "unexpected end of flag array");
5613
5614 /* get final WJB_DONE and free iterator */
5615 type = JsonbIteratorNext(&it, &v, false);
5616 if (type != WJB_DONE)
5617 elog(ERROR, "unexpected end of flag array");
5618
5619 return flags;
5620}

References elog, ereport, errcode(), errhint(), errmsg(), ERROR, fb(), jbvString, JsonbIteratorInit(), JsonbIteratorNext(), jtiAll, jtiBool, jtiKey, jtiNumeric, jtiString, pg_strncasecmp(), pnstrdup(), type, JsonbValue::type, JsonbValue::val, WJB_BEGIN_ARRAY, WJB_DONE, WJB_ELEM, and WJB_END_ARRAY.

Referenced by json_to_tsvector(), json_to_tsvector_byid(), jsonb_to_tsvector(), and jsonb_to_tsvector_byid().

◆ pg_parse_json_or_errsave()

bool pg_parse_json_or_errsave ( JsonLexContext lex,
const JsonSemAction sem,
Node escontext 
)

Definition at line 519 of file jsonfuncs.c.

521{
522 JsonParseErrorType result;
523
524 result = pg_parse_json(lex, sem);
525 if (result != JSON_SUCCESS)
526 {
527 json_errsave_error(result, lex, escontext);
528 return false;
529 }
530 return true;
531}

References json_errsave_error(), JSON_SUCCESS, pg_parse_json(), and sem.

Referenced by get_json_object_as_hash(), json_in(), jsonb_from_cstring(), and populate_array_json().

◆ populate_array()

static Datum populate_array ( ArrayIOData aio,
const char colname,
MemoryContext  mcxt,
JsValue jsv,
bool isnull,
Node escontext 
)
static

Definition at line 2912 of file jsonfuncs.c.

2918{
2920 Datum result;
2921 int *lbs;
2922 int i;
2923
2924 ctx.aio = aio;
2925 ctx.mcxt = mcxt;
2927 ctx.astate = initArrayResult(aio->element_type, ctx.acxt, true);
2928 ctx.colname = colname;
2929 ctx.ndims = 0; /* unknown yet */
2930 ctx.dims = NULL;
2931 ctx.sizes = NULL;
2932 ctx.escontext = escontext;
2933
2934 if (jsv->is_json)
2935 {
2936 /* Return null if an error was found. */
2937 if (!populate_array_json(&ctx, jsv->val.json.str,
2938 jsv->val.json.len >= 0 ? jsv->val.json.len
2939 : strlen(jsv->val.json.str)))
2940 {
2941 *isnull = true;
2942 return (Datum) 0;
2943 }
2944 }
2945 else
2946 {
2947 /* Return null if an error was found. */
2948 if (!populate_array_dim_jsonb(&ctx, jsv->val.jsonb, 1))
2949 {
2950 *isnull = true;
2951 return (Datum) 0;
2952 }
2953 ctx.dims[0] = ctx.sizes[0];
2954 }
2955
2956 Assert(ctx.ndims > 0);
2957
2958 lbs = palloc_array(int, ctx.ndims);
2959
2960 for (i = 0; i < ctx.ndims; i++)
2961 lbs[i] = 1;
2962
2963 result = makeMdArrayResult(ctx.astate, ctx.ndims, ctx.dims, lbs,
2964 ctx.acxt, true);
2965
2966 pfree(ctx.dims);
2967 pfree(ctx.sizes);
2968 pfree(lbs);
2969
2970 *isnull = false;
2971 return result;
2972}

References PopulateArrayContext::acxt, PopulateArrayContext::aio, Assert, PopulateArrayContext::astate, PopulateArrayContext::colname, CurrentMemoryContext, PopulateArrayContext::dims, ArrayIOData::element_type, PopulateArrayContext::escontext, fb(), i, initArrayResult(), makeMdArrayResult(), PopulateArrayContext::mcxt, PopulateArrayContext::ndims, palloc_array, pfree(), populate_array_dim_jsonb(), populate_array_json(), and PopulateArrayContext::sizes.

Referenced by populate_record_field().

◆ populate_array_array_end()

static JsonParseErrorType populate_array_array_end ( void _state)
static

Definition at line 2665 of file jsonfuncs.c.

2666{
2668 PopulateArrayContext *ctx = state->ctx;
2669 int ndim = state->lex->lex_level;
2670
2671 if (ctx->ndims <= 0)
2672 {
2673 if (!populate_array_assign_ndims(ctx, ndim + 1))
2675 }
2676
2677 if (ndim < ctx->ndims)
2678 {
2679 /* Report if an error occurred. */
2680 if (!populate_array_check_dimension(ctx, ndim))
2682 }
2683
2684 return JSON_SUCCESS;
2685}

References fb(), JSON_SEM_ACTION_FAILED, JSON_SUCCESS, PopulateArrayContext::ndims, populate_array_assign_ndims(), and populate_array_check_dimension().

Referenced by populate_array_json().

◆ populate_array_assign_ndims()

static bool populate_array_assign_ndims ( PopulateArrayContext ctx,
int  ndims 
)
static

Definition at line 2557 of file jsonfuncs.c.

2558{
2559 int i;
2560
2561 Assert(ctx->ndims <= 0);
2562
2563 if (ndims <= 0)
2564 {
2566 /* Getting here means the error was reported softly. */
2568 return false;
2569 }
2570
2571 ctx->ndims = ndims;
2572 ctx->dims = palloc_array(int, ndims);
2573 ctx->sizes = palloc0_array(int, ndims);
2574
2575 for (i = 0; i < ndims; i++)
2576 ctx->dims[i] = -1; /* dimensions are unknown yet */
2577
2578 return true;
2579}

References Assert, PopulateArrayContext::dims, PopulateArrayContext::escontext, i, PopulateArrayContext::ndims, palloc0_array, palloc_array, populate_array_report_expected_array(), PopulateArrayContext::sizes, and SOFT_ERROR_OCCURRED.

Referenced by populate_array_array_end(), populate_array_dim_jsonb(), populate_array_object_start(), and populate_array_scalar().

◆ populate_array_check_dimension()

static bool populate_array_check_dimension ( PopulateArrayContext ctx,
int  ndim 
)
static

Definition at line 2587 of file jsonfuncs.c.

2588{
2589 int dim = ctx->sizes[ndim]; /* current dimension counter */
2590
2591 if (ctx->dims[ndim] == -1)
2592 ctx->dims[ndim] = dim; /* assign dimension if not yet known */
2593 else if (ctx->dims[ndim] != dim)
2594 ereturn(ctx->escontext, false,
2596 errmsg("malformed JSON array"),
2597 errdetail("Multidimensional arrays must have "
2598 "sub-arrays with matching dimensions.")));
2599
2600 /* reset the current array dimension size counter */
2601 ctx->sizes[ndim] = 0;
2602
2603 /* increment the parent dimension counter if it is a nested sub-array */
2604 if (ndim > 0)
2605 ctx->sizes[ndim - 1]++;
2606
2607 return true;
2608}

References PopulateArrayContext::dims, ereturn, errcode(), errdetail(), errmsg(), PopulateArrayContext::escontext, fb(), and PopulateArrayContext::sizes.

Referenced by populate_array_array_end(), and populate_array_dim_jsonb().

◆ populate_array_dim_jsonb()

static bool populate_array_dim_jsonb ( PopulateArrayContext ctx,
JsonbValue jbv,
int  ndim 
)
static

Definition at line 2822 of file jsonfuncs.c.

2825{
2826 JsonbContainer *jbc = jbv->val.binary.data;
2830 JsValue jsv;
2831
2833
2834 /* Even scalars can end up here thanks to ExecEvalJsonCoercion(). */
2835 if (jbv->type != jbvBinary || !JsonContainerIsArray(jbc) ||
2837 {
2839 /* Getting here means the error was reported softly. */
2841 return false;
2842 }
2843
2844 it = JsonbIteratorInit(jbc);
2845
2846 tok = JsonbIteratorNext(&it, &val, true);
2848
2849 tok = JsonbIteratorNext(&it, &val, true);
2850
2851 /*
2852 * If the number of dimensions is not yet known and we have found end of
2853 * the array, or the first child element is not an array, then assign the
2854 * number of dimensions now.
2855 */
2856 if (ctx->ndims <= 0 &&
2857 (tok == WJB_END_ARRAY ||
2858 (tok == WJB_ELEM &&
2859 (val.type != jbvBinary ||
2860 !JsonContainerIsArray(val.val.binary.data)))))
2861 {
2862 if (!populate_array_assign_ndims(ctx, ndim))
2863 return false;
2864 }
2865
2866 jsv.is_json = false;
2867 jsv.val.jsonb = &val;
2868
2869 /* process all the array elements */
2870 while (tok == WJB_ELEM)
2871 {
2872 /*
2873 * Recurse only if the dimensions of dimensions is still unknown or if
2874 * it is not the innermost dimension.
2875 */
2876 if (ctx->ndims > 0 && ndim >= ctx->ndims)
2877 {
2878 if (!populate_array_element(ctx, ndim, &jsv))
2879 return false;
2880 }
2881 else
2882 {
2883 /* populate child sub-array */
2884 if (!populate_array_dim_jsonb(ctx, &val, ndim + 1))
2885 return false;
2886
2887 /* number of dimensions should be already known */
2888 Assert(ctx->ndims > 0 && ctx->dims);
2889
2890 if (!populate_array_check_dimension(ctx, ndim))
2891 return false;
2892 }
2893
2894 tok = JsonbIteratorNext(&it, &val, true);
2895 }
2896
2898
2899 /* free iterator, iterating until WJB_DONE */
2900 tok = JsonbIteratorNext(&it, &val, true);
2901 Assert(tok == WJB_DONE && !it);
2902
2903 return true;
2904}

References Assert, check_stack_depth(), PopulateArrayContext::dims, PopulateArrayContext::escontext, fb(), jbvBinary, JsonbIteratorInit(), JsonbIteratorNext(), JsonContainerIsArray, JsonContainerIsScalar, PopulateArrayContext::ndims, populate_array_assign_ndims(), populate_array_check_dimension(), populate_array_dim_jsonb(), populate_array_element(), populate_array_report_expected_array(), SOFT_ERROR_OCCURRED, val, WJB_BEGIN_ARRAY, WJB_DONE, WJB_ELEM, and WJB_END_ARRAY.

Referenced by populate_array(), and populate_array_dim_jsonb().

◆ populate_array_element()

static bool populate_array_element ( PopulateArrayContext ctx,
int  ndim,
JsValue jsv 
)
static

Definition at line 2615 of file jsonfuncs.c.

2616{
2617 Datum element;
2618 bool element_isnull;
2619
2620 /* populate the array element */
2622 ctx->aio->element_type,
2623 ctx->aio->element_typmod,
2624 NULL, ctx->mcxt, PointerGetDatum(NULL),
2626 false);
2627 /* Nothing to do on an error. */
2629 return false;
2630
2632 ctx->aio->element_type, ctx->acxt);
2633
2634 Assert(ndim > 0);
2635 ctx->sizes[ndim - 1]++; /* increment current dimension counter */
2636
2637 return true;
2638}

References accumArrayResult(), PopulateArrayContext::acxt, PopulateArrayContext::aio, Assert, PopulateArrayContext::astate, element(), ArrayIOData::element_info, ArrayIOData::element_type, ArrayIOData::element_typmod, PopulateArrayContext::escontext, fb(), PopulateArrayContext::mcxt, PointerGetDatum(), populate_record_field(), PopulateArrayContext::sizes, and SOFT_ERROR_OCCURRED.

Referenced by populate_array_dim_jsonb(), and populate_array_element_end().

◆ populate_array_element_end()

static JsonParseErrorType populate_array_element_end ( void _state,
bool  isnull 
)
static

Definition at line 2707 of file jsonfuncs.c.

2708{
2710 PopulateArrayContext *ctx = state->ctx;
2711 int ndim = state->lex->lex_level;
2712
2713 Assert(ctx->ndims > 0);
2714
2715 if (ndim == ctx->ndims)
2716 {
2717 JsValue jsv;
2718
2719 jsv.is_json = true;
2720 jsv.val.json.type = state->element_type;
2721
2722 if (isnull)
2723 {
2724 Assert(jsv.val.json.type == JSON_TOKEN_NULL);
2725 jsv.val.json.str = NULL;
2726 jsv.val.json.len = 0;
2727 }
2728 else if (state->element_scalar)
2729 {
2730 jsv.val.json.str = state->element_scalar;
2731 jsv.val.json.len = -1; /* null-terminated */
2732 }
2733 else
2734 {
2735 jsv.val.json.str = state->element_start;
2736 jsv.val.json.len = (state->lex->prev_token_terminator -
2737 state->element_start) * sizeof(char);
2738 }
2739
2740 /* Report if an error occurred. */
2741 if (!populate_array_element(ctx, ndim, &jsv))
2743 }
2744
2745 return JSON_SUCCESS;
2746}

References Assert, fb(), JsValue::is_json, JSON_SEM_ACTION_FAILED, JSON_SUCCESS, JSON_TOKEN_NULL, PopulateArrayContext::ndims, and populate_array_element().

Referenced by populate_array_json().

◆ populate_array_element_start()

static JsonParseErrorType populate_array_element_start ( void _state,
bool  isnull 
)
static

Definition at line 2689 of file jsonfuncs.c.

2690{
2692 int ndim = state->lex->lex_level;
2693
2694 if (state->ctx->ndims <= 0 || ndim == state->ctx->ndims)
2695 {
2696 /* remember current array element start */
2697 state->element_start = state->lex->token_start;
2698 state->element_type = state->lex->token_type;
2699 state->element_scalar = NULL;
2700 }
2701
2702 return JSON_SUCCESS;
2703}

References fb(), and JSON_SUCCESS.

Referenced by populate_array_json().

◆ populate_array_json()

static bool populate_array_json ( PopulateArrayContext ctx,
const char json,
int  len 
)
static

◆ populate_array_object_start()

static JsonParseErrorType populate_array_object_start ( void _state)
static

Definition at line 2642 of file jsonfuncs.c.

2643{
2645 int ndim = state->lex->lex_level;
2646
2647 if (state->ctx->ndims <= 0)
2648 {
2649 if (!populate_array_assign_ndims(state->ctx, ndim))
2651 }
2652 else if (ndim < state->ctx->ndims)
2653 {
2655 /* Getting here means the error was reported softly. */
2656 Assert(SOFT_ERROR_OCCURRED(state->ctx->escontext));
2658 }
2659
2660 return JSON_SUCCESS;
2661}

References Assert, fb(), JSON_SEM_ACTION_FAILED, JSON_SUCCESS, populate_array_assign_ndims(), populate_array_report_expected_array(), and SOFT_ERROR_OCCURRED.

Referenced by populate_array_json().

◆ populate_array_report_expected_array()

static void populate_array_report_expected_array ( PopulateArrayContext ctx,
int  ndim 
)
static

Definition at line 2507 of file jsonfuncs.c.

2508{
2509 if (ndim <= 0)
2510 {
2511 if (ctx->colname)
2512 errsave(ctx->escontext,
2514 errmsg("expected JSON array"),
2515 errhint("See the value of key \"%s\".", ctx->colname)));
2516 else
2517 errsave(ctx->escontext,
2519 errmsg("expected JSON array")));
2520 return;
2521 }
2522 else
2523 {
2524 StringInfoData indices;
2525 int i;
2526
2527 initStringInfo(&indices);
2528
2529 Assert(ctx->ndims > 0 && ndim < ctx->ndims);
2530
2531 for (i = 0; i < ndim; i++)
2532 appendStringInfo(&indices, "[%d]", ctx->sizes[i]);
2533
2534 if (ctx->colname)
2535 errsave(ctx->escontext,
2537 errmsg("expected JSON array"),
2538 errhint("See the array element %s of key \"%s\".",
2539 indices.data, ctx->colname)));
2540 else
2541 errsave(ctx->escontext,
2543 errmsg("expected JSON array"),
2544 errhint("See the array element %s.",
2545 indices.data)));
2546 return;
2547 }
2548}

References appendStringInfo(), Assert, PopulateArrayContext::colname, StringInfoData::data, errcode(), errhint(), errmsg(), errsave, PopulateArrayContext::escontext, fb(), i, initStringInfo(), PopulateArrayContext::ndims, and PopulateArrayContext::sizes.

Referenced by populate_array_assign_ndims(), populate_array_dim_jsonb(), populate_array_object_start(), and populate_array_scalar().

◆ populate_array_scalar()

static JsonParseErrorType populate_array_scalar ( void _state,
char token,
JsonTokenType  tokentype 
)
static

Definition at line 2750 of file jsonfuncs.c.

2751{
2753 PopulateArrayContext *ctx = state->ctx;
2754 int ndim = state->lex->lex_level;
2755
2756 if (ctx->ndims <= 0)
2757 {
2758 if (!populate_array_assign_ndims(ctx, ndim))
2760 }
2761 else if (ndim < ctx->ndims)
2762 {
2764 /* Getting here means the error was reported softly. */
2767 }
2768
2769 if (ndim == ctx->ndims)
2770 {
2771 /* remember the scalar element token */
2772 state->element_scalar = token;
2773 /* element_type must already be set in populate_array_element_start() */
2774 Assert(state->element_type == tokentype);
2775 }
2776
2777 return JSON_SUCCESS;
2778}

References Assert, PopulateArrayContext::escontext, fb(), JSON_SEM_ACTION_FAILED, JSON_SUCCESS, PopulateArrayContext::ndims, populate_array_assign_ndims(), populate_array_report_expected_array(), SOFT_ERROR_OCCURRED, and token.

Referenced by populate_array_json().

◆ populate_composite()

static Datum populate_composite ( CompositeIOData io,
Oid  typid,
const char colname,
MemoryContext  mcxt,
HeapTupleHeader  defaultval,
JsValue jsv,
bool isnull,
Node escontext 
)
static

Definition at line 3055 of file jsonfuncs.c.

3063{
3064 Datum result;
3065
3066 /* acquire/update cached tuple descriptor */
3067 update_cached_tupdesc(io, mcxt);
3068
3069 if (*isnull)
3070 result = (Datum) 0;
3071 else
3072 {
3073 HeapTupleHeader tuple;
3074 JsObject jso;
3075
3076 /* prepare input value */
3077 if (!JsValueToJsObject(jsv, &jso, escontext))
3078 {
3079 *isnull = true;
3080 return (Datum) 0;
3081 }
3082
3083 /* populate resulting record tuple */
3084 tuple = populate_record(io->tupdesc, &io->record_io,
3085 defaultval, mcxt, &jso, escontext);
3086
3087 if (SOFT_ERROR_OCCURRED(escontext))
3088 {
3089 *isnull = true;
3090 return (Datum) 0;
3091 }
3092 result = HeapTupleHeaderGetDatum(tuple);
3093
3094 JsObjectFree(&jso);
3095 }
3096
3097 /*
3098 * If it's domain over composite, check domain constraints. (This should
3099 * probably get refactored so that we can see the TYPECAT value, but for
3100 * now, we can tell by comparing typid to base_typid.)
3101 */
3102 if (typid != io->base_typid && typid != RECORDOID)
3103 {
3104 if (!domain_check_safe(result, *isnull, typid, &io->domain_info, mcxt,
3105 escontext))
3106 {
3107 *isnull = true;
3108 return (Datum) 0;
3109 }
3110 }
3111
3112 return result;
3113}

References CompositeIOData::base_typid, domain_check_safe(), CompositeIOData::domain_info, fb(), HeapTupleHeaderGetDatum(), JsObjectFree, JsValueToJsObject(), populate_record(), CompositeIOData::record_io, SOFT_ERROR_OCCURRED, CompositeIOData::tupdesc, and update_cached_tupdesc().

Referenced by populate_record_field(), and populate_record_worker().

◆ populate_domain()

static Datum populate_domain ( DomainIOData io,
Oid  typid,
const char colname,
MemoryContext  mcxt,
JsValue jsv,
bool isnull,
Node escontext,
bool  omit_quotes 
)
static

Definition at line 3214 of file jsonfuncs.c.

3222{
3223 Datum res;
3224
3225 if (*isnull)
3226 res = (Datum) 0;
3227 else
3228 {
3230 io->base_typid, io->base_typmod,
3231 colname, mcxt, PointerGetDatum(NULL),
3232 jsv, isnull, escontext, omit_quotes);
3233 Assert(!*isnull || SOFT_ERROR_OCCURRED(escontext));
3234 }
3235
3236 if (!domain_check_safe(res, *isnull, typid, &io->domain_info, mcxt,
3237 escontext))
3238 {
3239 *isnull = true;
3240 return (Datum) 0;
3241 }
3242
3243 return res;
3244}

References Assert, DomainIOData::base_io, DomainIOData::base_typid, DomainIOData::base_typmod, domain_check_safe(), DomainIOData::domain_info, fb(), PointerGetDatum(), populate_record_field(), and SOFT_ERROR_OCCURRED.

Referenced by populate_record_field().

◆ populate_record()

static HeapTupleHeader populate_record ( TupleDesc  tupdesc,
RecordIOData **  record_p,
HeapTupleHeader  defaultval,
MemoryContext  mcxt,
JsObject obj,
Node escontext 
)
static

Definition at line 3517 of file jsonfuncs.c.

3523{
3524 RecordIOData *record = *record_p;
3525 Datum *values;
3526 bool *nulls;
3527 HeapTuple res;
3528 int ncolumns = tupdesc->natts;
3529 int i;
3530
3531 /*
3532 * if the input json is empty, we can only skip the rest if we were passed
3533 * in a non-null record, since otherwise there may be issues with domain
3534 * nulls.
3535 */
3536 if (defaultval && JsObjectIsEmpty(obj))
3537 return defaultval;
3538
3539 /* (re)allocate metadata cache */
3540 if (record == NULL ||
3541 record->ncolumns != ncolumns)
3542 *record_p = record = allocate_record_info(mcxt, ncolumns);
3543
3544 /* invalidate metadata cache if the record type has changed */
3545 if (record->record_type != tupdesc->tdtypeid ||
3546 record->record_typmod != tupdesc->tdtypmod)
3547 {
3548 MemSet(record, 0, offsetof(RecordIOData, columns) +
3549 ncolumns * sizeof(ColumnIOData));
3550 record->record_type = tupdesc->tdtypeid;
3551 record->record_typmod = tupdesc->tdtypmod;
3552 record->ncolumns = ncolumns;
3553 }
3554
3555 values = (Datum *) palloc(ncolumns * sizeof(Datum));
3556 nulls = (bool *) palloc(ncolumns * sizeof(bool));
3557
3558 if (defaultval)
3559 {
3560 HeapTupleData tuple;
3561
3562 /* Build a temporary HeapTuple control structure */
3564 ItemPointerSetInvalid(&(tuple.t_self));
3565 tuple.t_tableOid = InvalidOid;
3566 tuple.t_data = defaultval;
3567
3568 /* Break down the tuple into fields */
3569 heap_deform_tuple(&tuple, tupdesc, values, nulls);
3570 }
3571 else
3572 {
3573 for (i = 0; i < ncolumns; ++i)
3574 {
3575 values[i] = (Datum) 0;
3576 nulls[i] = true;
3577 }
3578 }
3579
3580 for (i = 0; i < ncolumns; ++i)
3581 {
3583 char *colname = NameStr(att->attname);
3584 JsValue field = {0};
3585 bool found;
3586
3587 /* Ignore dropped columns in datatype */
3588 if (att->attisdropped)
3589 {
3590 nulls[i] = true;
3591 continue;
3592 }
3593
3594 found = JsObjectGetField(obj, colname, &field);
3595
3596 /*
3597 * we can't just skip here if the key wasn't found since we might have
3598 * a domain to deal with. If we were passed in a non-null record
3599 * datum, we assume that the existing values are valid (if they're
3600 * not, then it's not our fault), but if we were passed in a null,
3601 * then every field which we don't populate needs to be run through
3602 * the input function just in case it's a domain type.
3603 */
3604 if (defaultval && !found)
3605 continue;
3606
3607 values[i] = populate_record_field(&record->columns[i],
3608 att->atttypid,
3609 att->atttypmod,
3610 colname,
3611 mcxt,
3612 nulls[i] ? (Datum) 0 : values[i],
3613 &field,
3614 &nulls[i],
3615 escontext,
3616 false);
3617 }
3618
3619 res = heap_form_tuple(tupdesc, values, nulls);
3620
3621 pfree(values);
3622 pfree(nulls);
3623
3624 return res->t_data;
3625}

References allocate_record_info(), RecordIOData::columns, fb(), heap_deform_tuple(), heap_form_tuple(), HeapTupleHeaderGetDatumLength(), i, InvalidOid, ItemPointerSetInvalid(), JsObjectGetField(), JsObjectIsEmpty, MemSet, NameStr, TupleDescData::natts, RecordIOData::ncolumns, palloc(), pfree(), populate_record_field(), RecordIOData::record_type, RecordIOData::record_typmod, HeapTupleData::t_data, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, TupleDescData::tdtypeid, TupleDescData::tdtypmod, TupleDescAttr(), and values.

Referenced by populate_composite(), and populate_recordset_record().

◆ populate_record_field()

static Datum populate_record_field ( ColumnIOData col,
Oid  typid,
int32  typmod,
const char colname,
MemoryContext  mcxt,
Datum  defaultval,
JsValue jsv,
bool isnull,
Node escontext,
bool  omit_scalar_quotes 
)
static

Definition at line 3403 of file jsonfuncs.c.

3413{
3414 TypeCat typcat;
3415
3417
3418 /*
3419 * Prepare column metadata cache for the given type. Force lookup of the
3420 * scalar_io data so that the json string hack below will work.
3421 */
3422 if (col->typid != typid || col->typmod != typmod)
3423 prepare_column_cache(col, typid, typmod, mcxt, true);
3424
3425 *isnull = JsValueIsNull(jsv);
3426
3427 typcat = col->typcat;
3428
3429 /* try to convert json string to a non-scalar type through input function */
3430 if (JsValueIsString(jsv) &&
3431 (typcat == TYPECAT_ARRAY ||
3432 typcat == TYPECAT_COMPOSITE ||
3433 typcat == TYPECAT_COMPOSITE_DOMAIN))
3434 typcat = TYPECAT_SCALAR;
3435
3436 /* we must perform domain checks for NULLs, otherwise exit immediately */
3437 if (*isnull &&
3438 typcat != TYPECAT_DOMAIN &&
3439 typcat != TYPECAT_COMPOSITE_DOMAIN)
3440 return (Datum) 0;
3441
3442 switch (typcat)
3443 {
3444 case TYPECAT_SCALAR:
3445 return populate_scalar(&col->scalar_io, typid, typmod, jsv,
3446 isnull, escontext, omit_scalar_quotes);
3447
3448 case TYPECAT_ARRAY:
3449 return populate_array(&col->io.array, colname, mcxt, jsv,
3450 isnull, escontext);
3451
3452 case TYPECAT_COMPOSITE:
3454 return populate_composite(&col->io.composite, typid,
3455 colname, mcxt,
3458 : NULL,
3459 jsv, isnull,
3460 escontext);
3461
3462 case TYPECAT_DOMAIN:
3463 return populate_domain(&col->io.domain, typid, colname, mcxt,
3464 jsv, isnull, escontext, omit_scalar_quotes);
3465
3466 default:
3467 elog(ERROR, "unrecognized type category '%c'", typcat);
3468 return (Datum) 0;
3469 }
3470}

References check_stack_depth(), DatumGetHeapTupleHeader, DatumGetPointer(), elog, ERROR, fb(), JsValueIsNull, JsValueIsString, populate_array(), populate_composite(), populate_domain(), populate_scalar(), prepare_column_cache(), TYPECAT_ARRAY, TYPECAT_COMPOSITE, TYPECAT_COMPOSITE_DOMAIN, TYPECAT_DOMAIN, and TYPECAT_SCALAR.

Referenced by json_populate_type(), populate_array_element(), populate_domain(), and populate_record().

◆ populate_record_worker()

static Datum populate_record_worker ( FunctionCallInfo  fcinfo,
const char funcname,
bool  is_json,
bool  have_record_arg,
Node escontext 
)
static

Definition at line 3696 of file jsonfuncs.c.

3699{
3700 int json_arg_num = have_record_arg ? 1 : 0;
3701 JsValue jsv = {0};
3702 HeapTupleHeader rec;
3704 bool isnull;
3707 PopulateRecordCache *cache = fcinfo->flinfo->fn_extra;
3708
3709 /*
3710 * If first time through, identify input/result record type. Note that
3711 * this stanza looks only at fcinfo context, which can't change during the
3712 * query; so we may not be able to fully resolve a RECORD input type yet.
3713 */
3714 if (!cache)
3715 {
3716 fcinfo->flinfo->fn_extra = cache =
3717 MemoryContextAllocZero(fnmcxt, sizeof(*cache));
3718 cache->fn_mcxt = fnmcxt;
3719
3720 if (have_record_arg)
3722 else
3723 get_record_type_from_query(fcinfo, funcname, cache);
3724 }
3725
3726 /* Collect record arg if we have one */
3727 if (!have_record_arg)
3728 rec = NULL; /* it's json{b}_to_record() */
3729 else if (!PG_ARGISNULL(0))
3730 {
3732
3733 /*
3734 * When declared arg type is RECORD, identify actual record type from
3735 * the tuple itself.
3736 */
3737 if (cache->argtype == RECORDOID)
3738 {
3741 }
3742 }
3743 else
3744 {
3745 rec = NULL;
3746
3747 /*
3748 * When declared arg type is RECORD, identify actual record type from
3749 * calling query, or fail if we can't.
3750 */
3751 if (cache->argtype == RECORDOID)
3752 {
3753 get_record_type_from_query(fcinfo, funcname, cache);
3754 /* This can't change argtype, which is important for next time */
3755 Assert(cache->argtype == RECORDOID);
3756 }
3757 }
3758
3759 /* If no JSON argument, just return the record (if any) unchanged */
3761 {
3762 if (rec)
3763 PG_RETURN_POINTER(rec);
3764 else
3766 }
3767
3768 jsv.is_json = is_json;
3769
3770 if (is_json)
3771 {
3773
3774 jsv.val.json.str = VARDATA_ANY(json);
3775 jsv.val.json.len = VARSIZE_ANY_EXHDR(json);
3776 jsv.val.json.type = JSON_TOKEN_INVALID; /* not used in
3777 * populate_composite() */
3778 }
3779 else
3780 {
3782
3783 jsv.val.jsonb = &jbv;
3784
3785 /* fill binary jsonb value pointing to jb */
3786 jbv.type = jbvBinary;
3787 jbv.val.binary.data = &jb->root;
3788 jbv.val.binary.len = VARSIZE(jb) - VARHDRSZ;
3789 }
3790
3791 isnull = false;
3792 rettuple = populate_composite(&cache->c.io.composite, cache->argtype,
3793 NULL, fnmcxt, rec, &jsv, &isnull,
3794 escontext);
3795 Assert(!isnull || SOFT_ERROR_OCCURRED(escontext));
3796
3798}

References PopulateRecordCache::argtype, Assert, CompositeIOData::base_typid, CompositeIOData::base_typmod, PopulateRecordCache::c, ColumnIOData::composite, fb(), FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_extra, PopulateRecordCache::fn_mcxt, FmgrInfo::fn_mcxt, funcname, get_record_type_from_argument(), get_record_type_from_query(), HeapTupleHeaderGetTypeId(), HeapTupleHeaderGetTypMod(), ColumnIOData::io, jbvBinary, JSON_TOKEN_INVALID, MemoryContextAllocZero(), PG_ARGISNULL, PG_GETARG_HEAPTUPLEHEADER, PG_GETARG_JSONB_P, PG_GETARG_TEXT_PP, PG_RETURN_DATUM, PG_RETURN_NULL, PG_RETURN_POINTER, populate_composite(), SOFT_ERROR_OCCURRED, VARDATA_ANY(), VARHDRSZ, VARSIZE(), and VARSIZE_ANY_EXHDR().

Referenced by json_populate_record(), json_to_record(), jsonb_populate_record(), jsonb_populate_record_valid(), and jsonb_to_record().

◆ populate_recordset_array_element_start()

static JsonParseErrorType populate_recordset_array_element_start ( void state,
bool  isnull 
)
static

Definition at line 4265 of file jsonfuncs.c.

4266{
4268
4269 if (_state->lex->lex_level == 1 &&
4270 _state->lex->token_type != JSON_TOKEN_OBJECT_START)
4271 ereport(ERROR,
4273 errmsg("argument of %s must be an array of objects",
4274 _state->function_name)));
4275
4276 return JSON_SUCCESS;
4277}

References ereport, errcode(), errmsg(), ERROR, fb(), JSON_SUCCESS, and JSON_TOKEN_OBJECT_START.

Referenced by populate_recordset_worker().

◆ populate_recordset_array_start()

static JsonParseErrorType populate_recordset_array_start ( void state)
static

Definition at line 4280 of file jsonfuncs.c.

4281{
4282 /* nothing to do */
4283 return JSON_SUCCESS;
4284}

References JSON_SUCCESS.

Referenced by populate_recordset_worker().

◆ populate_recordset_object_end()

static JsonParseErrorType populate_recordset_object_end ( void state)
static

Definition at line 4242 of file jsonfuncs.c.

4243{
4245 JsObject obj;
4246
4247 /* Nested objects require no special processing */
4248 if (_state->lex->lex_level > 1)
4249 return JSON_SUCCESS;
4250
4251 obj.is_json = true;
4252 obj.val.json_hash = _state->json_hash;
4253
4254 /* Otherwise, construct and return a tuple based on this level-1 object */
4256
4257 /* Done with hash for this object */
4258 hash_destroy(_state->json_hash);
4259 _state->json_hash = NULL;
4260
4261 return JSON_SUCCESS;
4262}

References fb(), hash_destroy(), JsObject::is_json, JsObject::json_hash, JSON_SUCCESS, populate_recordset_record(), and JsObject::val.

Referenced by populate_recordset_worker().

◆ populate_recordset_object_field_end()

static JsonParseErrorType populate_recordset_object_field_end ( void state,
char fname,
bool  isnull 
)
static

Definition at line 4327 of file jsonfuncs.c.

4328{
4331 bool found;
4332
4333 /*
4334 * Ignore nested fields.
4335 */
4336 if (_state->lex->lex_level > 2)
4337 return JSON_SUCCESS;
4338
4339 /*
4340 * Ignore field names >= NAMEDATALEN - they can't match a record field.
4341 * (Note: without this test, the hash code would truncate the string at
4342 * NAMEDATALEN-1, and could then match against a similarly-truncated
4343 * record field name. That would be a reasonable behavior, but this code
4344 * has previously insisted on exact equality, so we keep this behavior.)
4345 */
4346 if (strlen(fname) >= NAMEDATALEN)
4347 return JSON_SUCCESS;
4348
4349 hashentry = hash_search(_state->json_hash, fname, HASH_ENTER, &found);
4350
4351 /*
4352 * found being true indicates a duplicate. We don't do anything about
4353 * that, a later field with the same name overrides the earlier field.
4354 */
4355
4356 hashentry->type = _state->saved_token_type;
4357 Assert(isnull == (hashentry->type == JSON_TOKEN_NULL));
4358
4359 if (_state->save_json_start != NULL)
4360 {
4361 int len = _state->lex->prev_token_terminator - _state->save_json_start;
4362 char *val = palloc((len + 1) * sizeof(char));
4363
4364 memcpy(val, _state->save_json_start, len);
4365 val[len] = '\0';
4366 hashentry->val = val;
4367 }
4368 else
4369 {
4370 /* must have had a scalar instead */
4371 hashentry->val = _state->saved_scalar;
4372 }
4373
4374 return JSON_SUCCESS;
4375}

References Assert, fb(), HASH_ENTER, hash_search(), JSON_SUCCESS, JSON_TOKEN_NULL, len, NAMEDATALEN, palloc(), and val.

Referenced by populate_recordset_worker().

◆ populate_recordset_object_field_start()

static JsonParseErrorType populate_recordset_object_field_start ( void state,
char fname,
bool  isnull 
)
static

Definition at line 4304 of file jsonfuncs.c.

4305{
4307
4308 if (_state->lex->lex_level > 2)
4309 return JSON_SUCCESS;
4310
4311 _state->saved_token_type = _state->lex->token_type;
4312
4313 if (_state->lex->token_type == JSON_TOKEN_ARRAY_START ||
4314 _state->lex->token_type == JSON_TOKEN_OBJECT_START)
4315 {
4316 _state->save_json_start = _state->lex->token_start;
4317 }
4318 else
4319 {
4320 _state->save_json_start = NULL;
4321 }
4322
4323 return JSON_SUCCESS;
4324}

References fb(), JSON_SUCCESS, JSON_TOKEN_ARRAY_START, and JSON_TOKEN_OBJECT_START.

Referenced by populate_recordset_worker().

◆ populate_recordset_object_start()

static JsonParseErrorType populate_recordset_object_start ( void state)
static

Definition at line 4212 of file jsonfuncs.c.

4213{
4215 int lex_level = _state->lex->lex_level;
4216 HASHCTL ctl;
4217
4218 /* Reject object at top level: we must have an array at level 0 */
4219 if (lex_level == 0)
4220 ereport(ERROR,
4222 errmsg("cannot call %s on an object",
4223 _state->function_name)));
4224
4225 /* Nested objects require no special processing */
4226 if (lex_level > 1)
4227 return JSON_SUCCESS;
4228
4229 /* Object at level 1: set up a new hash table for this object */
4230 ctl.keysize = NAMEDATALEN;
4231 ctl.entrysize = sizeof(JsonHashEntry);
4233 _state->json_hash = hash_create("json object hashtable",
4234 100,
4235 &ctl,
4237
4238 return JSON_SUCCESS;
4239}

References ctl, CurrentMemoryContext, ereport, errcode(), errmsg(), ERROR, fb(), HASH_CONTEXT, hash_create(), HASH_ELEM, HASH_STRINGS, JSON_SUCCESS, and NAMEDATALEN.

Referenced by populate_recordset_worker().

◆ populate_recordset_record()

static void populate_recordset_record ( PopulateRecordsetState state,
JsObject obj 
)
static

Definition at line 3999 of file jsonfuncs.c.

4000{
4001 PopulateRecordCache *cache = state->cache;
4003 HeapTupleData tuple;
4004
4005 /* acquire/update cached tuple descriptor */
4006 update_cached_tupdesc(&cache->c.io.composite, cache->fn_mcxt);
4007
4008 /* replace record fields from json */
4010 &cache->c.io.composite.record_io,
4011 state->rec,
4012 cache->fn_mcxt,
4013 obj,
4014 NULL);
4015
4016 /* if it's domain over composite, check domain constraints */
4017 if (cache->c.typcat == TYPECAT_COMPOSITE_DOMAIN)
4019 cache->argtype,
4020 &cache->c.io.composite.domain_info,
4021 cache->fn_mcxt,
4022 NULL);
4023
4024 /* ok, save into tuplestore */
4026 ItemPointerSetInvalid(&(tuple.t_self));
4027 tuple.t_tableOid = InvalidOid;
4028 tuple.t_data = tuphead;
4029
4030 tuplestore_puttuple(state->tuple_store, &tuple);
4031}

References PopulateRecordCache::argtype, PopulateRecordCache::c, ColumnIOData::composite, domain_check_safe(), CompositeIOData::domain_info, fb(), PopulateRecordCache::fn_mcxt, HeapTupleHeaderGetDatum(), HeapTupleHeaderGetDatumLength(), InvalidOid, ColumnIOData::io, ItemPointerSetInvalid(), populate_record(), CompositeIOData::record_io, HeapTupleData::t_data, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, CompositeIOData::tupdesc, tuplestore_puttuple(), ColumnIOData::typcat, TYPECAT_COMPOSITE_DOMAIN, and update_cached_tupdesc().

Referenced by populate_recordset_object_end(), and populate_recordset_worker().

◆ populate_recordset_scalar()

static JsonParseErrorType populate_recordset_scalar ( void state,
char token,
JsonTokenType  tokentype 
)
static

Definition at line 4287 of file jsonfuncs.c.

4288{
4290
4291 if (_state->lex->lex_level == 0)
4292 ereport(ERROR,
4294 errmsg("cannot call %s on a scalar",
4295 _state->function_name)));
4296
4297 if (_state->lex->lex_level == 2)
4298 _state->saved_scalar = token;
4299
4300 return JSON_SUCCESS;
4301}

References ereport, errcode(), errmsg(), ERROR, fb(), JSON_SUCCESS, and token.

Referenced by populate_recordset_worker().

◆ populate_recordset_worker()

static Datum populate_recordset_worker ( FunctionCallInfo  fcinfo,
const char funcname,
bool  is_json,
bool  have_record_arg 
)
static

Definition at line 4038 of file jsonfuncs.c.

4040{
4041 int json_arg_num = have_record_arg ? 1 : 0;
4042 ReturnSetInfo *rsi;
4044 HeapTupleHeader rec;
4045 PopulateRecordCache *cache = fcinfo->flinfo->fn_extra;
4047
4048 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
4049
4050 if (!rsi || !IsA(rsi, ReturnSetInfo))
4051 ereport(ERROR,
4053 errmsg("set-valued function called in context that cannot accept a set")));
4054
4055 if (!(rsi->allowedModes & SFRM_Materialize))
4056 ereport(ERROR,
4058 errmsg("materialize mode required, but it is not allowed in this context")));
4059
4060 rsi->returnMode = SFRM_Materialize;
4061
4062 /*
4063 * If first time through, identify input/result record type. Note that
4064 * this stanza looks only at fcinfo context, which can't change during the
4065 * query; so we may not be able to fully resolve a RECORD input type yet.
4066 */
4067 if (!cache)
4068 {
4069 fcinfo->flinfo->fn_extra = cache =
4070 MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt, sizeof(*cache));
4071 cache->fn_mcxt = fcinfo->flinfo->fn_mcxt;
4072
4073 if (have_record_arg)
4075 else
4076 get_record_type_from_query(fcinfo, funcname, cache);
4077 }
4078
4079 /* Collect record arg if we have one */
4080 if (!have_record_arg)
4081 rec = NULL; /* it's json{b}_to_recordset() */
4082 else if (!PG_ARGISNULL(0))
4083 {
4085
4086 /*
4087 * When declared arg type is RECORD, identify actual record type from
4088 * the tuple itself.
4089 */
4090 if (cache->argtype == RECORDOID)
4091 {
4092 cache->c.io.composite.base_typid = HeapTupleHeaderGetTypeId(rec);
4093 cache->c.io.composite.base_typmod = HeapTupleHeaderGetTypMod(rec);
4094 }
4095 }
4096 else
4097 {
4098 rec = NULL;
4099
4100 /*
4101 * When declared arg type is RECORD, identify actual record type from
4102 * calling query, or fail if we can't.
4103 */
4104 if (cache->argtype == RECORDOID)
4105 {
4106 get_record_type_from_query(fcinfo, funcname, cache);
4107 /* This can't change argtype, which is important for next time */
4108 Assert(cache->argtype == RECORDOID);
4109 }
4110 }
4111
4112 /* if the json is null send back an empty set */
4115
4116 /*
4117 * Forcibly update the cached tupdesc, to ensure we have the right tupdesc
4118 * to return even if the JSON contains no rows.
4119 */
4120 update_cached_tupdesc(&cache->c.io.composite, cache->fn_mcxt);
4121
4123
4124 /* make tuplestore in a sufficiently long-lived memory context */
4125 old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
4126 state->tuple_store = tuplestore_begin_heap(rsi->allowedModes &
4128 false, work_mem);
4130
4131 state->function_name = funcname;
4132 state->cache = cache;
4133 state->rec = rec;
4134
4135 if (is_json)
4136 {
4138 JsonLexContext lex;
4140
4142
4143 makeJsonLexContext(&lex, json, true);
4144
4145 sem->semstate = state;
4153
4154 state->lex = &lex;
4155
4157
4158 freeJsonLexContext(&lex);
4159 state->lex = NULL;
4160 }
4161 else
4162 {
4165 JsonbValue v;
4166 bool skipNested = false;
4168
4170 ereport(ERROR,
4172 errmsg("cannot call %s on a non-array",
4173 funcname)));
4174
4175 it = JsonbIteratorInit(&jb->root);
4176
4177 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4178 {
4179 skipNested = true;
4180
4181 if (r == WJB_ELEM)
4182 {
4183 JsObject obj;
4184
4185 if (v.type != jbvBinary ||
4186 !JsonContainerIsObject(v.val.binary.data))
4187 ereport(ERROR,
4189 errmsg("argument of %s must be an array of objects",
4190 funcname)));
4191
4192 obj.is_json = false;
4193 obj.val.jsonb_cont = v.val.binary.data;
4194
4196 }
4197 }
4198 }
4199
4200 /*
4201 * Note: we must copy the cached tupdesc because the executor will free
4202 * the passed-back setDesc, but we want to hang onto the cache in case
4203 * we're called again in the same query.
4204 */
4205 rsi->setResult = state->tuple_store;
4206 rsi->setDesc = CreateTupleDescCopy(cache->c.io.composite.tupdesc);
4207
4209}

References ReturnSetInfo::allowedModes, PopulateRecordCache::argtype, JsonSemAction::array_element_start, JsonSemAction::array_start, Assert, CompositeIOData::base_typid, CompositeIOData::base_typmod, PopulateRecordCache::c, ColumnIOData::composite, CreateTupleDescCopy(), ReturnSetInfo::econtext, ExprContext::ecxt_per_query_memory, ereport, errcode(), errmsg(), ERROR, fb(), FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_extra, PopulateRecordCache::fn_mcxt, FmgrInfo::fn_mcxt, freeJsonLexContext(), funcname, get_record_type_from_argument(), get_record_type_from_query(), HeapTupleHeaderGetTypeId(), HeapTupleHeaderGetTypMod(), ColumnIOData::io, JsObject::is_json, IsA, JB_ROOT_IS_ARRAY, JB_ROOT_IS_SCALAR, jbvBinary, JsObject::jsonb_cont, JsonbIteratorInit(), JsonbIteratorNext(), JsonContainerIsObject, makeJsonLexContext(), MemoryContextAllocZero(), MemoryContextSwitchTo(), JsonSemAction::object_end, JsonSemAction::object_field_end, JsonSemAction::object_field_start, JsonSemAction::object_start, palloc0_object, PG_ARGISNULL, PG_GETARG_HEAPTUPLEHEADER, PG_GETARG_JSONB_P, PG_GETARG_TEXT_PP, pg_parse_json_or_ereport, PG_RETURN_NULL, populate_recordset_array_element_start(), populate_recordset_array_start(), populate_recordset_object_end(), populate_recordset_object_field_end(), populate_recordset_object_field_start(), populate_recordset_object_start(), populate_recordset_record(), populate_recordset_scalar(), FunctionCallInfoBaseData::resultinfo, ReturnSetInfo::returnMode, JsonSemAction::scalar, sem, JsonSemAction::semstate, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, SFRM_Materialize, SFRM_Materialize_Random, CompositeIOData::tupdesc, tuplestore_begin_heap(), JsonbValue::type, update_cached_tupdesc(), JsObject::val, JsonbValue::val, WJB_DONE, WJB_ELEM, and work_mem.

Referenced by json_populate_recordset(), json_to_recordset(), jsonb_populate_recordset(), and jsonb_to_recordset().

◆ populate_scalar()

static Datum populate_scalar ( ScalarIOData io,
Oid  typid,
int32  typmod,
JsValue jsv,
bool isnull,
Node escontext,
bool  omit_quotes 
)
static

Definition at line 3122 of file jsonfuncs.c.

3124{
3125 Datum res;
3126 char *str = NULL;
3127 const char *json = NULL;
3128
3129 if (jsv->is_json)
3130 {
3131 int len = jsv->val.json.len;
3132
3133 json = jsv->val.json.str;
3134 Assert(json);
3135
3136 /* If converting to json/jsonb, make string into valid JSON literal */
3137 if ((typid == JSONOID || typid == JSONBOID) &&
3138 jsv->val.json.type == JSON_TOKEN_STRING)
3139 {
3141
3143 if (len >= 0)
3144 escape_json_with_len(&buf, json, len);
3145 else
3146 escape_json(&buf, json);
3147 str = buf.data;
3148 }
3149 else if (len >= 0)
3150 {
3151 /* create a NUL-terminated version */
3152 str = palloc(len + 1);
3153 memcpy(str, json, len);
3154 str[len] = '\0';
3155 }
3156 else
3157 {
3158 /* string is already NUL-terminated */
3159 str = unconstify(char *, json);
3160 }
3161 }
3162 else
3163 {
3164 JsonbValue *jbv = jsv->val.jsonb;
3165
3166 if (jbv->type == jbvString && omit_quotes)
3167 str = pnstrdup(jbv->val.string.val, jbv->val.string.len);
3168 else if (typid == JSONBOID)
3169 {
3170 Jsonb *jsonb = JsonbValueToJsonb(jbv); /* directly use jsonb */
3171
3172 return JsonbPGetDatum(jsonb);
3173 }
3174 /* convert jsonb to string for typio call */
3175 else if (typid == JSONOID && jbv->type != jbvBinary)
3176 {
3177 /*
3178 * Convert scalar jsonb (non-scalars are passed here as jbvBinary)
3179 * to json string, preserving quotes around top-level strings.
3180 */
3181 Jsonb *jsonb = JsonbValueToJsonb(jbv);
3182
3183 str = JsonbToCString(NULL, &jsonb->root, VARSIZE(jsonb));
3184 }
3185 else if (jbv->type == jbvString) /* quotes are stripped */
3186 str = pnstrdup(jbv->val.string.val, jbv->val.string.len);
3187 else if (jbv->type == jbvBool)
3188 str = pstrdup(jbv->val.boolean ? "true" : "false");
3189 else if (jbv->type == jbvNumeric)
3191 PointerGetDatum(jbv->val.numeric)));
3192 else if (jbv->type == jbvBinary)
3193 str = JsonbToCString(NULL, jbv->val.binary.data,
3194 jbv->val.binary.len);
3195 else
3196 elog(ERROR, "unrecognized jsonb type: %d", (int) jbv->type);
3197 }
3198
3199 if (!InputFunctionCallSafe(&io->typiofunc, str, io->typioparam, typmod,
3200 escontext, &res))
3201 {
3202 res = (Datum) 0;
3203 *isnull = true;
3204 }
3205
3206 /* free temporary buffer */
3207 if (str != json)
3208 pfree(str);
3209
3210 return res;
3211}

References Assert, buf, DatumGetCString(), DirectFunctionCall1, elog, ERROR, escape_json(), escape_json_with_len(), fb(), initStringInfo(), InputFunctionCallSafe(), jbvBinary, jbvBool, jbvNumeric, jbvString, JSON_TOKEN_STRING, JsonbPGetDatum(), JsonbToCString(), JsonbValueToJsonb(), len, numeric_out(), palloc(), pfree(), pnstrdup(), PointerGetDatum(), pstrdup(), Jsonb::root, str, ScalarIOData::typiofunc, ScalarIOData::typioparam, unconstify, JsonbValue::val, and VARSIZE().

Referenced by populate_record_field().

◆ prepare_column_cache()

static void prepare_column_cache ( ColumnIOData column,
Oid  typid,
int32  typmod,
MemoryContext  mcxt,
bool  need_scalar 
)
static

Definition at line 3248 of file jsonfuncs.c.

3253{
3254 HeapTuple tup;
3256
3257 column->typid = typid;
3258 column->typmod = typmod;
3259
3261 if (!HeapTupleIsValid(tup))
3262 elog(ERROR, "cache lookup failed for type %u", typid);
3263
3265
3266 if (type->typtype == TYPTYPE_DOMAIN)
3267 {
3268 /*
3269 * We can move directly to the bottom base type; domain_check() will
3270 * take care of checking all constraints for a stack of domains.
3271 */
3272 Oid base_typid;
3273 int32 base_typmod = typmod;
3274
3275 base_typid = getBaseTypeAndTypmod(typid, &base_typmod);
3276 if (get_typtype(base_typid) == TYPTYPE_COMPOSITE)
3277 {
3278 /* domain over composite has its own code path */
3280 column->io.composite.record_io = NULL;
3281 column->io.composite.tupdesc = NULL;
3282 column->io.composite.base_typid = base_typid;
3283 column->io.composite.base_typmod = base_typmod;
3284 column->io.composite.domain_info = NULL;
3285 }
3286 else
3287 {
3288 /* domain over anything else */
3289 column->typcat = TYPECAT_DOMAIN;
3290 column->io.domain.base_typid = base_typid;
3291 column->io.domain.base_typmod = base_typmod;
3292 column->io.domain.base_io =
3293 MemoryContextAllocZero(mcxt, sizeof(ColumnIOData));
3294 column->io.domain.domain_info = NULL;
3295 }
3296 }
3297 else if (type->typtype == TYPTYPE_COMPOSITE || typid == RECORDOID)
3298 {
3299 column->typcat = TYPECAT_COMPOSITE;
3300 column->io.composite.record_io = NULL;
3301 column->io.composite.tupdesc = NULL;
3302 column->io.composite.base_typid = typid;
3303 column->io.composite.base_typmod = typmod;
3304 column->io.composite.domain_info = NULL;
3305 }
3306 else if (IsTrueArrayType(type))
3307 {
3308 column->typcat = TYPECAT_ARRAY;
3309 column->io.array.element_info = MemoryContextAllocZero(mcxt,
3310 sizeof(ColumnIOData));
3311 column->io.array.element_type = type->typelem;
3312 /* array element typemod stored in attribute's typmod */
3313 column->io.array.element_typmod = typmod;
3314 }
3315 else
3316 {
3317 column->typcat = TYPECAT_SCALAR;
3318 need_scalar = true;
3319 }
3320
3321 /* caller can force us to look up scalar_io info even for non-scalars */
3322 if (need_scalar)
3323 {
3324 Oid typioproc;
3325
3326 getTypeInputInfo(typid, &typioproc, &column->scalar_io.typioparam);
3327 fmgr_info_cxt(typioproc, &column->scalar_io.typiofunc, mcxt);
3328 }
3329
3331}

References elog, ERROR, fb(), fmgr_info_cxt(), get_typtype(), getBaseTypeAndTypmod(), GETSTRUCT(), getTypeInputInfo(), HeapTupleIsValid, MemoryContextAllocZero(), ObjectIdGetDatum(), ReleaseSysCache(), SearchSysCache1(), type, TYPECAT_ARRAY, TYPECAT_COMPOSITE, TYPECAT_COMPOSITE_DOMAIN, TYPECAT_DOMAIN, and TYPECAT_SCALAR.

Referenced by get_record_type_from_argument(), and populate_record_field().

◆ push_null_elements()

static void push_null_elements ( JsonbInState ps,
int  num 
)
static

Definition at line 1701 of file jsonfuncs.c.

1702{
1704
1705 null.type = jbvNull;
1706
1707 while (num-- > 0)
1709}

References fb(), jbvNull, ps, pushJsonbValue(), JsonbValue::type, and WJB_ELEM.

Referenced by push_path(), and setPathArray().

◆ push_path()

static void push_path ( JsonbInState st,
int  level,
const Datum path_elems,
const bool path_nulls,
int  path_len,
JsonbValue newval 
)
static

Definition at line 1720 of file jsonfuncs.c.

1722{
1723 /*
1724 * tpath contains expected type of an empty jsonb created at each level
1725 * higher or equal to the current one, either jbvObject or jbvArray. Since
1726 * it contains only information about path slice from level to the end,
1727 * the access index must be normalized by level.
1728 */
1729 enum jbvType *tpath = palloc0_array(enum jbvType, path_len - level);
1731
1732 /*
1733 * Create first part of the chain with beginning tokens. For the current
1734 * level WJB_BEGIN_OBJECT/WJB_BEGIN_ARRAY was already created, so start
1735 * with the next one.
1736 */
1737 for (int i = level + 1; i < path_len; i++)
1738 {
1739 char *c,
1740 *badp;
1741 int lindex;
1742
1743 if (path_nulls[i])
1744 break;
1745
1746 /*
1747 * Try to convert to an integer to find out the expected type, object
1748 * or array.
1749 */
1751 errno = 0;
1752 lindex = strtoint(c, &badp, 10);
1753 if (badp == c || *badp != '\0' || errno != 0)
1754 {
1755 /* text, an object is expected */
1756 newkey.type = jbvString;
1757 newkey.val.string.val = c;
1758 newkey.val.string.len = strlen(c);
1759
1762
1763 tpath[i - level] = jbvObject;
1764 }
1765 else
1766 {
1767 /* integer, an array is expected */
1769
1771
1772 tpath[i - level] = jbvArray;
1773 }
1774 }
1775
1776 /* Insert an actual value for either an object or array */
1777 if (tpath[(path_len - level) - 1] == jbvArray)
1779 else
1781
1782 /*
1783 * Close everything up to the last but one level. The last one will be
1784 * closed outside of this function.
1785 */
1786 for (int i = path_len - 1; i > level; i--)
1787 {
1788 if (path_nulls[i])
1789 break;
1790
1791 if (tpath[i - level] == jbvObject)
1793 else
1795 }
1796}

References fb(), i, jbvArray, jbvObject, jbvString, newval, palloc0_array, push_null_elements(), pushJsonbValue(), strtoint(), TextDatumGetCString, WJB_BEGIN_ARRAY, WJB_BEGIN_OBJECT, WJB_ELEM, WJB_END_ARRAY, WJB_END_OBJECT, WJB_KEY, and WJB_VALUE.

Referenced by setPathArray(), and setPathObject().

◆ report_json_context()

static int report_json_context ( JsonLexContext lex)
static

Definition at line 677 of file jsonfuncs.c.

678{
679 const char *context_start;
680 const char *context_end;
681 const char *line_start;
682 char *ctxt;
683 int ctxtlen;
684 const char *prefix;
685 const char *suffix;
686
687 /* Choose boundaries for the part of the input we will display */
688 line_start = lex->line_start;
689 context_start = line_start;
692
693 /* Advance until we are close enough to context_end */
694 while (context_end - context_start >= 50)
695 {
696 /* Advance to next multibyte character */
699 else
701 }
702
703 /*
704 * We add "..." to indicate that the excerpt doesn't start at the
705 * beginning of the line ... but if we're within 3 characters of the
706 * beginning of the line, we might as well just show the whole line.
707 */
708 if (context_start - line_start <= 3)
709 context_start = line_start;
710
711 /* Get a null-terminated copy of the data to present */
713 ctxt = palloc(ctxtlen + 1);
715 ctxt[ctxtlen] = '\0';
716
717 /*
718 * Show the context, prefixing "..." if not starting at start of line, and
719 * suffixing "..." if not ending at end of line.
720 */
721 prefix = (context_start > line_start) ? "..." : "";
722 suffix = (lex->token_type != JSON_TOKEN_END &&
723 context_end - lex->input < lex->input_length &&
724 *context_end != '\n' && *context_end != '\r') ? "..." : "";
725
726 return errcontext("JSON data, line %d: %s%s%s",
727 lex->line_number, prefix, ctxt, suffix);
728}

References Assert, errcontext, fb(), JsonLexContext::input, JsonLexContext::input_length, IS_HIGHBIT_SET, JSON_TOKEN_END, JsonLexContext::line_number, JsonLexContext::line_start, palloc(), pg_mblen(), JsonLexContext::token_terminator, and JsonLexContext::token_type.

Referenced by json_errsave_error().

◆ setPath()

static void setPath ( JsonbIterator **  it,
const Datum path_elems,
const bool path_nulls,
int  path_len,
JsonbInState st,
int  level,
JsonbValue newval,
int  op_type 
)
static

Definition at line 5173 of file jsonfuncs.c.

5176{
5177 JsonbValue v;
5179
5181
5182 if (path_nulls[level])
5183 ereport(ERROR,
5185 errmsg("path element at position %d is null",
5186 level + 1)));
5187
5188 r = JsonbIteratorNext(it, &v, false);
5189
5190 switch (r)
5191 {
5192 case WJB_BEGIN_ARRAY:
5193
5194 /*
5195 * If instructed complain about attempts to replace within a raw
5196 * scalar value. This happens even when current level is equal to
5197 * path_len, because the last path key should also correspond to
5198 * an object or an array, not raw scalar.
5199 */
5200 if ((op_type & JB_PATH_FILL_GAPS) && (level <= path_len - 1) &&
5201 v.val.array.rawScalar)
5202 ereport(ERROR,
5204 errmsg("cannot replace existing key"),
5205 errdetail("The path assumes key is a composite object, "
5206 "but it is a scalar value.")));
5207
5208 pushJsonbValue(st, r, NULL);
5210 newval, v.val.array.nElems, op_type);
5211 r = JsonbIteratorNext(it, &v, false);
5212 Assert(r == WJB_END_ARRAY);
5213 pushJsonbValue(st, r, NULL);
5214 break;
5215 case WJB_BEGIN_OBJECT:
5216 pushJsonbValue(st, r, NULL);
5218 newval, v.val.object.nPairs, op_type);
5219 r = JsonbIteratorNext(it, &v, true);
5220 Assert(r == WJB_END_OBJECT);
5221 pushJsonbValue(st, r, NULL);
5222 break;
5223 case WJB_ELEM:
5224 case WJB_VALUE:
5225
5226 /*
5227 * If instructed complain about attempts to replace within a
5228 * scalar value. This happens even when current level is equal to
5229 * path_len, because the last path key should also correspond to
5230 * an object or an array, not an element or value.
5231 */
5232 if ((op_type & JB_PATH_FILL_GAPS) && (level <= path_len - 1))
5233 ereport(ERROR,
5235 errmsg("cannot replace existing key"),
5236 errdetail("The path assumes key is a composite object, "
5237 "but it is a scalar value.")));
5238
5239 pushJsonbValue(st, r, &v);
5240 break;
5241 default:
5242 elog(ERROR, "unrecognized iterator result: %d", (int) r);
5243 break;
5244 }
5245}

References Assert, check_stack_depth(), elog, ereport, errcode(), errdetail(), errmsg(), ERROR, fb(), JB_PATH_FILL_GAPS, JsonbIteratorNext(), newval, pushJsonbValue(), setPathArray(), setPathObject(), JsonbValue::val, WJB_BEGIN_ARRAY, WJB_BEGIN_OBJECT, WJB_ELEM, WJB_END_ARRAY, WJB_END_OBJECT, and WJB_VALUE.

Referenced by jsonb_delete_path(), jsonb_insert(), jsonb_set(), jsonb_set_element(), setPathArray(), and setPathObject().

◆ setPathArray()

static void setPathArray ( JsonbIterator **  it,
const Datum path_elems,
const bool path_nulls,
int  path_len,
JsonbInState st,
int  level,
JsonbValue newval,
uint32  nelems,
int  op_type 
)
static

Definition at line 5389 of file jsonfuncs.c.

5392{
5393 JsonbValue v;
5394 int idx,
5395 i;
5396 bool done = false;
5397
5398 /* pick correct index */
5399 if (level < path_len && !path_nulls[level])
5400 {
5401 char *c = TextDatumGetCString(path_elems[level]);
5402 char *badp;
5403
5404 errno = 0;
5405 idx = strtoint(c, &badp, 10);
5406 if (badp == c || *badp != '\0' || errno != 0)
5407 ereport(ERROR,
5409 errmsg("path element at position %d is not an integer: \"%s\"",
5410 level + 1, c)));
5411 }
5412 else
5413 idx = nelems;
5414
5415 if (idx < 0)
5416 {
5417 if (pg_abs_s32(idx) > nelems)
5418 {
5419 /*
5420 * If asked to keep elements position consistent, it's not allowed
5421 * to prepend the array.
5422 */
5424 ereport(ERROR,
5426 errmsg("path element at position %d is out of range: %d",
5427 level + 1, idx)));
5428 else
5429 idx = PG_INT32_MIN;
5430 }
5431 else
5432 idx = nelems + idx;
5433 }
5434
5435 /*
5436 * Filling the gaps means there are no limits on the positive index are
5437 * imposed, we can set any element. Otherwise limit the index by nelems.
5438 */
5439 if (!(op_type & JB_PATH_FILL_GAPS))
5440 {
5441 if (idx > 0 && idx > nelems)
5442 idx = nelems;
5443 }
5444
5445 /*
5446 * if we're creating, and idx == INT_MIN, we prepend the new value to the
5447 * array also if the array is empty - in which case we don't really care
5448 * what the idx value is
5449 */
5450 if ((idx == INT_MIN || nelems == 0) && (level == path_len - 1) &&
5452 {
5453 Assert(newval != NULL);
5454
5455 if (op_type & JB_PATH_FILL_GAPS && nelems == 0 && idx > 0)
5457
5459
5460 done = true;
5461 }
5462
5463 /* iterate over the array elements */
5464 for (i = 0; i < nelems; i++)
5465 {
5467
5468 if (i == idx && level < path_len)
5469 {
5470 done = true;
5471
5472 if (level == path_len - 1)
5473 {
5474 r = JsonbIteratorNext(it, &v, true); /* skip */
5475
5478
5479 /*
5480 * We should keep current value only in case of
5481 * JB_PATH_INSERT_BEFORE or JB_PATH_INSERT_AFTER because
5482 * otherwise it should be deleted or replaced
5483 */
5485 pushJsonbValue(st, r, &v);
5486
5489 }
5490 else
5492 st, level + 1, newval, op_type);
5493 }
5494 else
5495 {
5496 r = JsonbIteratorNext(it, &v, false);
5497
5498 pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5499
5500 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5501 {
5502 int walking_level = 1;
5503
5504 while (walking_level != 0)
5505 {
5506 r = JsonbIteratorNext(it, &v, false);
5507
5508 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5509 ++walking_level;
5510 if (r == WJB_END_ARRAY || r == WJB_END_OBJECT)
5511 --walking_level;
5512
5513 pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5514 }
5515 }
5516 }
5517 }
5518
5519 if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done && level == path_len - 1)
5520 {
5521 /*
5522 * If asked to fill the gaps, idx could be bigger than nelems, so
5523 * prepend the new element with nulls if that's the case.
5524 */
5525 if (op_type & JB_PATH_FILL_GAPS && idx > nelems)
5526 push_null_elements(st, idx - nelems);
5527
5529 done = true;
5530 }
5531
5532 /*--
5533 * If we got here there are only few possibilities:
5534 * - no target path was found, and an open array with some keys/values was
5535 * pushed into the state
5536 * - an array is empty, only WJB_BEGIN_ARRAY is pushed
5537 *
5538 * In both cases if instructed to create the path when not present,
5539 * generate the whole chain of empty objects and insert the new value
5540 * there.
5541 */
5542 if (!done && (op_type & JB_PATH_FILL_GAPS) && (level < path_len - 1))
5543 {
5544 if (idx > 0)
5545 push_null_elements(st, idx - nelems);
5546
5548
5549 /* Result is closed with WJB_END_OBJECT outside of this function */
5550 }
5551}

References Assert, ereport, errcode(), errmsg(), ERROR, fb(), i, idx(), JB_PATH_CONSISTENT_POSITION, JB_PATH_CREATE, JB_PATH_CREATE_OR_INSERT, JB_PATH_FILL_GAPS, JB_PATH_INSERT_AFTER, JB_PATH_INSERT_BEFORE, JB_PATH_REPLACE, JsonbIteratorNext(), newval, pg_abs_s32(), PG_INT32_MIN, push_null_elements(), push_path(), pushJsonbValue(), setPath(), strtoint(), TextDatumGetCString, WJB_BEGIN_ARRAY, WJB_BEGIN_OBJECT, WJB_ELEM, WJB_END_ARRAY, and WJB_END_OBJECT.

Referenced by setPath().

◆ setPathObject()

static void setPathObject ( JsonbIterator **  it,
const Datum path_elems,
const bool path_nulls,
int  path_len,
JsonbInState st,
int  level,
JsonbValue newval,
uint32  npairs,
int  op_type 
)
static

Definition at line 5251 of file jsonfuncs.c.

5254{
5255 text *pathelem = NULL;
5256 int i;
5257 JsonbValue k,
5258 v;
5259 bool done = false;
5260
5261 if (level >= path_len || path_nulls[level])
5262 done = true;
5263 else
5264 {
5265 /* The path Datum could be toasted, in which case we must detoast it */
5267 }
5268
5269 /* empty object is a special case for create */
5270 if ((npairs == 0) && (op_type & JB_PATH_CREATE_OR_INSERT) &&
5271 (level == path_len - 1))
5272 {
5274
5276 newkey.val.string.val = VARDATA_ANY(pathelem);
5277 newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
5278
5281 }
5282
5283 for (i = 0; i < npairs; i++)
5284 {
5286
5287 Assert(r == WJB_KEY);
5288
5289 if (!done &&
5290 k.val.string.len == VARSIZE_ANY_EXHDR(pathelem) &&
5291 memcmp(k.val.string.val, VARDATA_ANY(pathelem),
5292 k.val.string.len) == 0)
5293 {
5294 done = true;
5295
5296 if (level == path_len - 1)
5297 {
5298 /*
5299 * called from jsonb_insert(), it forbids redefining an
5300 * existing value
5301 */
5303 ereport(ERROR,
5305 errmsg("cannot replace existing key"),
5306 errhint("Try using the function jsonb_set "
5307 "to replace key value.")));
5308
5309 r = JsonbIteratorNext(it, &v, true); /* skip value */
5310 if (!(op_type & JB_PATH_DELETE))
5311 {
5312 pushJsonbValue(st, WJB_KEY, &k);
5314 }
5315 }
5316 else
5317 {
5318 pushJsonbValue(st, r, &k);
5320 st, level + 1, newval, op_type);
5321 }
5322 }
5323 else
5324 {
5325 if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done &&
5326 level == path_len - 1 && i == npairs - 1)
5327 {
5329
5331 newkey.val.string.val = VARDATA_ANY(pathelem);
5332 newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
5333
5336 }
5337
5338 pushJsonbValue(st, r, &k);
5339 r = JsonbIteratorNext(it, &v, false);
5340 pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5341 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5342 {
5343 int walking_level = 1;
5344
5345 while (walking_level != 0)
5346 {
5347 r = JsonbIteratorNext(it, &v, false);
5348
5349 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5350 ++walking_level;
5351 if (r == WJB_END_ARRAY || r == WJB_END_OBJECT)
5352 --walking_level;
5353
5354 pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5355 }
5356 }
5357 }
5358 }
5359
5360 /*--
5361 * If we got here there are only few possibilities:
5362 * - no target path was found, and an open object with some keys/values was
5363 * pushed into the state
5364 * - an object is empty, only WJB_BEGIN_OBJECT is pushed
5365 *
5366 * In both cases if instructed to create the path when not present,
5367 * generate the whole chain of empty objects and insert the new value
5368 * there.
5369 */
5370 if (!done && (op_type & JB_PATH_FILL_GAPS) && (level < path_len - 1))
5371 {
5373
5375 newkey.val.string.val = VARDATA_ANY(pathelem);
5376 newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
5377
5380
5381 /* Result is closed with WJB_END_OBJECT outside of this function */
5382 }
5383}

References Assert, DatumGetTextPP, ereport, errcode(), errhint(), errmsg(), ERROR, fb(), i, JB_PATH_CREATE_OR_INSERT, JB_PATH_DELETE, JB_PATH_FILL_GAPS, JB_PATH_INSERT_AFTER, JB_PATH_INSERT_BEFORE, jbvString, JsonbIteratorNext(), newval, push_path(), pushJsonbValue(), setPath(), JsonbValue::type, JsonbValue::val, VARDATA_ANY(), VARSIZE_ANY_EXHDR(), WJB_BEGIN_ARRAY, WJB_BEGIN_OBJECT, WJB_END_ARRAY, WJB_END_OBJECT, WJB_KEY, and WJB_VALUE.

Referenced by setPath().

◆ sn_array_element_start()

static JsonParseErrorType sn_array_element_start ( void state,
bool  isnull 
)
static

Definition at line 4457 of file jsonfuncs.c.

4458{
4460
4461 /* If strip_in_arrays is enabled and this is a null, mark it for skipping */
4462 if (isnull && _state->strip_in_arrays)
4463 {
4464 _state->skip_next_null = true;
4465 return JSON_SUCCESS;
4466 }
4467
4468 /* Only add a comma if this is not the first valid element */
4469 if (_state->strval->len > 0 &&
4470 _state->strval->data[_state->strval->len - 1] != '[')
4471 {
4472 appendStringInfoCharMacro(_state->strval, ',');
4473 }
4474
4475 return JSON_SUCCESS;
4476}

References appendStringInfoCharMacro, fb(), and JSON_SUCCESS.

Referenced by json_strip_nulls().

◆ sn_array_end()

static JsonParseErrorType sn_array_end ( void state)
static

Definition at line 4417 of file jsonfuncs.c.

4418{
4420
4421 appendStringInfoCharMacro(_state->strval, ']');
4422
4423 return JSON_SUCCESS;
4424}

References appendStringInfoCharMacro, fb(), and JSON_SUCCESS.

Referenced by json_strip_nulls().

◆ sn_array_start()

static JsonParseErrorType sn_array_start ( void state)
static

Definition at line 4407 of file jsonfuncs.c.

4408{
4410
4411 appendStringInfoCharMacro(_state->strval, '[');
4412
4413 return JSON_SUCCESS;
4414}

References appendStringInfoCharMacro, fb(), and JSON_SUCCESS.

Referenced by json_strip_nulls().

◆ sn_object_end()

static JsonParseErrorType sn_object_end ( void state)
static

Definition at line 4397 of file jsonfuncs.c.

4398{
4400
4401 appendStringInfoCharMacro(_state->strval, '}');
4402
4403 return JSON_SUCCESS;
4404}

References appendStringInfoCharMacro, fb(), and JSON_SUCCESS.

Referenced by json_strip_nulls().

◆ sn_object_field_start()

static JsonParseErrorType sn_object_field_start ( void state,
char fname,
bool  isnull 
)
static

Definition at line 4427 of file jsonfuncs.c.

4428{
4430
4431 if (isnull)
4432 {
4433 /*
4434 * The next thing must be a scalar or isnull couldn't be true, so
4435 * there is no danger of this state being carried down into a nested
4436 * object or array. The flag will be reset in the scalar action.
4437 */
4438 _state->skip_next_null = true;
4439 return JSON_SUCCESS;
4440 }
4441
4442 if (_state->strval->data[_state->strval->len - 1] != '{')
4443 appendStringInfoCharMacro(_state->strval, ',');
4444
4445 /*
4446 * Unfortunately we don't have the quoted and escaped string any more, so
4447 * we have to re-escape it.
4448 */
4449 escape_json(_state->strval, fname);
4450
4451 appendStringInfoCharMacro(_state->strval, ':');
4452
4453 return JSON_SUCCESS;
4454}

References appendStringInfoCharMacro, escape_json(), fb(), and JSON_SUCCESS.

Referenced by json_strip_nulls().

◆ sn_object_start()

static JsonParseErrorType sn_object_start ( void state)
static

Definition at line 4387 of file jsonfuncs.c.

4388{
4390
4391 appendStringInfoCharMacro(_state->strval, '{');
4392
4393 return JSON_SUCCESS;
4394}

References appendStringInfoCharMacro, fb(), and JSON_SUCCESS.

Referenced by json_strip_nulls().

◆ sn_scalar()

static JsonParseErrorType sn_scalar ( void state,
char token,
JsonTokenType  tokentype 
)
static

Definition at line 4479 of file jsonfuncs.c.

4480{
4482
4483 if (_state->skip_next_null)
4484 {
4485 Assert(tokentype == JSON_TOKEN_NULL);
4486 _state->skip_next_null = false;
4487 return JSON_SUCCESS;
4488 }
4489
4490 if (tokentype == JSON_TOKEN_STRING)
4491 escape_json(_state->strval, token);
4492 else
4494
4495 return JSON_SUCCESS;
4496}

References appendStringInfoString(), Assert, escape_json(), fb(), JSON_SUCCESS, JSON_TOKEN_NULL, and JSON_TOKEN_STRING.

Referenced by json_strip_nulls().

◆ transform_json_string_values()

text * transform_json_string_values ( text json,
void action_state,
JsonTransformStringValuesAction  transform_action 
)

Definition at line 5815 of file jsonfuncs.c.

References JsonSemAction::array_element_start, JsonSemAction::array_end, JsonSemAction::array_start, cstring_to_text_with_len(), fb(), freeJsonLexContext(), initStringInfo(), makeJsonLexContext(), JsonSemAction::object_end, JsonSemAction::object_field_start, JsonSemAction::object_start, palloc0_object, pg_parse_json_or_ereport, JsonSemAction::scalar, sem, JsonSemAction::semstate, transform_string_values_array_element_start(), transform_string_values_array_end(), transform_string_values_array_start(), transform_string_values_object_end(), transform_string_values_object_field_start(), transform_string_values_object_start(), and transform_string_values_scalar().

Referenced by ts_headline_json_byid_opt().

◆ transform_jsonb_string_values()

Jsonb * transform_jsonb_string_values ( Jsonb jsonb,
void action_state,
JsonTransformStringValuesAction  transform_action 
)

Definition at line 5769 of file jsonfuncs.c.

5771{
5773 JsonbValue v;
5775 JsonbInState st = {0};
5776 text *out;
5777 bool is_scalar = false;
5778
5779 it = JsonbIteratorInit(&jsonb->root);
5780 is_scalar = it->isScalar;
5781
5782 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
5783 {
5784 if ((type == WJB_VALUE || type == WJB_ELEM) && v.type == jbvString)
5785 {
5786 out = transform_action(action_state, v.val.string.val, v.val.string.len);
5787 /* out is probably not toasted, but let's be sure */
5788 out = pg_detoast_datum_packed(out);
5789 v.val.string.val = VARDATA_ANY(out);
5790 v.val.string.len = VARSIZE_ANY_EXHDR(out);
5792 }
5793 else
5794 {
5795 pushJsonbValue(&st, type, (type == WJB_KEY ||
5796 type == WJB_VALUE ||
5797 type == WJB_ELEM) ? &v : NULL);
5798 }
5799 }
5800
5801 if (st.result->type == jbvArray)
5802 st.result->val.array.rawScalar = is_scalar;
5803
5804 return JsonbValueToJsonb(st.result);
5805}

References fb(), jbvArray, jbvString, JsonbIteratorInit(), JsonbIteratorNext(), JsonbValueToJsonb(), pg_detoast_datum_packed(), pushJsonbValue(), JsonbInState::result, Jsonb::root, type, JsonbValue::type, JsonbValue::val, VARDATA_ANY(), VARSIZE_ANY_EXHDR(), WJB_BEGIN_ARRAY, WJB_DONE, WJB_ELEM, WJB_KEY, and WJB_VALUE.

Referenced by ts_headline_jsonb_byid_opt().

◆ transform_string_values_array_element_start()

static JsonParseErrorType transform_string_values_array_element_start ( void state,
bool  isnull 
)
static

Definition at line 5909 of file jsonfuncs.c.

5910{
5912
5913 if (_state->strval->data[_state->strval->len - 1] != '[')
5914 appendStringInfoCharMacro(_state->strval, ',');
5915
5916 return JSON_SUCCESS;
5917}

References appendStringInfoCharMacro, fb(), and JSON_SUCCESS.

Referenced by transform_json_string_values().

◆ transform_string_values_array_end()

static JsonParseErrorType transform_string_values_array_end ( void state)
static

Definition at line 5881 of file jsonfuncs.c.

5882{
5884
5885 appendStringInfoCharMacro(_state->strval, ']');
5886
5887 return JSON_SUCCESS;
5888}

References appendStringInfoCharMacro, fb(), and JSON_SUCCESS.

Referenced by transform_json_string_values().

◆ transform_string_values_array_start()

static JsonParseErrorType transform_string_values_array_start ( void state)
static

Definition at line 5871 of file jsonfuncs.c.

5872{
5874
5875 appendStringInfoCharMacro(_state->strval, '[');
5876
5877 return JSON_SUCCESS;
5878}

References appendStringInfoCharMacro, fb(), and JSON_SUCCESS.

Referenced by transform_json_string_values().

◆ transform_string_values_object_end()

static JsonParseErrorType transform_string_values_object_end ( void state)
static

Definition at line 5861 of file jsonfuncs.c.

5862{
5864
5865 appendStringInfoCharMacro(_state->strval, '}');
5866
5867 return JSON_SUCCESS;
5868}

References appendStringInfoCharMacro, fb(), and JSON_SUCCESS.

Referenced by transform_json_string_values().

◆ transform_string_values_object_field_start()

static JsonParseErrorType transform_string_values_object_field_start ( void state,
char fname,
bool  isnull 
)
static

Definition at line 5891 of file jsonfuncs.c.

5892{
5894
5895 if (_state->strval->data[_state->strval->len - 1] != '{')
5896 appendStringInfoCharMacro(_state->strval, ',');
5897
5898 /*
5899 * Unfortunately we don't have the quoted and escaped string any more, so
5900 * we have to re-escape it.
5901 */
5902 escape_json(_state->strval, fname);
5903 appendStringInfoCharMacro(_state->strval, ':');
5904
5905 return JSON_SUCCESS;
5906}

References appendStringInfoCharMacro, escape_json(), fb(), and JSON_SUCCESS.

Referenced by transform_json_string_values().

◆ transform_string_values_object_start()

static JsonParseErrorType transform_string_values_object_start ( void state)
static

Definition at line 5851 of file jsonfuncs.c.

5852{
5854
5855 appendStringInfoCharMacro(_state->strval, '{');
5856
5857 return JSON_SUCCESS;
5858}

References appendStringInfoCharMacro, fb(), and JSON_SUCCESS.

Referenced by transform_json_string_values().

◆ transform_string_values_scalar()

static JsonParseErrorType transform_string_values_scalar ( void state,
char token,
JsonTokenType  tokentype 
)
static

Definition at line 5920 of file jsonfuncs.c.

5921{
5923
5924 if (tokentype == JSON_TOKEN_STRING)
5925 {
5926 text *out = _state->action(_state->action_state, token, strlen(token));
5927
5928 escape_json_text(_state->strval, out);
5929 }
5930 else
5932
5933 return JSON_SUCCESS;
5934}

References appendStringInfoString(), escape_json_text(), fb(), JSON_SUCCESS, and JSON_TOKEN_STRING.

Referenced by transform_json_string_values().

◆ update_cached_tupdesc()

static void update_cached_tupdesc ( CompositeIOData io,
MemoryContext  mcxt 
)
static

Definition at line 3026 of file jsonfuncs.c.

3027{
3028 if (!io->tupdesc ||
3029 io->tupdesc->tdtypeid != io->base_typid ||
3030 io->tupdesc->tdtypmod != io->base_typmod)
3031 {
3033 io->base_typmod);
3035
3036 if (io->tupdesc)
3038
3039 /* copy tuple desc without constraints into cache memory context */
3041 io->tupdesc = CreateTupleDescCopy(tupdesc);
3043
3044 ReleaseTupleDesc(tupdesc);
3045 }
3046}

References CompositeIOData::base_typid, CompositeIOData::base_typmod, CreateTupleDescCopy(), fb(), FreeTupleDesc(), lookup_rowtype_tupdesc(), MemoryContextSwitchTo(), ReleaseTupleDesc, TupleDescData::tdtypeid, TupleDescData::tdtypmod, and CompositeIOData::tupdesc.

Referenced by populate_composite(), populate_recordset_record(), and populate_recordset_worker().