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 "access/tupdesc.h"
#include "catalog/pg_proc.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/tuplestore.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)
 
void json_check_mutability (Oid typoid, bool is_jsonb, bool *has_mutable)
 

Macro Definition Documentation

◆ JB_PATH_CONSISTENT_POSITION

#define JB_PATH_CONSISTENT_POSITION   0x0040

Definition at line 55 of file jsonfuncs.c.

◆ JB_PATH_CREATE

#define JB_PATH_CREATE   0x0001

Definition at line 47 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 52 of file jsonfuncs.c.

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

◆ JB_PATH_DELETE

#define JB_PATH_DELETE   0x0002

Definition at line 48 of file jsonfuncs.c.

◆ JB_PATH_FILL_GAPS

#define JB_PATH_FILL_GAPS   0x0020

Definition at line 54 of file jsonfuncs.c.

◆ JB_PATH_INSERT_AFTER

#define JB_PATH_INSERT_AFTER   0x0010

Definition at line 51 of file jsonfuncs.c.

◆ JB_PATH_INSERT_BEFORE

#define JB_PATH_INSERT_BEFORE   0x0008

Definition at line 50 of file jsonfuncs.c.

◆ JB_PATH_REPLACE

#define JB_PATH_REPLACE   0x0004

Definition at line 49 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 338 of file jsonfuncs.c.

339 { \
340 if ((jso)->is_json) \
341 hash_destroy((jso)->val.json_hash); \
342 } 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 332 of file jsonfuncs.c.

335 : ((jso)->val.jsonb_cont == NULL || \
336 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 323 of file jsonfuncs.c.

325 : \
326 (!(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 328 of file jsonfuncs.c.

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

Typedef Documentation

◆ AlenState

◆ ArrayIOData

◆ ColumnIOData

Definition at line 165 of file jsonfuncs.c.

◆ CompositeIOData

◆ DomainIOData

◆ EachState

◆ ElementsState

◆ GetState

◆ IterateJsonStringValuesState

◆ JHashState

◆ JsObject

◆ JsonHashEntry

◆ JsValue

◆ OkeysState

◆ PopulateArrayContext

◆ PopulateArrayState

◆ PopulateRecordCache

◆ PopulateRecordsetState

◆ RecordIOData

Definition at line 166 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 202 of file jsonfuncs.c.

203{
204 TYPECAT_SCALAR = 's',
205 TYPECAT_ARRAY = 'a',
206 TYPECAT_COMPOSITE = 'c',
208 TYPECAT_DOMAIN = 'd',
209} TypeCat;

Function Documentation

◆ alen_array_element_start()

static JsonParseErrorType alen_array_element_start ( void state,
bool  isnull 
)
static

Definition at line 1928 of file jsonfuncs.c.

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

References fb(), and JSON_SUCCESS.

Referenced by json_array_length().

◆ alen_object_start()

static JsonParseErrorType alen_object_start ( void state)
static

Definition at line 1900 of file jsonfuncs.c.

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

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 1914 of file jsonfuncs.c.

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

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 3476 of file jsonfuncs.c.

3477{
3479 MemoryContextAlloc(mcxt,
3480 offsetof(RecordIOData, columns) +
3481 ncolumns * sizeof(ColumnIOData));
3482
3484 data->record_typmod = 0;
3485 data->ncolumns = ncolumns;
3486 MemSet(data->columns, 0, sizeof(ColumnIOData) * ncolumns);
3487
3488 return data;
3489}

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 2168 of file jsonfuncs.c.

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

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 2120 of file jsonfuncs.c.

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

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 2098 of file jsonfuncs.c.

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

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 2182 of file jsonfuncs.c.

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

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 2058 of file jsonfuncs.c.

2059{
2060 text *json = PG_GETARG_TEXT_PP(0);
2061 JsonLexContext lex;
2063 ReturnSetInfo *rsi;
2065
2068
2069 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2070
2072 state->tuple_store = rsi->setResult;
2073 state->ret_tdesc = rsi->setDesc;
2074
2075 sem->semstate = state;
2080
2081 state->normalize_results = as_text;
2082 state->next_scalar = false;
2083 state->lex = makeJsonLexContext(&lex, json, true);
2085 "json_each temporary cxt",
2087
2089
2090 MemoryContextDelete(state->tmp_cxt);
2091 freeJsonLexContext(&lex);
2092
2094}

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 1974 of file jsonfuncs.c.

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

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 2372 of file jsonfuncs.c.

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

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 2350 of file jsonfuncs.c.

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

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 2418 of file jsonfuncs.c.

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

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 2433 of file jsonfuncs.c.

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

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 2308 of file jsonfuncs.c.

2309{
2310 text *json = PG_GETARG_TEXT_PP(0);
2311 JsonLexContext lex;
2313 ReturnSetInfo *rsi;
2315
2316 /* elements only needs escaped strings when as_text */
2317 makeJsonLexContext(&lex, json, as_text);
2318
2321
2323 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2324 state->tuple_store = rsi->setResult;
2325 state->ret_tdesc = rsi->setDesc;
2326
2327 sem->semstate = state;
2332
2333 state->function_name = funcname;
2334 state->normalize_results = as_text;
2335 state->next_scalar = false;
2336 state->lex = &lex;
2338 "json_array_elements temporary cxt",
2340
2342
2343 MemoryContextDelete(state->tmp_cxt);
2344 freeJsonLexContext(&lex);
2345
2347}

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 2220 of file jsonfuncs.c.

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

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 1404 of file jsonfuncs.c.

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

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 1356 of file jsonfuncs.c.

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

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 1338 of file jsonfuncs.c.

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

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 1298 of file jsonfuncs.c.

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

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 3811 of file jsonfuncs.c.

3813{
3814 HASHCTL ctl;
3815 HTAB *tab;
3818
3819 ctl.keysize = NAMEDATALEN;
3820 ctl.entrysize = sizeof(JsonHashEntry);
3822 tab = hash_create("json object hashtable",
3823 100,
3824 &ctl,
3826
3829
3830 state->function_name = funcname;
3831 state->hash = tab;
3833 GetDatabaseEncoding(), true);
3834
3835 sem->semstate = state;
3840
3841 if (!pg_parse_json_or_errsave(state->lex, sem, escontext))
3842 {
3843 hash_destroy(state->hash);
3844 tab = NULL;
3845 }
3846
3848
3849 return tab;
3850}

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 1503 of file jsonfuncs.c.

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

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 1182 of file jsonfuncs.c.

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

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 1247 of file jsonfuncs.c.

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

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 1200 of file jsonfuncs.c.

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

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 1163 of file jsonfuncs.c.

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

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 1027 of file jsonfuncs.c.

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

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 3636 of file jsonfuncs.c.

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

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 3662 of file jsonfuncs.c.

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

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 1448 of file jsonfuncs.c.

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

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 1106 of file jsonfuncs.c.

1111{
1114
1115 Assert(npath >= 0);
1116
1117 state->lex = makeJsonLexContext(NULL, json, true);
1118
1119 /* is it "_as_text" variant? */
1120 state->normalize_results = normalize_results;
1121 state->npath = npath;
1122 state->path_names = tpath;
1123 state->path_indexes = ipath;
1124 state->pathok = palloc0_array(bool, npath);
1125 state->array_cur_index = palloc_array(int, npath);
1126
1127 if (npath > 0)
1128 state->pathok[0] = true;
1129
1130 sem->semstate = state;
1131
1132 /*
1133 * Not all variants need all the semantic routines. Only set the ones that
1134 * are actually needed for maximum efficiency.
1135 */
1137 if (npath == 0)
1138 {
1143 }
1144 if (tpath != NULL)
1145 {
1148 }
1149 if (ipath != NULL)
1150 {
1154 }
1155
1158
1159 return state->tresult;
1160}

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 3930 of file jsonfuncs.c.

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

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 3879 of file jsonfuncs.c.

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

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 3853 of file jsonfuncs.c.

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

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 3943 of file jsonfuncs.c.

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

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 5630 of file jsonfuncs.c.

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

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 5751 of file jsonfuncs.c.

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

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 5723 of file jsonfuncs.c.

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

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 5051 of file jsonfuncs.c.

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

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 3492 of file jsonfuncs.c.

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

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 925 of file jsonfuncs.c.

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

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 968 of file jsonfuncs.c.

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

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 2296 of file jsonfuncs.c.

2297{
2298 return elements_worker(fcinfo, "json_array_elements", false);
2299}

References elements_worker().

◆ json_array_elements_text()

Datum json_array_elements_text ( PG_FUNCTION_ARGS  )

Definition at line 2302 of file jsonfuncs.c.

2303{
2304 return elements_worker(fcinfo, "json_array_elements_text", true);
2305}

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 5967 of file jsonfuncs.c.

5969{
5970 bool typisvarlena;
5971
5972 /* Look through any domain */
5973 typoid = getBaseType(typoid);
5974
5976
5977 switch (typoid)
5978 {
5979 case BOOLOID:
5982 break;
5983
5984 case INT2OID:
5985 case INT4OID:
5986 case INT8OID:
5987 case FLOAT4OID:
5988 case FLOAT8OID:
5989 case NUMERICOID:
5990 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
5992 break;
5993
5994 case DATEOID:
5997 break;
5998
5999 case TIMESTAMPOID:
6002 break;
6003
6004 case TIMESTAMPTZOID:
6007 break;
6008
6009 case JSONOID:
6010 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6012 break;
6013
6014 case JSONBOID:
6015 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6017 break;
6018
6019 default:
6020 /* Check for arrays and composites */
6021 if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
6022 || typoid == ANYCOMPATIBLEARRAYOID || typoid == RECORDARRAYOID)
6023 {
6026 }
6027 else if (type_is_rowtype(typoid)) /* includes RECORDOID */
6028 {
6031 }
6032 else
6033 {
6034 /*
6035 * It's probably the general case. But let's look for a cast
6036 * to json (note: not to jsonb even if is_jsonb is true), if
6037 * it's not built-in.
6038 */
6040 if (typoid >= FirstNormalObjectId)
6041 {
6042 Oid castfunc;
6043 CoercionPathType ctype;
6044
6045 ctype = find_coercion_pathway(JSONOID, typoid,
6047 &castfunc);
6048 if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc))
6049 {
6050 *outfuncoid = castfunc;
6052 }
6053 else
6054 {
6055 /* non builtin type with no cast */
6056 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6057 }
6058 }
6059 else
6060 {
6061 /* any other builtin type */
6062 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6063 }
6064 }
6065 break;
6066 }
6067}

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_check_mutability(), json_object_agg_transfn_worker(), jsonb_agg_transfn_worker(), jsonb_object_agg_transfn_worker(), to_json(), and to_jsonb().

◆ json_check_mutability()

void json_check_mutability ( Oid  typoid,
bool  is_jsonb,
bool has_mutable 
)

Definition at line 6078 of file jsonfuncs.c.

6079{
6080 char att_typtype = get_typtype(typoid);
6083
6084 /* since this function recurses, it could be driven to stack overflow */
6086
6088
6089 if (*has_mutable)
6090 return;
6091
6093 {
6095 return;
6096 }
6097 else if (att_typtype == TYPTYPE_COMPOSITE)
6098 {
6099 /*
6100 * For a composite type, recurse into its attributes. Use the
6101 * typcache to avoid opening the relation directly.
6102 */
6103 TupleDesc tupdesc = lookup_rowtype_tupdesc(typoid, -1);
6104
6105 for (int i = 0; i < tupdesc->natts; i++)
6106 {
6107 Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
6108
6109 if (attr->attisdropped)
6110 continue;
6111
6112 json_check_mutability(attr->atttypid, is_jsonb, has_mutable);
6113 if (*has_mutable)
6114 break;
6115 }
6116 ReleaseTupleDesc(tupdesc);
6117 return;
6118 }
6119 else if (att_typtype == TYPTYPE_RANGE)
6120 {
6122 has_mutable);
6123 return;
6124 }
6125 else if (att_typtype == TYPTYPE_MULTIRANGE)
6126 {
6128 has_mutable);
6129 return;
6130 }
6131 else
6132 {
6134
6136 {
6137 /* recurse into array element type */
6139 return;
6140 }
6141 }
6142
6144
6145 switch (tcategory)
6146 {
6147 case JSONTYPE_NULL:
6148 case JSONTYPE_BOOL:
6149 case JSONTYPE_NUMERIC:
6150 break;
6151
6152 case JSONTYPE_DATE:
6153 case JSONTYPE_TIMESTAMP:
6155 *has_mutable = true;
6156 break;
6157
6158 case JSONTYPE_JSON:
6159 case JSONTYPE_JSONB:
6160 case JSONTYPE_ARRAY:
6161 case JSONTYPE_COMPOSITE:
6162 break;
6163
6164 case JSONTYPE_CAST:
6165 case JSONTYPE_OTHER:
6167 *has_mutable = true;
6168 break;
6169 }
6170}

References Assert, check_stack_depth(), fb(), func_volatile(), get_element_type(), get_multirange_range(), get_range_subtype(), get_typtype(), getBaseType(), i, json_categorize_type(), json_check_mutability(), JSONTYPE_ARRAY, JSONTYPE_BOOL, JSONTYPE_CAST, JSONTYPE_COMPOSITE, JSONTYPE_DATE, JSONTYPE_JSON, JSONTYPE_JSONB, JSONTYPE_NULL, JSONTYPE_NUMERIC, JSONTYPE_OTHER, JSONTYPE_TIMESTAMP, JSONTYPE_TIMESTAMPTZ, lookup_rowtype_tupdesc(), TupleDescData::natts, OidIsValid, ReleaseTupleDesc, and TupleDescAttr().

Referenced by json_check_mutability(), to_json_is_immutable(), and to_jsonb_is_immutable().

◆ json_each()

Datum json_each ( PG_FUNCTION_ARGS  )

Definition at line 1950 of file jsonfuncs.c.

1951{
1952 return each_worker(fcinfo, false);
1953}

References each_worker().

◆ json_each_text()

Datum json_each_text ( PG_FUNCTION_ARGS  )

Definition at line 1962 of file jsonfuncs.c.

1963{
1964 return each_worker(fcinfo, true);
1965}

References each_worker().

◆ json_errsave_error()

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

Definition at line 644 of file jsonfuncs.c.

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

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 1012 of file jsonfuncs.c.

1013{
1014 return get_path_all(fcinfo, false);
1015}

References get_path_all().

◆ json_extract_path_text()

Datum json_extract_path_text ( PG_FUNCTION_ARGS  )

Definition at line 1018 of file jsonfuncs.c.

1019{
1020 return get_path_all(fcinfo, true);
1021}

References get_path_all().

◆ json_get_first_token()

JsonTokenType json_get_first_token ( text json,
bool  throw_error 
)

Definition at line 5940 of file jsonfuncs.c.

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

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 849 of file jsonfuncs.c.

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

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 887 of file jsonfuncs.c.

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

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 735 of file jsonfuncs.c.

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

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 2495 of file jsonfuncs.c.

2496{
2497 return populate_record_worker(fcinfo, "json_populate_record",
2498 true, true, NULL);
2499}

References fb(), and populate_record_worker().

◆ json_populate_recordset()

Datum json_populate_recordset ( PG_FUNCTION_ARGS  )

Definition at line 3988 of file jsonfuncs.c.

3989{
3990 return populate_recordset_worker(fcinfo, "json_populate_recordset",
3991 true, true);
3992}

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 3345 of file jsonfuncs.c.

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

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 4505 of file jsonfuncs.c.

4506{
4507 text *json = PG_GETARG_TEXT_PP(0);
4508 bool strip_in_arrays = PG_NARGS() == 2 ? PG_GETARG_BOOL(1) : false;
4511 JsonLexContext lex;
4513
4517
4518 state->lex = makeJsonLexContext(&lex, json, true);
4519 state->strval = &strbuf;
4520 state->skip_next_null = false;
4521 state->strip_in_arrays = strip_in_arrays;
4522
4523 sem->semstate = state;
4528 sem->scalar = sn_scalar;
4531
4533
4535 state->strval->len));
4536}

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 2502 of file jsonfuncs.c.

2503{
2504 return populate_record_worker(fcinfo, "json_to_record",
2505 true, false, NULL);
2506}

References fb(), and populate_record_worker().

◆ json_to_recordset()

Datum json_to_recordset ( PG_FUNCTION_ARGS  )

Definition at line 3995 of file jsonfuncs.c.

3996{
3997 return populate_recordset_worker(fcinfo, "json_to_recordset",
3998 true, false);
3999}

References populate_recordset_worker().

◆ jsonb_array_element()

Datum jsonb_array_element ( PG_FUNCTION_ARGS  )

Definition at line 940 of file jsonfuncs.c.

941{
943 int element = PG_GETARG_INT32(1);
944 JsonbValue *v;
945
946 if (!JB_ROOT_IS_ARRAY(jb))
948
949 /* Handle negative subscript */
950 if (element < 0)
951 {
952 uint32 nelements = JB_ROOT_COUNT(jb);
953
954 if (pg_abs_s32(element) > nelements)
956 else
957 element += nelements;
958 }
959
961 if (v != NULL)
963
965}

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 983 of file jsonfuncs.c.

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

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 2208 of file jsonfuncs.c.

2209{
2210 return elements_worker_jsonb(fcinfo, "jsonb_array_elements", false);
2211}

References elements_worker_jsonb().

◆ jsonb_array_elements_text()

Datum jsonb_array_elements_text ( PG_FUNCTION_ARGS  )

Definition at line 2214 of file jsonfuncs.c.

2215{
2216 return elements_worker_jsonb(fcinfo, "jsonb_array_elements_text", true);
2217}

References elements_worker_jsonb().

◆ jsonb_array_length()

Datum jsonb_array_length ( PG_FUNCTION_ARGS  )

Definition at line 1878 of file jsonfuncs.c.

1879{
1881
1882 if (JB_ROOT_IS_SCALAR(jb))
1883 ereport(ERROR,
1885 errmsg("cannot get array length of a scalar")));
1886 else if (!JB_ROOT_IS_ARRAY(jb))
1887 ereport(ERROR,
1889 errmsg("cannot get array length of a non-array")));
1890
1892}

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 4623 of file jsonfuncs.c.

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

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 4661 of file jsonfuncs.c.

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

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 4711 of file jsonfuncs.c.

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

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 4795 of file jsonfuncs.c.

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

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 4965 of file jsonfuncs.c.

4966{
4967 Jsonb *in = PG_GETARG_JSONB_P(0);
4970 bool *path_nulls;
4971 int path_len;
4973 JsonbInState st = {0};
4974
4975 if (ARR_NDIM(path) > 1)
4976 ereport(ERROR,
4978 errmsg("wrong number of array subscripts")));
4979
4980 if (JB_ROOT_IS_SCALAR(in))
4981 ereport(ERROR,
4983 errmsg("cannot delete path in scalar")));
4984
4985 if (JB_ROOT_COUNT(in) == 0)
4987
4989
4990 if (path_len == 0)
4992
4993 it = JsonbIteratorInit(&in->root);
4994
4996 0, NULL, JB_PATH_DELETE);
4997
4999}

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 1956 of file jsonfuncs.c.

1957{
1958 return each_worker_jsonb(fcinfo, "jsonb_each", false);
1959}

References each_worker_jsonb().

◆ jsonb_each_text()

Datum jsonb_each_text ( PG_FUNCTION_ARGS  )

Definition at line 1968 of file jsonfuncs.c.

1969{
1970 return each_worker_jsonb(fcinfo, "jsonb_each_text", true);
1971}

References each_worker_jsonb().

◆ jsonb_extract_path()

Datum jsonb_extract_path ( PG_FUNCTION_ARGS  )

Definition at line 1491 of file jsonfuncs.c.

1492{
1493 return get_jsonb_path_all(fcinfo, false);
1494}

References get_jsonb_path_all().

◆ jsonb_extract_path_text()

Datum jsonb_extract_path_text ( PG_FUNCTION_ARGS  )

Definition at line 1497 of file jsonfuncs.c.

1498{
1499 return get_jsonb_path_all(fcinfo, true);
1500}

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 1534 of file jsonfuncs.c.

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

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 571 of file jsonfuncs.c.

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

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 2464 of file jsonfuncs.c.

2465{
2466 return populate_record_worker(fcinfo, "jsonb_populate_record",
2467 false, true, NULL);
2468}

References fb(), and populate_record_worker().

◆ jsonb_populate_record_valid()

Datum jsonb_populate_record_valid ( PG_FUNCTION_ARGS  )

Definition at line 2477 of file jsonfuncs.c.

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

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

◆ jsonb_populate_recordset()

Datum jsonb_populate_recordset ( PG_FUNCTION_ARGS  )

Definition at line 3974 of file jsonfuncs.c.

3975{
3976 return populate_recordset_worker(fcinfo, "jsonb_populate_recordset",
3977 false, true);
3978}

References populate_recordset_worker().

◆ jsonb_pretty()

◆ jsonb_set()

Datum jsonb_set ( PG_FUNCTION_ARGS  )

Definition at line 4856 of file jsonfuncs.c.

4857{
4858 Jsonb *in = PG_GETARG_JSONB_P(0);
4862 bool create = PG_GETARG_BOOL(3);
4864 bool *path_nulls;
4865 int path_len;
4867 JsonbInState st = {0};
4868
4870
4871 if (ARR_NDIM(path) > 1)
4872 ereport(ERROR,
4874 errmsg("wrong number of array subscripts")));
4875
4876 if (JB_ROOT_IS_SCALAR(in))
4877 ereport(ERROR,
4879 errmsg("cannot set path in scalar")));
4880
4881 if (JB_ROOT_COUNT(in) == 0 && !create)
4883
4885
4886 if (path_len == 0)
4888
4889 it = JsonbIteratorInit(&in->root);
4890
4892 0, &newval, create ? JB_PATH_CREATE : JB_PATH_REPLACE);
4893
4895}

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 1682 of file jsonfuncs.c.

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

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 4902 of file jsonfuncs.c.

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

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 4542 of file jsonfuncs.c.

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

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 2488 of file jsonfuncs.c.

2489{
2490 return populate_record_worker(fcinfo, "jsonb_to_record",
2491 false, false, NULL);
2492}

References fb(), and populate_record_worker().

◆ jsonb_to_recordset()

Datum jsonb_to_recordset ( PG_FUNCTION_ARGS  )

Definition at line 3981 of file jsonfuncs.c.

3982{
3983 return populate_recordset_worker(fcinfo, "jsonb_to_recordset",
3984 false, false);
3985}

References populate_recordset_worker().

◆ JsonbValueAsText()

static text * JsonbValueAsText ( JsonbValue v)
static

Definition at line 1805 of file jsonfuncs.c.

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

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 2982 of file jsonfuncs.c.

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

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 543 of file jsonfuncs.c.

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

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 812 of file jsonfuncs.c.

813{
815
816 /* top level must be a json object */
817 if (_state->lex->lex_level == 0)
820 errmsg("cannot call %s on an array",
821 "json_object_keys")));
822
823 return JSON_SUCCESS;
824}

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 789 of file jsonfuncs.c.

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

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 827 of file jsonfuncs.c.

828{
830
831 /* top level must be a json object */
832 if (_state->lex->lex_level == 0)
835 errmsg("cannot call %s on a scalar",
836 "json_object_keys")));
837
838 return JSON_SUCCESS;
839}

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 5562 of file jsonfuncs.c.

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

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 522 of file jsonfuncs.c.

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

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 2915 of file jsonfuncs.c.

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

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 2668 of file jsonfuncs.c.

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

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 2560 of file jsonfuncs.c.

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

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 2590 of file jsonfuncs.c.

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

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 2825 of file jsonfuncs.c.

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

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 2618 of file jsonfuncs.c.

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

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 2710 of file jsonfuncs.c.

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

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 2692 of file jsonfuncs.c.

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

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 2645 of file jsonfuncs.c.

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

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 2510 of file jsonfuncs.c.

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

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 2753 of file jsonfuncs.c.

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

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 3058 of file jsonfuncs.c.

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

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 3217 of file jsonfuncs.c.

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

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 3520 of file jsonfuncs.c.

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

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 3406 of file jsonfuncs.c.

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

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 3699 of file jsonfuncs.c.

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

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 4268 of file jsonfuncs.c.

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

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 4283 of file jsonfuncs.c.

4284{
4285 /* nothing to do */
4286 return JSON_SUCCESS;
4287}

References JSON_SUCCESS.

Referenced by populate_recordset_worker().

◆ populate_recordset_object_end()

static JsonParseErrorType populate_recordset_object_end ( void state)
static

Definition at line 4245 of file jsonfuncs.c.

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

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 4330 of file jsonfuncs.c.

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

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 4307 of file jsonfuncs.c.

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

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 4215 of file jsonfuncs.c.

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

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 4002 of file jsonfuncs.c.

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

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 4290 of file jsonfuncs.c.

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

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 4041 of file jsonfuncs.c.

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

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 3125 of file jsonfuncs.c.

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

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 3251 of file jsonfuncs.c.

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

References elog, ERROR, fb(), fmgr_info_cxt(), Form_pg_type, 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 1704 of file jsonfuncs.c.

1705{
1707
1708 null.type = jbvNull;
1709
1710 while (num-- > 0)
1712}

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 1723 of file jsonfuncs.c.

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

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 680 of file jsonfuncs.c.

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

References Assert, errcontext, fb(), JsonLexContext::input, JsonLexContext::input_length, IS_HIGHBIT_SET, JSON_TOKEN_END, JsonLexContext::line_number, JsonLexContext::line_start, palloc(), pg_mblen_range(), 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 5176 of file jsonfuncs.c.

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

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 5392 of file jsonfuncs.c.

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

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 5254 of file jsonfuncs.c.

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

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 4460 of file jsonfuncs.c.

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

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 4420 of file jsonfuncs.c.

4421{
4423
4424 appendStringInfoCharMacro(_state->strval, ']');
4425
4426 return JSON_SUCCESS;
4427}

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 4410 of file jsonfuncs.c.

4411{
4413
4414 appendStringInfoCharMacro(_state->strval, '[');
4415
4416 return JSON_SUCCESS;
4417}

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 4400 of file jsonfuncs.c.

4401{
4403
4404 appendStringInfoCharMacro(_state->strval, '}');
4405
4406 return JSON_SUCCESS;
4407}

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 4430 of file jsonfuncs.c.

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

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 4390 of file jsonfuncs.c.

4391{
4393
4394 appendStringInfoCharMacro(_state->strval, '{');
4395
4396 return JSON_SUCCESS;
4397}

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 4482 of file jsonfuncs.c.

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

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 5818 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 5772 of file jsonfuncs.c.

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

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 5912 of file jsonfuncs.c.

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

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 5884 of file jsonfuncs.c.

5885{
5887
5888 appendStringInfoCharMacro(_state->strval, ']');
5889
5890 return JSON_SUCCESS;
5891}

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 5874 of file jsonfuncs.c.

5875{
5877
5878 appendStringInfoCharMacro(_state->strval, '[');
5879
5880 return JSON_SUCCESS;
5881}

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 5864 of file jsonfuncs.c.

5865{
5867
5868 appendStringInfoCharMacro(_state->strval, '}');
5869
5870 return JSON_SUCCESS;
5871}

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 5894 of file jsonfuncs.c.

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

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 5854 of file jsonfuncs.c.

5855{
5857
5858 appendStringInfoCharMacro(_state->strval, '{');
5859
5860 return JSON_SUCCESS;
5861}

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 5923 of file jsonfuncs.c.

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

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 3029 of file jsonfuncs.c.

3030{
3031 if (!io->tupdesc ||
3032 io->tupdesc->tdtypeid != io->base_typid ||
3033 io->tupdesc->tdtypmod != io->base_typmod)
3034 {
3036 io->base_typmod);
3038
3039 if (io->tupdesc)
3041
3042 /* copy tuple desc without constraints into cache memory context */
3044 io->tupdesc = CreateTupleDescCopy(tupdesc);
3046
3047 ReleaseTupleDesc(tupdesc);
3048 }
3049}

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().