PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
jsonfuncs.c File Reference
#include "postgres.h"
#include <limits.h>
#include "access/htup_details.h"
#include "catalog/pg_type.h"
#include "common/int.h"
#include "common/jsonapi.h"
#include "common/string.h"
#include "fmgr.h"
#include "funcapi.h"
#include "lib/stringinfo.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "nodes/miscnodes.h"
#include "parser/parse_coerce.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/hsearch.h"
#include "utils/json.h"
#include "utils/jsonb.h"
#include "utils/jsonfuncs.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
Include dependency graph for jsonfuncs.c:

Go to the source code of this file.

Data Structures

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

Macros

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

Typedefs

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

Enumerations

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

Functions

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

Macro Definition Documentation

◆ JB_PATH_CONSISTENT_POSITION

#define JB_PATH_CONSISTENT_POSITION   0x0040

Definition at line 52 of file jsonfuncs.c.

◆ JB_PATH_CREATE

#define JB_PATH_CREATE   0x0001

Definition at line 44 of file jsonfuncs.c.

◆ JB_PATH_CREATE_OR_INSERT

#define JB_PATH_CREATE_OR_INSERT    (JB_PATH_INSERT_BEFORE | JB_PATH_INSERT_AFTER | JB_PATH_CREATE)

Definition at line 49 of file jsonfuncs.c.

◆ JB_PATH_DELETE

#define JB_PATH_DELETE   0x0002

Definition at line 45 of file jsonfuncs.c.

◆ JB_PATH_FILL_GAPS

#define JB_PATH_FILL_GAPS   0x0020

Definition at line 51 of file jsonfuncs.c.

◆ JB_PATH_INSERT_AFTER

#define JB_PATH_INSERT_AFTER   0x0010

Definition at line 48 of file jsonfuncs.c.

◆ JB_PATH_INSERT_BEFORE

#define JB_PATH_INSERT_BEFORE   0x0008

Definition at line 47 of file jsonfuncs.c.

◆ JB_PATH_REPLACE

#define JB_PATH_REPLACE   0x0004

Definition at line 46 of file jsonfuncs.c.

◆ JsObjectFree

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

Definition at line 335 of file jsonfuncs.c.

◆ 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))
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1341

Definition at line 329 of file jsonfuncs.c.

◆ 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))
@ JSON_TOKEN_NULL
Definition: jsonapi.h:30
@ jbvNull
Definition: jsonb.h:228

Definition at line 320 of file jsonfuncs.c.

◆ JsValueIsString

#define JsValueIsString (   jsv)
Value:
((jsv)->is_json ? (jsv)->val.json.type == JSON_TOKEN_STRING \
: ((jsv)->val.jsonb && (jsv)->val.jsonb->type == jbvString))
@ JSON_TOKEN_STRING
Definition: jsonapi.h:20
@ jbvString
Definition: jsonb.h:229

Definition at line 325 of file jsonfuncs.c.

Typedef Documentation

◆ AlenState

typedef struct AlenState AlenState

◆ ArrayIOData

typedef struct ArrayIOData ArrayIOData

◆ ColumnIOData

typedef struct ColumnIOData ColumnIOData

Definition at line 162 of file jsonfuncs.c.

◆ CompositeIOData

◆ DomainIOData

typedef struct DomainIOData DomainIOData

◆ EachState

typedef struct EachState EachState

◆ ElementsState

typedef struct ElementsState ElementsState

◆ GetState

typedef struct GetState GetState

◆ IterateJsonStringValuesState

◆ JHashState

typedef struct JHashState JHashState

◆ JsObject

typedef struct JsObject JsObject

◆ JsonHashEntry

typedef struct JsonHashEntry JsonHashEntry

◆ JsValue

typedef struct JsValue JsValue

◆ OkeysState

typedef struct OkeysState OkeysState

◆ PopulateArrayContext

◆ PopulateArrayState

◆ PopulateRecordCache

◆ PopulateRecordsetState

◆ RecordIOData

typedef struct RecordIOData RecordIOData

Definition at line 163 of file jsonfuncs.c.

◆ ScalarIOData

typedef struct ScalarIOData ScalarIOData

◆ StripnullState

◆ TransformJsonStringValuesState

◆ TypeCat

typedef enum TypeCat TypeCat

Enumeration Type Documentation

◆ TypeCat

enum TypeCat
Enumerator
TYPECAT_SCALAR 
TYPECAT_ARRAY 
TYPECAT_COMPOSITE 
TYPECAT_COMPOSITE_DOMAIN 
TYPECAT_DOMAIN 

Definition at line 199 of file jsonfuncs.c.

200{
201 TYPECAT_SCALAR = 's',
202 TYPECAT_ARRAY = 'a',
203 TYPECAT_COMPOSITE = 'c',
205 TYPECAT_DOMAIN = 'd',
206} TypeCat;
TypeCat
Definition: jsonfuncs.c:200
@ TYPECAT_COMPOSITE
Definition: jsonfuncs.c:203
@ TYPECAT_SCALAR
Definition: jsonfuncs.c:201
@ TYPECAT_COMPOSITE_DOMAIN
Definition: jsonfuncs.c:204
@ TYPECAT_DOMAIN
Definition: jsonfuncs.c:205
@ TYPECAT_ARRAY
Definition: jsonfuncs.c:202

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{
1930 AlenState *_state = (AlenState *) state;
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}
@ JSON_SUCCESS
Definition: jsonapi.h:36
int count
Definition: jsonfuncs.c:105
JsonLexContext * lex
Definition: jsonfuncs.c:104
Definition: regguts.h:323

References AlenState::count, JSON_SUCCESS, AlenState::lex, and JsonLexContext::lex_level.

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{
1902 AlenState *_state = (AlenState *) state;
1903
1904 /* json structure check */
1905 if (_state->lex->lex_level == 0)
1906 ereport(ERROR,
1907 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1908 errmsg("cannot get array length of a non-array")));
1909
1910 return JSON_SUCCESS;
1911}
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149

References ereport, errcode(), errmsg(), ERROR, JSON_SUCCESS, AlenState::lex, and JsonLexContext::lex_level.

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{
1916 AlenState *_state = (AlenState *) state;
1917
1918 /* json structure check */
1919 if (_state->lex->lex_level == 0)
1920 ereport(ERROR,
1921 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1922 errmsg("cannot get array length of a scalar")));
1923
1924 return JSON_SUCCESS;
1925}

References ereport, errcode(), errmsg(), ERROR, JSON_SUCCESS, AlenState::lex, and JsonLexContext::lex_level.

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
3483 data->record_type = InvalidOid;
3484 data->record_typmod = 0;
3485 data->ncolumns = ncolumns;
3486 MemSet(data->columns, 0, sizeof(ColumnIOData) * ncolumns);
3487
3488 return data;
3489}
#define MemSet(start, val, len)
Definition: c.h:991
struct ColumnIOData ColumnIOData
Definition: jsonfuncs.c:162
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1181
const void * data
#define InvalidOid
Definition: postgres_ext.h:35

References data, InvalidOid, MemoryContextAlloc(), and MemSet.

Referenced by populate_record().

◆ each_array_start()

static JsonParseErrorType each_array_start ( void *  state)
static

Definition at line 2168 of file jsonfuncs.c.

2169{
2170 EachState *_state = (EachState *) state;
2171
2172 /* json structure check */
2173 if (_state->lex->lex_level == 0)
2174 ereport(ERROR,
2175 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2176 errmsg("cannot deconstruct an array as an object")));
2177
2178 return JSON_SUCCESS;
2179}
JsonLexContext * lex
Definition: jsonfuncs.c:111

References ereport, errcode(), errmsg(), ERROR, JSON_SUCCESS, EachState::lex, and JsonLexContext::lex_level.

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{
2122 EachState *_state = (EachState *) state;
2123 MemoryContext old_cxt;
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 */
2135 old_cxt = MemoryContextSwitchTo(_state->tmp_cxt);
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 {
2147 _state->next_scalar = false;
2148 }
2149 else
2150 {
2151 len = _state->lex->prev_token_terminator - _state->result_start;
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 */
2161 MemoryContextSwitchTo(old_cxt);
2162 MemoryContextReset(_state->tmp_cxt);
2163
2164 return JSON_SUCCESS;
2165}
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define CStringGetTextDatum(s)
Definition: builtins.h:97
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
const void size_t len
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
bool normalize_results
Definition: jsonfuncs.c:116
TupleDesc ret_tdesc
Definition: jsonfuncs.c:113
char * normalized_scalar
Definition: jsonfuncs.c:118
const char * result_start
Definition: jsonfuncs.c:115
Tuplestorestate * tuple_store
Definition: jsonfuncs.c:112
MemoryContext tmp_cxt
Definition: jsonfuncs.c:114
bool next_scalar
Definition: jsonfuncs.c:117
const char * prev_token_terminator
Definition: jsonapi.h:107
Definition: c.h:658
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
Definition: tuplestore.c:764
text * cstring_to_text_with_len(const char *s, int len)
Definition: varlena.c:204

References cstring_to_text_with_len(), CStringGetTextDatum, heap_form_tuple(), JSON_SUCCESS, len, EachState::lex, JsonLexContext::lex_level, MemoryContextReset(), MemoryContextSwitchTo(), EachState::next_scalar, EachState::normalize_results, EachState::normalized_scalar, PointerGetDatum(), JsonLexContext::prev_token_terminator, EachState::result_start, EachState::ret_tdesc, EachState::tmp_cxt, EachState::tuple_store, 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{
2100 EachState *_state = (EachState *) state;
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}
const char * token_start
Definition: jsonapi.h:105
JsonTokenType token_type
Definition: jsonapi.h:109

References JSON_SUCCESS, JSON_TOKEN_STRING, EachState::lex, JsonLexContext::lex_level, EachState::next_scalar, EachState::normalize_results, EachState::result_start, JsonLexContext::token_start, and JsonLexContext::token_type.

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{
2184 EachState *_state = (EachState *) state;
2185
2186 /* json structure check */
2187 if (_state->lex->lex_level == 0)
2188 ereport(ERROR,
2189 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
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}
#define token
Definition: indent_globs.h:126

References ereport, errcode(), errmsg(), ERROR, JSON_SUCCESS, EachState::lex, JsonLexContext::lex_level, EachState::next_scalar, EachState::normalized_scalar, 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
2066 state = palloc0(sizeof(EachState));
2067 sem = palloc0(sizeof(JsonSemAction));
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}
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_RETURN_NULL()
Definition: fmgr.h:345
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition: funcapi.c:76
#define MAT_SRF_BLESS
Definition: funcapi.h:297
void freeJsonLexContext(JsonLexContext *lex)
Definition: jsonapi.c:687
JsonLexContext * makeJsonLexContext(JsonLexContext *lex, text *json, bool need_escapes)
Definition: jsonfuncs.c:540
static JsonParseErrorType each_object_field_end(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:2120
static JsonParseErrorType each_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:2182
static JsonParseErrorType each_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:2098
static JsonParseErrorType each_array_start(void *state)
Definition: jsonfuncs.c:2168
#define pg_parse_json_or_ereport(lex, sem)
Definition: jsonfuncs.h:47
void * palloc0(Size size)
Definition: mcxt.c:1347
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
fmNodePtr resultinfo
Definition: fmgr.h:89
json_ofield_action object_field_start
Definition: jsonapi.h:158
json_scalar_action scalar
Definition: jsonapi.h:162
void * semstate
Definition: jsonapi.h:153
json_struct_action array_start
Definition: jsonapi.h:156
json_ofield_action object_field_end
Definition: jsonapi.h:159
TupleDesc setDesc
Definition: execnodes.h:359
Tuplestorestate * setResult
Definition: execnodes.h:358
static JsonSemAction sem

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, JsonSemAction::array_start, CurrentMemoryContext, each_array_start(), each_object_field_end(), each_object_field_start(), each_scalar(), freeJsonLexContext(), InitMaterializedSRF(), makeJsonLexContext(), MAT_SRF_BLESS, MemoryContextDelete(), JsonSemAction::object_field_end, JsonSemAction::object_field_start, palloc0(), 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{
1976 Jsonb *jb = PG_GETARG_JSONB_P(0);
1977 ReturnSetInfo *rsi;
1978 MemoryContext old_cxt,
1979 tmp_cxt;
1980 bool skipNested = false;
1981 JsonbIterator *it;
1982 JsonbValue v;
1984
1985 if (!JB_ROOT_IS_OBJECT(jb))
1986 ereport(ERROR,
1987 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
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
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) NULL;
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 */
2046 MemoryContextSwitchTo(old_cxt);
2047 MemoryContextReset(tmp_cxt);
2048 }
2049 }
2050
2051 MemoryContextDelete(tmp_cxt);
2052
2054}
Assert(PointerIsAligned(start, uint64))
#define funcname
Definition: indent_codes.h:69
#define JB_ROOT_IS_OBJECT(jbp_)
Definition: jsonb.h:221
#define PG_GETARG_JSONB_P(x)
Definition: jsonb.h:391
JsonbIteratorToken
Definition: jsonb.h:21
@ WJB_KEY
Definition: jsonb.h:23
@ WJB_DONE
Definition: jsonb.h:22
JsonbIterator * JsonbIteratorInit(JsonbContainer *container)
Definition: jsonb_util.c:824
JsonbIteratorToken JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested)
Definition: jsonb_util.c:860
Jsonb * JsonbValueToJsonb(JsonbValue *val)
Definition: jsonb_util.c:92
static text * JsonbValueAsText(JsonbValue *v)
Definition: jsonfuncs.c:1805
enum jbvType type
Definition: jsonb.h:255
char * val
Definition: jsonb.h:264
Definition: jsonb.h:213
JsonbContainer root
Definition: jsonb.h:215
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:784

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert(), cstring_to_text_with_len(), CurrentMemoryContext, ereport, errcode(), errmsg(), ERROR, funcname, InitMaterializedSRF(), JB_ROOT_IS_OBJECT, jbvNull, JsonbIteratorInit(), JsonbIteratorNext(), JsonbValueAsText(), JsonbValueToJsonb(), sort-test::key, MAT_SRF_BLESS, MemoryContextDelete(), MemoryContextReset(), MemoryContextSwitchTo(), PG_GETARG_JSONB_P, PG_RETURN_NULL, PointerGetDatum(), FunctionCallInfoBaseData::resultinfo, Jsonb::root, 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{
2374 ElementsState *_state = (ElementsState *) state;
2375 MemoryContext old_cxt;
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 */
2387 old_cxt = MemoryContextSwitchTo(_state->tmp_cxt);
2388
2389 if (isnull && _state->normalize_results)
2390 {
2391 nulls[0] = true;
2392 values[0] = (Datum) NULL;
2393 }
2394 else if (_state->next_scalar)
2395 {
2397 _state->next_scalar = false;
2398 }
2399 else
2400 {
2401 len = _state->lex->prev_token_terminator - _state->result_start;
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 */
2411 MemoryContextSwitchTo(old_cxt);
2412 MemoryContextReset(_state->tmp_cxt);
2413
2414 return JSON_SUCCESS;
2415}
bool next_scalar
Definition: jsonfuncs.c:131
TupleDesc ret_tdesc
Definition: jsonfuncs.c:127
Tuplestorestate * tuple_store
Definition: jsonfuncs.c:126
bool normalize_results
Definition: jsonfuncs.c:130
MemoryContext tmp_cxt
Definition: jsonfuncs.c:128
JsonLexContext * lex
Definition: jsonfuncs.c:124
const char * result_start
Definition: jsonfuncs.c:129
char * normalized_scalar
Definition: jsonfuncs.c:132

References cstring_to_text_with_len(), CStringGetTextDatum, heap_form_tuple(), JSON_SUCCESS, len, ElementsState::lex, JsonLexContext::lex_level, MemoryContextReset(), MemoryContextSwitchTo(), ElementsState::next_scalar, ElementsState::normalize_results, ElementsState::normalized_scalar, PointerGetDatum(), JsonLexContext::prev_token_terminator, ElementsState::result_start, ElementsState::ret_tdesc, ElementsState::tmp_cxt, ElementsState::tuple_store, 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{
2352 ElementsState *_state = (ElementsState *) state;
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 JSON_SUCCESS, JSON_TOKEN_STRING, ElementsState::lex, JsonLexContext::lex_level, ElementsState::next_scalar, ElementsState::normalize_results, ElementsState::result_start, JsonLexContext::token_start, and JsonLexContext::token_type.

Referenced by elements_worker().

◆ elements_object_start()

static JsonParseErrorType elements_object_start ( void *  state)
static

Definition at line 2418 of file jsonfuncs.c.

2419{
2420 ElementsState *_state = (ElementsState *) state;
2421
2422 /* json structure check */
2423 if (_state->lex->lex_level == 0)
2424 ereport(ERROR,
2425 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2426 errmsg("cannot call %s on a non-array",
2427 _state->function_name)));
2428
2429 return JSON_SUCCESS;
2430}
const char * function_name
Definition: jsonfuncs.c:125

References ereport, errcode(), errmsg(), ERROR, ElementsState::function_name, JSON_SUCCESS, ElementsState::lex, and JsonLexContext::lex_level.

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{
2435 ElementsState *_state = (ElementsState *) state;
2436
2437 /* json structure check */
2438 if (_state->lex->lex_level == 0)
2439 ereport(ERROR,
2440 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
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, ElementsState::function_name, JSON_SUCCESS, ElementsState::lex, JsonLexContext::lex_level, ElementsState::next_scalar, ElementsState::normalized_scalar, 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
2319 state = palloc0(sizeof(ElementsState));
2320 sem = palloc0(sizeof(JsonSemAction));
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}
#define MAT_SRF_USE_EXPECTED_DESC
Definition: funcapi.h:296
static JsonParseErrorType elements_object_start(void *state)
Definition: jsonfuncs.c:2418
static JsonParseErrorType elements_array_element_end(void *state, bool isnull)
Definition: jsonfuncs.c:2372
static JsonParseErrorType elements_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:2433
static JsonParseErrorType elements_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:2350
json_struct_action object_start
Definition: jsonapi.h:154
json_aelem_action array_element_start
Definition: jsonapi.h:160
json_aelem_action array_element_end
Definition: jsonapi.h:161

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(), freeJsonLexContext(), funcname, InitMaterializedSRF(), makeJsonLexContext(), MAT_SRF_BLESS, MAT_SRF_USE_EXPECTED_DESC, MemoryContextDelete(), JsonSemAction::object_start, palloc0(), 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{
2223 Jsonb *jb = PG_GETARG_JSONB_P(0);
2224 ReturnSetInfo *rsi;
2225 MemoryContext old_cxt,
2226 tmp_cxt;
2227 bool skipNested = false;
2228 JsonbIterator *it;
2229 JsonbValue v;
2231
2232 if (JB_ROOT_IS_SCALAR(jb))
2233 ereport(ERROR,
2234 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2235 errmsg("cannot extract elements from a scalar")));
2236 else if (!JB_ROOT_IS_ARRAY(jb))
2237 ereport(ERROR,
2238 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
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) NULL;
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 */
2285 MemoryContextSwitchTo(old_cxt);
2286 MemoryContextReset(tmp_cxt);
2287 }
2288 }
2289
2290 MemoryContextDelete(tmp_cxt);
2291
2293}
#define JB_ROOT_IS_ARRAY(jbp_)
Definition: jsonb.h:222
#define JB_ROOT_IS_SCALAR(jbp_)
Definition: jsonb.h:220
@ WJB_ELEM
Definition: jsonb.h:25

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, CurrentMemoryContext, ereport, errcode(), errmsg(), ERROR, 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, Jsonb::root, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, tuplestore_putvalues(), JsonbValue::type, val, values, WJB_DONE, and WJB_ELEM.

Referenced by jsonb_array_elements(), and jsonb_array_elements_text().

◆ get_array_element_end()

static JsonParseErrorType get_array_element_end ( void *  state,
bool  isnull 
)
static

Definition at line 1401 of file jsonfuncs.c.

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

References GetState::array_cur_index, cstring_to_text_with_len(), JSON_SUCCESS, len, GetState::lex, JsonLexContext::lex_level, GetState::normalize_results, GetState::path_indexes, GetState::pathok, JsonLexContext::prev_token_terminator, GetState::result_start, start, and GetState::tresult.

Referenced by get_worker().

◆ get_array_element_start()

static JsonParseErrorType get_array_element_start ( void *  state,
bool  isnull 
)
static

Definition at line 1353 of file jsonfuncs.c.

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

References GetState::array_cur_index, JSON_SUCCESS, JSON_TOKEN_STRING, GetState::lex, JsonLexContext::lex_level, GetState::next_scalar, GetState::normalize_results, GetState::path_indexes, GetState::pathok, GetState::result_start, JsonLexContext::token_start, JsonLexContext::token_type, and GetState::tresult.

Referenced by get_worker().

◆ get_array_end()

static JsonParseErrorType get_array_end ( void *  state)
static

Definition at line 1335 of file jsonfuncs.c.

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

References cstring_to_text_with_len(), JSON_SUCCESS, len, GetState::lex, JsonLexContext::lex_level, GetState::npath, JsonLexContext::prev_token_terminator, GetState::result_start, start, and GetState::tresult.

Referenced by get_worker().

◆ get_array_start()

static JsonParseErrorType get_array_start ( void *  state)
static

Definition at line 1295 of file jsonfuncs.c.

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

References GetState::array_cur_index, error(), json_count_array_elements(), json_errsave_error(), JSON_SUCCESS, GetState::lex, JsonLexContext::lex_level, GetState::npath, GetState::path_indexes, GetState::result_start, and JsonLexContext::token_start.

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
3827 state = palloc0(sizeof(JHashState));
3828 sem = palloc0(sizeof(JsonSemAction));
3829
3830 state->function_name = funcname;
3831 state->hash = tab;
3832 state->lex = makeJsonLexContextCstringLen(NULL, json, len,
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}
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:865
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
#define HASH_STRINGS
Definition: hsearch.h:96
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
JsonLexContext * makeJsonLexContextCstringLen(JsonLexContext *lex, const char *json, size_t len, int encoding, bool need_escapes)
Definition: jsonapi.c:392
static JsonParseErrorType hash_array_start(void *state)
Definition: jsonfuncs.c:3930
static JsonParseErrorType hash_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:3943
struct JsonHashEntry JsonHashEntry
bool pg_parse_json_or_errsave(JsonLexContext *lex, const JsonSemAction *sem, Node *escontext)
Definition: jsonfuncs.c:519
static JsonParseErrorType hash_object_field_end(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:3879
static JsonParseErrorType hash_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:3853
int GetDatabaseEncoding(void)
Definition: mbutils.c:1261
#define NAMEDATALEN
tree ctl
Definition: radixtree.h:1838
Definition: dynahash.c:220

References JsonSemAction::array_start, ctl, CurrentMemoryContext, 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(), pg_parse_json_or_errsave(), JsonSemAction::scalar, sem, and JsonSemAction::semstate.

Referenced by JsValueToJsObject().

◆ get_jsonb_path_all()

static Datum get_jsonb_path_all ( FunctionCallInfo  fcinfo,
bool  as_text 
)
static

Definition at line 1500 of file jsonfuncs.c.

1501{
1502 Jsonb *jb = PG_GETARG_JSONB_P(0);
1504 Datum *pathtext;
1505 bool *pathnulls;
1506 bool isnull;
1507 int npath;
1508 Datum res;
1509
1510 /*
1511 * If the array contains any null elements, return NULL, on the grounds
1512 * that you'd have gotten NULL if any RHS value were NULL in a nested
1513 * series of applications of the -> operator. (Note: because we also
1514 * return NULL for error cases such as no-such-field, this is true
1515 * regardless of the contents of the rest of the array.)
1516 */
1517 if (array_contains_nulls(path))
1519
1520 deconstruct_array_builtin(path, TEXTOID, &pathtext, &pathnulls, &npath);
1521
1522 res = jsonb_get_element(jb, pathtext, npath, &isnull, as_text);
1523
1524 if (isnull)
1526 else
1527 PG_RETURN_DATUM(res);
1528}
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:263
bool array_contains_nulls(ArrayType *array)
Definition: arrayfuncs.c:3767
void deconstruct_array_builtin(ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3697
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
Datum jsonb_get_element(Jsonb *jb, Datum *path, int npath, bool *isnull, bool as_text)
Definition: jsonfuncs.c:1531

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

Referenced by jsonb_extract_path(), and jsonb_extract_path_text().

◆ get_object_end()

static JsonParseErrorType get_object_end ( void *  state)
static

Definition at line 1179 of file jsonfuncs.c.

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

References cstring_to_text_with_len(), JSON_SUCCESS, len, GetState::lex, JsonLexContext::lex_level, GetState::npath, JsonLexContext::prev_token_terminator, GetState::result_start, start, and GetState::tresult.

Referenced by get_worker().

◆ get_object_field_end()

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

Definition at line 1244 of file jsonfuncs.c.

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

References cstring_to_text_with_len(), JSON_SUCCESS, len, GetState::lex, JsonLexContext::lex_level, GetState::normalize_results, GetState::path_names, GetState::pathok, JsonLexContext::prev_token_terminator, GetState::result_start, start, and GetState::tresult.

Referenced by get_worker().

◆ get_object_field_start()

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

Definition at line 1197 of file jsonfuncs.c.

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

References JSON_SUCCESS, JSON_TOKEN_STRING, GetState::lex, JsonLexContext::lex_level, GetState::next_scalar, GetState::normalize_results, GetState::path_names, GetState::pathok, GetState::result_start, JsonLexContext::token_start, JsonLexContext::token_type, and GetState::tresult.

Referenced by get_worker().

◆ get_object_start()

static JsonParseErrorType get_object_start ( void *  state)
static

Definition at line 1160 of file jsonfuncs.c.

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

References JSON_SUCCESS, GetState::lex, JsonLexContext::lex_level, GetState::npath, GetState::result_start, and JsonLexContext::token_start.

Referenced by get_worker().

◆ get_path_all()

static Datum get_path_all ( FunctionCallInfo  fcinfo,
bool  as_text 
)
static

Definition at line 1024 of file jsonfuncs.c.

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

References array_contains_nulls(), Assert(), deconstruct_array_builtin(), get_worker(), i, palloc(), 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,
3647 (errcode(ERRCODE_DATATYPE_MISMATCH),
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}
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1910
static void prepare_column_cache(ColumnIOData *column, Oid typid, int32 typmod, MemoryContext mcxt, bool need_scalar)
Definition: jsonfuncs.c:3251
TypeCat typcat
Definition: jsonfuncs.c:215
FmgrInfo * flinfo
Definition: fmgr.h:87
ColumnIOData c
Definition: jsonfuncs.c:240
MemoryContext fn_mcxt
Definition: jsonfuncs.c:241

References PopulateRecordCache::argtype, PopulateRecordCache::c, ereport, errcode(), errmsg(), ERROR, 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;
3667 MemoryContext old_cxt;
3668
3669 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
3670 ereport(ERROR,
3671 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
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 */
3687 old_cxt = MemoryContextSwitchTo(cache->fn_mcxt);
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;
3691 MemoryContextSwitchTo(old_cxt);
3692}
int errhint(const char *fmt,...)
Definition: elog.c:1318
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149
union ColumnIOData::@24 io
CompositeIOData composite
Definition: jsonfuncs.c:221
int32 base_typmod
Definition: jsonfuncs.c:184
TupleDesc tupdesc
Definition: jsonfuncs.c:181
int32 tdtypmod
Definition: tupdesc.h:139
Oid tdtypeid
Definition: tupdesc.h:138
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:495
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:245

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

Referenced by populate_record_worker(), and populate_recordset_worker().

◆ get_scalar()

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

Definition at line 1445 of file jsonfuncs.c.

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

References cstring_to_text(), cstring_to_text_with_len(), JsonLexContext::input, JSON_SUCCESS, JSON_TOKEN_NULL, JSON_TOKEN_STRING, len, GetState::lex, JsonLexContext::lex_level, GetState::next_scalar, GetState::normalize_results, GetState::npath, JsonLexContext::prev_token_terminator, start, and GetState::tresult.

Referenced by get_worker().

◆ get_worker()

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

Definition at line 1103 of file jsonfuncs.c.

1108{
1110 GetState *state = palloc0(sizeof(GetState));
1111
1112 Assert(npath >= 0);
1113
1114 state->lex = makeJsonLexContext(NULL, json, true);
1115
1116 /* is it "_as_text" variant? */
1117 state->normalize_results = normalize_results;
1118 state->npath = npath;
1119 state->path_names = tpath;
1120 state->path_indexes = ipath;
1121 state->pathok = palloc0(sizeof(bool) * npath);
1122 state->array_cur_index = palloc(sizeof(int) * npath);
1123
1124 if (npath > 0)
1125 state->pathok[0] = true;
1126
1127 sem->semstate = state;
1128
1129 /*
1130 * Not all variants need all the semantic routines. Only set the ones that
1131 * are actually needed for maximum efficiency.
1132 */
1134 if (npath == 0)
1135 {
1140 }
1141 if (tpath != NULL)
1142 {
1145 }
1146 if (ipath != NULL)
1147 {
1151 }
1152
1155
1156 return state->tresult;
1157}
static JsonParseErrorType get_array_element_end(void *state, bool isnull)
Definition: jsonfuncs.c:1401
static JsonParseErrorType get_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:1197
static JsonParseErrorType get_object_start(void *state)
Definition: jsonfuncs.c:1160
static JsonParseErrorType get_array_start(void *state)
Definition: jsonfuncs.c:1295
static JsonParseErrorType get_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:1445
static JsonParseErrorType get_object_end(void *state)
Definition: jsonfuncs.c:1179
static JsonParseErrorType get_object_field_end(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:1244
static JsonParseErrorType get_array_end(void *state)
Definition: jsonfuncs.c:1335
static JsonParseErrorType get_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:1353
json_struct_action array_end
Definition: jsonapi.h:157
json_struct_action object_end
Definition: jsonapi.h:155

References JsonSemAction::array_element_end, JsonSemAction::array_element_start, JsonSemAction::array_end, JsonSemAction::array_start, Assert(), 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, palloc(), palloc0(), 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{
3932 JHashState *_state = (JHashState *) state;
3933
3934 if (_state->lex->lex_level == 0)
3935 ereport(ERROR,
3936 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3937 errmsg("cannot call %s on an array", _state->function_name)));
3938
3939 return JSON_SUCCESS;
3940}
const char * function_name
Definition: jsonfuncs.c:139
JsonLexContext * lex
Definition: jsonfuncs.c:138

References ereport, errcode(), errmsg(), ERROR, JHashState::function_name, JSON_SUCCESS, JHashState::lex, and JsonLexContext::lex_level.

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{
3881 JHashState *_state = (JHashState *) state;
3882 JsonHashEntry *hashentry;
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}
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
@ HASH_ENTER
Definition: hsearch.h:114
char * saved_scalar
Definition: jsonfuncs.c:141
const char * save_json_start
Definition: jsonfuncs.c:142
JsonTokenType saved_token_type
Definition: jsonfuncs.c:143
HTAB * hash
Definition: jsonfuncs.c:140
char * val
Definition: jsonfuncs.c:150
JsonTokenType type
Definition: jsonfuncs.c:151

References Assert(), JHashState::hash, HASH_ENTER, hash_search(), JSON_SUCCESS, JSON_TOKEN_NULL, len, JHashState::lex, JsonLexContext::lex_level, NAMEDATALEN, palloc(), JsonLexContext::prev_token_terminator, JHashState::save_json_start, JHashState::saved_scalar, JHashState::saved_token_type, JsonHashEntry::type, JsonHashEntry::val, 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{
3855 JHashState *_state = (JHashState *) state;
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 ||
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}
@ JSON_TOKEN_OBJECT_START
Definition: jsonapi.h:22
@ JSON_TOKEN_ARRAY_START
Definition: jsonapi.h:24

References JSON_SUCCESS, JSON_TOKEN_ARRAY_START, JSON_TOKEN_OBJECT_START, JHashState::lex, JsonLexContext::lex_level, JHashState::save_json_start, JHashState::saved_token_type, JsonLexContext::token_start, and JsonLexContext::token_type.

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{
3945 JHashState *_state = (JHashState *) state;
3946
3947 if (_state->lex->lex_level == 0)
3948 ereport(ERROR,
3949 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
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, JHashState::function_name, JSON_SUCCESS, JHashState::lex, JsonLexContext::lex_level, JHashState::saved_scalar, JHashState::saved_token_type, and token.

Referenced by get_json_object_as_hash().

◆ iterate_json_values()

void iterate_json_values ( text json,
uint32  flags,
void *  action_state,
JsonIterateStringValuesAction  action 
)

Definition at line 5732 of file jsonfuncs.c.

5734{
5735 JsonLexContext lex;
5738
5739 state->lex = makeJsonLexContext(&lex, json, true);
5740 state->action = action;
5741 state->action_state = action_state;
5742 state->flags = flags;
5743
5744 sem->semstate = state;
5747
5749 freeJsonLexContext(&lex);
5750}
static JsonParseErrorType iterate_values_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:5785
static JsonParseErrorType iterate_values_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:5757

References generate_unaccent_rules::action, freeJsonLexContext(), iterate_values_object_field_start(), iterate_values_scalar(), makeJsonLexContext(), JsonSemAction::object_field_start, palloc0(), pg_parse_json_or_ereport, JsonSemAction::scalar, sem, and JsonSemAction::semstate.

Referenced by json_to_tsvector_worker().

◆ iterate_jsonb_values()

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

Definition at line 5664 of file jsonfuncs.c.

5666{
5667 JsonbIterator *it;
5668 JsonbValue v;
5670
5671 it = JsonbIteratorInit(&jb->root);
5672
5673 /*
5674 * Just recursively iterating over jsonb and call callback on all
5675 * corresponding elements
5676 */
5677 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
5678 {
5679 if (type == WJB_KEY)
5680 {
5681 if (flags & jtiKey)
5682 action(state, v.val.string.val, v.val.string.len);
5683
5684 continue;
5685 }
5686 else if (!(type == WJB_VALUE || type == WJB_ELEM))
5687 {
5688 /* do not call callback for composite JsonbValue */
5689 continue;
5690 }
5691
5692 /* JsonbValue is a value of object or element of array */
5693 switch (v.type)
5694 {
5695 case jbvString:
5696 if (flags & jtiString)
5697 action(state, v.val.string.val, v.val.string.len);
5698 break;
5699 case jbvNumeric:
5700 if (flags & jtiNumeric)
5701 {
5702 char *val;
5703
5705 NumericGetDatum(v.val.numeric)));
5706
5707 action(state, val, strlen(val));
5708 pfree(val);
5709 }
5710 break;
5711 case jbvBool:
5712 if (flags & jtiBool)
5713 {
5714 if (v.val.boolean)
5715 action(state, "true", 4);
5716 else
5717 action(state, "false", 5);
5718 }
5719 break;
5720 default:
5721 /* do not call callback for composite JsonbValue */
5722 break;
5723 }
5724 }
5725}
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:816
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:682
@ jbvNumeric
Definition: jsonb.h:230
@ jbvBool
Definition: jsonb.h:231
@ WJB_VALUE
Definition: jsonb.h:24
@ jtiKey
Definition: jsonfuncs.h:27
@ jtiNumeric
Definition: jsonfuncs.h:29
@ jtiBool
Definition: jsonfuncs.h:30
@ jtiString
Definition: jsonfuncs.h:28
void pfree(void *pointer)
Definition: mcxt.c:1524
static Datum NumericGetDatum(Numeric X)
Definition: numeric.h:73
static char * DatumGetCString(Datum X)
Definition: postgres.h:340
const char * type

References generate_unaccent_rules::action, DatumGetCString(), DirectFunctionCall1, jbvBool, jbvNumeric, jbvString, JsonbIteratorInit(), JsonbIteratorNext(), jtiBool, jtiKey, jtiNumeric, jtiString, numeric_out(), NumericGetDatum(), pfree(), Jsonb::root, 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 5785 of file jsonfuncs.c.

5786{
5788
5789 if (_state->flags & jtiKey)
5790 {
5791 char *val = pstrdup(fname);
5792
5793 _state->action(_state->action_state, val, strlen(val));
5794 }
5795
5796 return JSON_SUCCESS;
5797}
char * pstrdup(const char *in)
Definition: mcxt.c:1699
JsonIterateStringValuesAction action
Definition: jsonfuncs.c:68

References IterateJsonStringValuesState::action, IterateJsonStringValuesState::action_state, IterateJsonStringValuesState::flags, 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 5757 of file jsonfuncs.c.

5758{
5760
5761 switch (tokentype)
5762 {
5763 case JSON_TOKEN_STRING:
5764 if (_state->flags & jtiString)
5765 _state->action(_state->action_state, token, strlen(token));
5766 break;
5767 case JSON_TOKEN_NUMBER:
5768 if (_state->flags & jtiNumeric)
5769 _state->action(_state->action_state, token, strlen(token));
5770 break;
5771 case JSON_TOKEN_TRUE:
5772 case JSON_TOKEN_FALSE:
5773 if (_state->flags & jtiBool)
5774 _state->action(_state->action_state, token, strlen(token));
5775 break;
5776 default:
5777 /* do not call callback for any other token */
5778 break;
5779 }
5780
5781 return JSON_SUCCESS;
5782}
@ JSON_TOKEN_FALSE
Definition: jsonapi.h:29
@ JSON_TOKEN_TRUE
Definition: jsonapi.h:28
@ JSON_TOKEN_NUMBER
Definition: jsonapi.h:21

References IterateJsonStringValuesState::action, IterateJsonStringValuesState::action_state, IterateJsonStringValuesState::flags, 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 JsonbValue * IteratorConcat ( JsonbIterator **  it1,
JsonbIterator **  it2,
JsonbParseState **  state 
)
static

Definition at line 5076 of file jsonfuncs.c.

5078{
5079 JsonbValue v1,
5080 v2,
5081 *res = NULL;
5083 r2,
5084 rk1,
5085 rk2;
5086
5087 rk1 = JsonbIteratorNext(it1, &v1, false);
5088 rk2 = JsonbIteratorNext(it2, &v2, false);
5089
5090 /*
5091 * JsonbIteratorNext reports raw scalars as if they were single-element
5092 * arrays; hence we only need consider "object" and "array" cases here.
5093 */
5094 if (rk1 == WJB_BEGIN_OBJECT && rk2 == WJB_BEGIN_OBJECT)
5095 {
5096 /*
5097 * Both inputs are objects.
5098 *
5099 * Append all the tokens from v1 to res, except last WJB_END_OBJECT
5100 * (because res will not be finished yet).
5101 */
5102 pushJsonbValue(state, rk1, NULL);
5103 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_OBJECT)
5104 pushJsonbValue(state, r1, &v1);
5105
5106 /*
5107 * Append all the tokens from v2 to res, including last WJB_END_OBJECT
5108 * (the concatenation will be completed). Any duplicate keys will
5109 * automatically override the value from the first object.
5110 */
5111 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5112 res = pushJsonbValue(state, r2, r2 != WJB_END_OBJECT ? &v2 : NULL);
5113 }
5114 else if (rk1 == WJB_BEGIN_ARRAY && rk2 == WJB_BEGIN_ARRAY)
5115 {
5116 /*
5117 * Both inputs are arrays.
5118 */
5119 pushJsonbValue(state, rk1, NULL);
5120
5121 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_ARRAY)
5122 {
5123 Assert(r1 == WJB_ELEM);
5124 pushJsonbValue(state, r1, &v1);
5125 }
5126
5127 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_END_ARRAY)
5128 {
5129 Assert(r2 == WJB_ELEM);
5131 }
5132
5133 res = pushJsonbValue(state, WJB_END_ARRAY, NULL /* signal to sort */ );
5134 }
5135 else if (rk1 == WJB_BEGIN_OBJECT)
5136 {
5137 /*
5138 * We have object || array.
5139 */
5140 Assert(rk2 == WJB_BEGIN_ARRAY);
5141
5143
5145 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_DONE)
5146 pushJsonbValue(state, r1, r1 != WJB_END_OBJECT ? &v1 : NULL);
5147
5148 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5149 res = pushJsonbValue(state, r2, r2 != WJB_END_ARRAY ? &v2 : NULL);
5150 }
5151 else
5152 {
5153 /*
5154 * We have array || object.
5155 */
5156 Assert(rk1 == WJB_BEGIN_ARRAY);
5157 Assert(rk2 == WJB_BEGIN_OBJECT);
5158
5160
5161 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_ARRAY)
5162 pushJsonbValue(state, r1, &v1);
5163
5165 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5166 pushJsonbValue(state, r2, r2 != WJB_END_OBJECT ? &v2 : NULL);
5167
5168 res = pushJsonbValue(state, WJB_END_ARRAY, NULL);
5169 }
5170
5171 return res;
5172}
@ WJB_END_ARRAY
Definition: jsonb.h:27
@ WJB_END_OBJECT
Definition: jsonb.h:29
@ WJB_BEGIN_OBJECT
Definition: jsonb.h:28
@ WJB_BEGIN_ARRAY
Definition: jsonb.h:26
JsonbValue * pushJsonbValue(JsonbParseState **pstate, JsonbIteratorToken seq, JsonbValue *jbval)
Definition: jsonb_util.c:573

References Assert(), 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 {
3498 JsonHashEntry *hashentry = hash_search(obj->val.json_hash, field,
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 :
3511 getKeyJsonValueFromContainer(obj->val.jsonb_cont, field, strlen(field),
3512 NULL);
3513
3514 return jsv->val.jsonb != NULL;
3515 }
3516}
@ HASH_FIND
Definition: hsearch.h:113
JsonbValue * getKeyJsonValueFromContainer(JsonbContainer *container, const char *keyVal, int keyLen, JsonbValue *res)
Definition: jsonb_util.c:405
bool is_json
Definition: jsonfuncs.c:311
JsonbContainer * jsonb_cont
Definition: jsonfuncs.c:315
HTAB * json_hash
Definition: jsonfuncs.c:314
union JsObject::@27 val
const char * str
Definition: jsonfuncs.c:300
JsonbValue * jsonb
Definition: jsonfuncs.c:305
struct JsValue::@25::@26 json
int len
Definition: jsonfuncs.c:301
union JsValue::@25 val
JsonTokenType type
Definition: jsonfuncs.c:302
bool is_json
Definition: jsonfuncs.c:295

References getKeyJsonValueFromContainer(), HASH_FIND, hash_search(), JsValue::is_json, JsObject::is_json, JsValue::json, JsObject::json_hash, JSON_TOKEN_NULL, JsValue::jsonb, JsObject::jsonb_cont, JsValue::len, JsValue::str, JsonHashEntry::type, JsValue::type, JsonHashEntry::val, JsValue::val, and JsObject::val.

Referenced by populate_record().

◆ json_array_element()

Datum json_array_element ( PG_FUNCTION_ARGS  )

Definition at line 922 of file jsonfuncs.c.

923{
924 text *json = PG_GETARG_TEXT_PP(0);
925 int element = PG_GETARG_INT32(1);
926 text *result;
927
928 result = get_worker(json, NULL, &element, 1, false);
929
930 if (result != NULL)
931 PG_RETURN_TEXT_P(result);
932 else
934}
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
static chr element(struct vars *v, const chr *startp, const chr *endp)
Definition: regc_locale.c:376

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

◆ json_array_element_text()

Datum json_array_element_text ( PG_FUNCTION_ARGS  )

Definition at line 965 of file jsonfuncs.c.

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

References element(), 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}
static Datum elements_worker(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
Definition: jsonfuncs.c:2308

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

Datum json_array_length ( PG_FUNCTION_ARGS  )

Definition at line 1852 of file jsonfuncs.c.

1853{
1854 text *json = PG_GETARG_TEXT_PP(0);
1856 JsonLexContext lex;
1858
1859 state = palloc0(sizeof(AlenState));
1860 state->lex = makeJsonLexContext(&lex, json, false);
1861 /* palloc0 does this for us */
1862#if 0
1863 state->count = 0;
1864#endif
1865
1866 sem = palloc0(sizeof(JsonSemAction));
1867 sem->semstate = state;
1871
1873
1874 PG_RETURN_INT32(state->count);
1875}
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
static JsonParseErrorType alen_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:1914
static JsonParseErrorType alen_object_start(void *state)
Definition: jsonfuncs.c:1900
static JsonParseErrorType alen_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:1928

References alen_array_element_start(), alen_object_start(), alen_scalar(), JsonSemAction::array_element_start, makeJsonLexContext(), JsonSemAction::object_start, palloc0(), PG_GETARG_TEXT_PP, pg_parse_json_or_ereport, PG_RETURN_INT32, JsonSemAction::scalar, sem, and JsonSemAction::semstate.

◆ json_categorize_type()

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

Definition at line 5999 of file jsonfuncs.c.

6001{
6002 bool typisvarlena;
6003
6004 /* Look through any domain */
6005 typoid = getBaseType(typoid);
6006
6007 *outfuncoid = InvalidOid;
6008
6009 switch (typoid)
6010 {
6011 case BOOLOID:
6012 *outfuncoid = F_BOOLOUT;
6013 *tcategory = JSONTYPE_BOOL;
6014 break;
6015
6016 case INT2OID:
6017 case INT4OID:
6018 case INT8OID:
6019 case FLOAT4OID:
6020 case FLOAT8OID:
6021 case NUMERICOID:
6022 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6023 *tcategory = JSONTYPE_NUMERIC;
6024 break;
6025
6026 case DATEOID:
6027 *outfuncoid = F_DATE_OUT;
6028 *tcategory = JSONTYPE_DATE;
6029 break;
6030
6031 case TIMESTAMPOID:
6032 *outfuncoid = F_TIMESTAMP_OUT;
6033 *tcategory = JSONTYPE_TIMESTAMP;
6034 break;
6035
6036 case TIMESTAMPTZOID:
6037 *outfuncoid = F_TIMESTAMPTZ_OUT;
6038 *tcategory = JSONTYPE_TIMESTAMPTZ;
6039 break;
6040
6041 case JSONOID:
6042 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6043 *tcategory = JSONTYPE_JSON;
6044 break;
6045
6046 case JSONBOID:
6047 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6048 *tcategory = is_jsonb ? JSONTYPE_JSONB : JSONTYPE_JSON;
6049 break;
6050
6051 default:
6052 /* Check for arrays and composites */
6053 if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
6054 || typoid == ANYCOMPATIBLEARRAYOID || typoid == RECORDARRAYOID)
6055 {
6056 *outfuncoid = F_ARRAY_OUT;
6057 *tcategory = JSONTYPE_ARRAY;
6058 }
6059 else if (type_is_rowtype(typoid)) /* includes RECORDOID */
6060 {
6061 *outfuncoid = F_RECORD_OUT;
6062 *tcategory = JSONTYPE_COMPOSITE;
6063 }
6064 else
6065 {
6066 /*
6067 * It's probably the general case. But let's look for a cast
6068 * to json (note: not to jsonb even if is_jsonb is true), if
6069 * it's not built-in.
6070 */
6071 *tcategory = JSONTYPE_OTHER;
6072 if (typoid >= FirstNormalObjectId)
6073 {
6074 Oid castfunc;
6075 CoercionPathType ctype;
6076
6077 ctype = find_coercion_pathway(JSONOID, typoid,
6079 &castfunc);
6080 if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc))
6081 {
6082 *outfuncoid = castfunc;
6083 *tcategory = JSONTYPE_CAST;
6084 }
6085 else
6086 {
6087 /* non builtin type with no cast */
6088 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6089 }
6090 }
6091 else
6092 {
6093 /* any other builtin type */
6094 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6095 }
6096 }
6097 break;
6098 }
6099}
#define OidIsValid(objectId)
Definition: c.h:746
@ JSONTYPE_JSON
Definition: jsonfuncs.h:76
@ JSONTYPE_TIMESTAMP
Definition: jsonfuncs.h:74
@ JSONTYPE_NUMERIC
Definition: jsonfuncs.h:72
@ JSONTYPE_DATE
Definition: jsonfuncs.h:73
@ JSONTYPE_BOOL
Definition: jsonfuncs.h:71
@ JSONTYPE_OTHER
Definition: jsonfuncs.h:81
@ JSONTYPE_CAST
Definition: jsonfuncs.h:80
@ JSONTYPE_COMPOSITE
Definition: jsonfuncs.h:79
@ JSONTYPE_ARRAY
Definition: jsonfuncs.h:78
@ JSONTYPE_TIMESTAMPTZ
Definition: jsonfuncs.h:75
@ JSONTYPE_JSONB
Definition: jsonfuncs.h:77
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2899
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2795
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:3047
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2661
CoercionPathType find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, CoercionContext ccontext, Oid *funcid)
CoercionPathType
Definition: parse_coerce.h:25
@ COERCION_PATH_FUNC
Definition: parse_coerce.h:27
unsigned int Oid
Definition: postgres_ext.h:30
@ COERCION_EXPLICIT
Definition: primnodes.h:734
#define FirstNormalObjectId
Definition: transam.h:197

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

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

◆ json_each()

Datum json_each ( PG_FUNCTION_ARGS  )

Definition at line 1950 of file jsonfuncs.c.

1951{
1952 return each_worker(fcinfo, false);
1953}
static Datum each_worker(FunctionCallInfo fcinfo, bool as_text)
Definition: jsonfuncs.c:2058

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

643{
647 errsave(escontext,
648 (errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
649 errmsg("unsupported Unicode escape sequence"),
651 report_json_context(lex)));
652 else if (error == JSON_SEM_ACTION_FAILED)
653 {
654 /* semantic action function had better have reported something */
655 if (!SOFT_ERROR_OCCURRED(escontext))
656 elog(ERROR, "JSON semantic action function did not provide error information");
657 }
658 else
659 errsave(escontext,
660 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
661 errmsg("invalid input syntax for type %s", "json"),
663 report_json_context(lex)));
664}
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1231
#define errsave(context,...)
Definition: elog.h:262
#define elog(elevel,...)
Definition: elog.h:226
char * json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
Definition: jsonapi.c:2401
@ JSON_SEM_ACTION_FAILED
Definition: jsonapi.h:59
@ JSON_UNICODE_CODE_POINT_ZERO
Definition: jsonapi.h:53
@ JSON_UNICODE_UNTRANSLATABLE
Definition: jsonapi.h:56
@ JSON_UNICODE_HIGH_ESCAPE
Definition: jsonapi.h:55
static int report_json_context(JsonLexContext *lex)
Definition: jsonfuncs.c:677
#define SOFT_ERROR_OCCURRED(escontext)
Definition: miscnodes.h:53

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

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

◆ json_extract_path()

Datum json_extract_path ( PG_FUNCTION_ARGS  )

Definition at line 1009 of file jsonfuncs.c.

1010{
1011 return get_path_all(fcinfo, false);
1012}
static Datum get_path_all(FunctionCallInfo fcinfo, bool as_text)
Definition: jsonfuncs.c:1024

References get_path_all().

◆ json_extract_path_text()

Datum json_extract_path_text ( PG_FUNCTION_ARGS  )

Definition at line 1015 of file jsonfuncs.c.

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

References get_path_all().

◆ json_get_first_token()

JsonTokenType json_get_first_token ( text json,
bool  throw_error 
)

Definition at line 5972 of file jsonfuncs.c.

5973{
5974 JsonLexContext lex;
5975 JsonParseErrorType result;
5976
5977 makeJsonLexContext(&lex, json, false);
5978
5979 /* Lex exactly one token from the input and check its type. */
5980 result = json_lex(&lex);
5981
5982 if (result == JSON_SUCCESS)
5983 return lex.token_type;
5984
5985 if (throw_error)
5986 json_errsave_error(result, &lex, NULL);
5987
5988 return JSON_TOKEN_INVALID; /* invalid json */
5989}
JsonParseErrorType json_lex(JsonLexContext *lex)
Definition: jsonapi.c:1588
@ JSON_TOKEN_INVALID
Definition: jsonapi.h:19

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

Referenced by ExecEvalJsonIsPredicate().

◆ json_object_field()

Datum json_object_field ( PG_FUNCTION_ARGS  )

Definition at line 846 of file jsonfuncs.c.

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

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

◆ json_object_field_text()

Datum json_object_field_text ( PG_FUNCTION_ARGS  )

Definition at line 884 of file jsonfuncs.c.

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

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

◆ json_object_keys()

Datum json_object_keys ( PG_FUNCTION_ARGS  )

Definition at line 732 of file jsonfuncs.c.

733{
734 FuncCallContext *funcctx;
736
737 if (SRF_IS_FIRSTCALL())
738 {
739 text *json = PG_GETARG_TEXT_PP(0);
740 JsonLexContext lex;
742 MemoryContext oldcontext;
743
744 funcctx = SRF_FIRSTCALL_INIT();
745 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
746
747 state = palloc(sizeof(OkeysState));
748 sem = palloc0(sizeof(JsonSemAction));
749
750 state->lex = makeJsonLexContext(&lex, json, true);
751 state->result_size = 256;
752 state->result_count = 0;
753 state->sent_count = 0;
754 state->result = palloc(256 * sizeof(char *));
755
756 sem->semstate = state;
760 /* remainder are all NULL, courtesy of palloc0 above */
761
763 /* keys are now in state->result */
764
765 freeJsonLexContext(&lex);
766 pfree(sem);
767
768 MemoryContextSwitchTo(oldcontext);
769 funcctx->user_fctx = state;
770 }
771
772 funcctx = SRF_PERCALL_SETUP();
773 state = (OkeysState *) funcctx->user_fctx;
774
775 if (state->sent_count < state->result_count)
776 {
777 char *nxt = state->result[state->sent_count++];
778
780 }
781
782 SRF_RETURN_DONE(funcctx);
783}
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:308
#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
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
static JsonParseErrorType okeys_array_start(void *state)
Definition: jsonfuncs.c:809
static JsonParseErrorType okeys_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:786
static JsonParseErrorType okeys_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:824
void * user_fctx
Definition: funcapi.h:82
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101

References JsonSemAction::array_start, CStringGetTextDatum, freeJsonLexContext(), if(), makeJsonLexContext(), MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, JsonSemAction::object_field_start, okeys_array_start(), okeys_object_field_start(), okeys_scalar(), palloc(), palloc0(), 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, SRF_RETURN_NEXT, and FuncCallContext::user_fctx.

◆ 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}
static Datum populate_record_worker(FunctionCallInfo fcinfo, const char *funcname, bool is_json, bool have_record_arg, Node *escontext)
Definition: jsonfuncs.c:3699

References 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}
static Datum populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname, bool is_json, bool have_record_arg)
Definition: jsonfuncs.c:4041

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};
3352 JsonbValue jbv;
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 {
3380 char *str = JsonbUnquote(DatumGetJsonbP(json_val));
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}
#define VARHDRSZ
Definition: c.h:663
#define DatumGetTextPP(X)
Definition: fmgr.h:292
const char * str
char * JsonbUnquote(Jsonb *jb)
Definition: jsonb.c:2229
@ jbvBinary
Definition: jsonb.h:236
static Jsonb * DatumGetJsonbP(Datum d)
Definition: jsonb.h:374
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
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1215
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define VARSIZE(PTR)
Definition: varatt.h:279
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317

References DatumGetJsonbP(), DatumGetTextPP, JsValue::is_json, jbvBinary, jbvString, JsValue::json, JSON_TOKEN_INVALID, JsValue::jsonb, JsonbUnquote(), JsValue::len, MemoryContextAllocZero(), PointerGetDatum(), populate_record_field(), Jsonb::root, JsValue::str, str, JsValue::type, JsonbValue::type, JsValue::val, 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;
4510 JsonLexContext lex;
4512
4513 state = palloc0(sizeof(StripnullState));
4514 sem = palloc0(sizeof(JsonSemAction));
4515
4516 state->lex = makeJsonLexContext(&lex, json, true);
4517 state->strval = makeStringInfo();
4518 state->skip_next_null = false;
4519 state->strip_in_arrays = strip_in_arrays;
4520
4521 sem->semstate = state;
4526 sem->scalar = sn_scalar;
4529
4531
4533 state->strval->len));
4534}
#define PG_NARGS()
Definition: fmgr.h:203
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
return false
Definition: isn.c:135
static JsonParseErrorType sn_object_end(void *state)
Definition: jsonfuncs.c:4400
static JsonParseErrorType sn_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:4460
static JsonParseErrorType sn_object_start(void *state)
Definition: jsonfuncs.c:4390
static JsonParseErrorType sn_array_start(void *state)
Definition: jsonfuncs.c:4410
static JsonParseErrorType sn_array_end(void *state)
Definition: jsonfuncs.c:4420
static JsonParseErrorType sn_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:4430
static JsonParseErrorType sn_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:4482
StringInfo makeStringInfo(void)
Definition: stringinfo.c:72

References JsonSemAction::array_element_start, JsonSemAction::array_end, JsonSemAction::array_start, cstring_to_text_with_len(), makeJsonLexContext(), makeStringInfo(), JsonSemAction::object_end, JsonSemAction::object_field_start, JsonSemAction::object_start, palloc0(), 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 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 937 of file jsonfuncs.c.

938{
939 Jsonb *jb = PG_GETARG_JSONB_P(0);
940 int element = PG_GETARG_INT32(1);
941 JsonbValue *v;
942
943 if (!JB_ROOT_IS_ARRAY(jb))
945
946 /* Handle negative subscript */
947 if (element < 0)
948 {
949 uint32 nelements = JB_ROOT_COUNT(jb);
950
951 if (pg_abs_s32(element) > nelements)
953 else
954 element += nelements;
955 }
956
958 if (v != NULL)
960
962}
uint32_t uint32
Definition: c.h:502
static uint32 pg_abs_s32(int32 a)
Definition: int.h:221
#define PG_RETURN_JSONB_P(x)
Definition: jsonb.h:393
#define JB_ROOT_COUNT(jbp_)
Definition: jsonb.h:219
JsonbValue * getIthJsonbValueFromContainer(JsonbContainer *container, uint32 i)
Definition: jsonb_util.c:475

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

◆ jsonb_array_element_text()

Datum jsonb_array_element_text ( PG_FUNCTION_ARGS  )

Definition at line 980 of file jsonfuncs.c.

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

References element(), 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, Jsonb::root, 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}
static Datum elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
Definition: jsonfuncs.c:2220

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{
1880 Jsonb *jb = PG_GETARG_JSONB_P(0);
1881
1882 if (JB_ROOT_IS_SCALAR(jb))
1883 ereport(ERROR,
1884 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1885 errmsg("cannot get array length of a scalar")));
1886 else if (!JB_ROOT_IS_ARRAY(jb))
1887 ereport(ERROR,
1888 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1889 errmsg("cannot get array length of a non-array")));
1890
1892}

References ereport, errcode(), errmsg(), ERROR, 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{
4625 Jsonb *jb1 = PG_GETARG_JSONB_P(0);
4626 Jsonb *jb2 = PG_GETARG_JSONB_P(1);
4627 JsonbParseState *state = NULL;
4628 JsonbValue *res;
4629 JsonbIterator *it1,
4630 *it2;
4631
4632 /*
4633 * If one of the jsonb is empty, just return the other if it's not scalar
4634 * and both are of the same kind. If it's a scalar or they are of
4635 * different kinds we need to perform the concatenation even if one is
4636 * empty.
4637 */
4638 if (JB_ROOT_IS_OBJECT(jb1) == JB_ROOT_IS_OBJECT(jb2))
4639 {
4640 if (JB_ROOT_COUNT(jb1) == 0 && !JB_ROOT_IS_SCALAR(jb2))
4641 PG_RETURN_JSONB_P(jb2);
4642 else if (JB_ROOT_COUNT(jb2) == 0 && !JB_ROOT_IS_SCALAR(jb1))
4643 PG_RETURN_JSONB_P(jb1);
4644 }
4645
4646 it1 = JsonbIteratorInit(&jb1->root);
4647 it2 = JsonbIteratorInit(&jb2->root);
4648
4649 res = IteratorConcat(&it1, &it2, &state);
4650
4651 Assert(res != NULL);
4652
4654}
static JsonbValue * IteratorConcat(JsonbIterator **it1, JsonbIterator **it2, JsonbParseState **state)
Definition: jsonfuncs.c:5076

References Assert(), IteratorConcat(), JB_ROOT_COUNT, JB_ROOT_IS_OBJECT, JB_ROOT_IS_SCALAR, JsonbIteratorInit(), JsonbValueToJsonb(), PG_GETARG_JSONB_P, PG_RETURN_JSONB_P, and Jsonb::root.

◆ jsonb_delete()

Datum jsonb_delete ( PG_FUNCTION_ARGS  )

Definition at line 4664 of file jsonfuncs.c.

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

References Assert(), ereport, errcode(), errmsg(), ERROR, JB_ROOT_COUNT, JB_ROOT_IS_SCALAR, jbvString, JsonbIteratorInit(), JsonbIteratorNext(), JsonbValueToJsonb(), sort-test::key, PG_GETARG_JSONB_P, PG_GETARG_TEXT_PP, PG_RETURN_JSONB_P, pushJsonbValue(), 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 4717 of file jsonfuncs.c.

4718{
4719 Jsonb *in = PG_GETARG_JSONB_P(0);
4721 Datum *keys_elems;
4722 bool *keys_nulls;
4723 int keys_len;
4724 JsonbParseState *state = NULL;
4725 JsonbIterator *it;
4726 JsonbValue v,
4727 *res = NULL;
4728 bool skipNested = false;
4730
4731 if (ARR_NDIM(keys) > 1)
4732 ereport(ERROR,
4733 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4734 errmsg("wrong number of array subscripts")));
4735
4736 if (JB_ROOT_IS_SCALAR(in))
4737 ereport(ERROR,
4738 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4739 errmsg("cannot delete from scalar")));
4740
4741 if (JB_ROOT_COUNT(in) == 0)
4743
4744 deconstruct_array_builtin(keys, TEXTOID, &keys_elems, &keys_nulls, &keys_len);
4745
4746 if (keys_len == 0)
4748
4749 it = JsonbIteratorInit(&in->root);
4750
4751 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4752 {
4753 skipNested = true;
4754
4755 if ((r == WJB_ELEM || r == WJB_KEY) && v.type == jbvString)
4756 {
4757 int i;
4758 bool found = false;
4759
4760 for (i = 0; i < keys_len; i++)
4761 {
4762 char *keyptr;
4763 int keylen;
4764
4765 if (keys_nulls[i])
4766 continue;
4767
4768 /* We rely on the array elements not being toasted */
4769 keyptr = VARDATA_ANY(keys_elems[i]);
4770 keylen = VARSIZE_ANY_EXHDR(keys_elems[i]);
4771 if (keylen == v.val.string.len &&
4772 memcmp(keyptr, v.val.string.val, keylen) == 0)
4773 {
4774 found = true;
4775 break;
4776 }
4777 }
4778 if (found)
4779 {
4780 /* skip corresponding value as well */
4781 if (r == WJB_KEY)
4782 (void) JsonbIteratorNext(&it, &v, true);
4783
4784 continue;
4785 }
4786 }
4787
4788 res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4789 }
4790
4791 Assert(res != NULL);
4792
4794}
#define ARR_NDIM(a)
Definition: array.h:290

References ARR_NDIM, Assert(), deconstruct_array_builtin(), ereport, errcode(), errmsg(), ERROR, 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(), 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 4804 of file jsonfuncs.c.

4805{
4806 Jsonb *in = PG_GETARG_JSONB_P(0);
4807 int idx = PG_GETARG_INT32(1);
4808 JsonbParseState *state = NULL;
4809 JsonbIterator *it;
4810 uint32 i = 0,
4811 n;
4812 JsonbValue v,
4813 *res = NULL;
4815
4816 if (JB_ROOT_IS_SCALAR(in))
4817 ereport(ERROR,
4818 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4819 errmsg("cannot delete from scalar")));
4820
4821 if (JB_ROOT_IS_OBJECT(in))
4822 ereport(ERROR,
4823 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4824 errmsg("cannot delete from object using integer index")));
4825
4826 if (JB_ROOT_COUNT(in) == 0)
4828
4829 it = JsonbIteratorInit(&in->root);
4830
4831 r = JsonbIteratorNext(&it, &v, false);
4832 Assert(r == WJB_BEGIN_ARRAY);
4833 n = v.val.array.nElems;
4834
4835 if (idx < 0)
4836 {
4837 if (pg_abs_s32(idx) > n)
4838 idx = n;
4839 else
4840 idx = n + idx;
4841 }
4842
4843 if (idx >= n)
4845
4846 pushJsonbValue(&state, r, NULL);
4847
4848 while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
4849 {
4850 if (r == WJB_ELEM)
4851 {
4852 if (i++ == idx)
4853 continue;
4854 }
4855
4856 res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4857 }
4858
4859 Assert(res != NULL);
4860
4862}
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:262

References Assert(), ereport, errcode(), errmsg(), ERROR, 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(), 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 4984 of file jsonfuncs.c.

4985{
4986 Jsonb *in = PG_GETARG_JSONB_P(0);
4988 JsonbValue *res = NULL;
4989 Datum *path_elems;
4990 bool *path_nulls;
4991 int path_len;
4992 JsonbIterator *it;
4993 JsonbParseState *st = NULL;
4994
4995 if (ARR_NDIM(path) > 1)
4996 ereport(ERROR,
4997 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4998 errmsg("wrong number of array subscripts")));
4999
5000 if (JB_ROOT_IS_SCALAR(in))
5001 ereport(ERROR,
5002 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5003 errmsg("cannot delete path in scalar")));
5004
5005 if (JB_ROOT_COUNT(in) == 0)
5007
5008 deconstruct_array_builtin(path, TEXTOID, &path_elems, &path_nulls, &path_len);
5009
5010 if (path_len == 0)
5012
5013 it = JsonbIteratorInit(&in->root);
5014
5015 res = setPath(&it, path_elems, path_nulls, path_len, &st,
5016 0, NULL, JB_PATH_DELETE);
5017
5018 Assert(res != NULL);
5019
5021}
static JsonbValue * setPath(JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, JsonbParseState **st, int level, JsonbValue *newval, int op_type)
Definition: jsonfuncs.c:5204
#define JB_PATH_DELETE
Definition: jsonfuncs.c:45

References ARR_NDIM, Assert(), deconstruct_array_builtin(), ereport, errcode(), errmsg(), ERROR, JB_PATH_DELETE, JB_ROOT_COUNT, JB_ROOT_IS_SCALAR, JsonbIteratorInit(), JsonbValueToJsonb(), PG_GETARG_ARRAYTYPE_P, PG_GETARG_JSONB_P, PG_RETURN_JSONB_P, 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}
static Datum each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
Definition: jsonfuncs.c:1974

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

1489{
1490 return get_jsonb_path_all(fcinfo, false);
1491}
static Datum get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
Definition: jsonfuncs.c:1500

References get_jsonb_path_all().

◆ jsonb_extract_path_text()

Datum jsonb_extract_path_text ( PG_FUNCTION_ARGS  )

Definition at line 1494 of file jsonfuncs.c.

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

References get_jsonb_path_all().

◆ jsonb_get_element()

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

Definition at line 1531 of file jsonfuncs.c.

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

References Assert(), cstring_to_text(), DatumGetTextPP, elog, ERROR, 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(), Jsonb::root, strtoint(), TextDatumGetCString, JsonbValue::type, JsonbValue::val, VARDATA_ANY, VARSIZE, and VARSIZE_ANY_EXHDR.

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

◆ jsonb_insert()

Datum jsonb_insert ( PG_FUNCTION_ARGS  )

Definition at line 5027 of file jsonfuncs.c.

5028{
5029 Jsonb *in = PG_GETARG_JSONB_P(0);
5031 Jsonb *newjsonb = PG_GETARG_JSONB_P(2);
5033 bool after = PG_GETARG_BOOL(3);
5034 JsonbValue *res = NULL;
5035 Datum *path_elems;
5036 bool *path_nulls;
5037 int path_len;
5038 JsonbIterator *it;
5039 JsonbParseState *st = NULL;
5040
5041 JsonbToJsonbValue(newjsonb, &newval);
5042
5043 if (ARR_NDIM(path) > 1)
5044 ereport(ERROR,
5045 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
5046 errmsg("wrong number of array subscripts")));
5047
5048 if (JB_ROOT_IS_SCALAR(in))
5049 ereport(ERROR,
5050 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5051 errmsg("cannot set path in scalar")));
5052
5053 deconstruct_array_builtin(path, TEXTOID, &path_elems, &path_nulls, &path_len);
5054
5055 if (path_len == 0)
5057
5058 it = JsonbIteratorInit(&in->root);
5059
5060 res = setPath(&it, path_elems, path_nulls, path_len, &st, 0, &newval,
5062
5063 Assert(res != NULL);
5064
5066}
#define newval
void JsonbToJsonbValue(Jsonb *jsonb, JsonbValue *val)
Definition: jsonb_util.c:72
#define JB_PATH_INSERT_BEFORE
Definition: jsonfuncs.c:47
#define JB_PATH_INSERT_AFTER
Definition: jsonfuncs.c:48

References ARR_NDIM, Assert(), deconstruct_array_builtin(), ereport, errcode(), errmsg(), ERROR, JB_PATH_INSERT_AFTER, JB_PATH_INSERT_BEFORE, JB_ROOT_IS_SCALAR, JsonbIteratorInit(), JsonbToJsonbValue(), JsonbValueToJsonb(), newval, PG_GETARG_ARRAYTYPE_P, PG_GETARG_BOOL, PG_GETARG_JSONB_P, PG_RETURN_JSONB_P, Jsonb::root, and setPath().

◆ jsonb_object_field()

◆ jsonb_object_field_text()

◆ jsonb_object_keys()

Datum jsonb_object_keys ( PG_FUNCTION_ARGS  )

Definition at line 568 of file jsonfuncs.c.

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

References CStringGetTextDatum, ereport, errcode(), errmsg(), ERROR, if(), JB_ROOT_COUNT, JB_ROOT_IS_ARRAY, JB_ROOT_IS_SCALAR, JsonbIteratorInit(), JsonbIteratorNext(), MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, palloc(), PG_GETARG_JSONB_P, Jsonb::root, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, FuncCallContext::user_fctx, 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 populate_record_worker().

◆ jsonb_populate_record_valid()

Datum jsonb_populate_record_valid ( PG_FUNCTION_ARGS  )

Definition at line 2477 of file jsonfuncs.c.

2478{
2479 ErrorSaveContext escontext = {T_ErrorSaveContext};
2480
2481 (void) populate_record_worker(fcinfo, "jsonb_populate_record",
2482 false, true, (Node *) &escontext);
2483
2484 return BoolGetDatum(!escontext.error_occurred);
2485}
static Datum BoolGetDatum(bool X)
Definition: postgres.h:107
bool error_occurred
Definition: miscnodes.h:47
Definition: nodes.h:135

References BoolGetDatum(), ErrorSaveContext::error_occurred, 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()

Datum jsonb_pretty ( PG_FUNCTION_ARGS  )

Definition at line 4607 of file jsonfuncs.c.

4608{
4609 Jsonb *jb = PG_GETARG_JSONB_P(0);
4611
4613
4615}
char * JsonbToCStringIndent(StringInfo out, JsonbContainer *in, int estimated_len)
Definition: jsonb.c:482

References cstring_to_text_with_len(), JsonbToCStringIndent(), makeStringInfo(), PG_GETARG_JSONB_P, PG_RETURN_TEXT_P, Jsonb::root, str, and VARSIZE.

◆ jsonb_set()

Datum jsonb_set ( PG_FUNCTION_ARGS  )

Definition at line 4868 of file jsonfuncs.c.

4869{
4870 Jsonb *in = PG_GETARG_JSONB_P(0);
4872 Jsonb *newjsonb = PG_GETARG_JSONB_P(2);
4874 bool create = PG_GETARG_BOOL(3);
4875 JsonbValue *res = NULL;
4876 Datum *path_elems;
4877 bool *path_nulls;
4878 int path_len;
4879 JsonbIterator *it;
4880 JsonbParseState *st = NULL;
4881
4882 JsonbToJsonbValue(newjsonb, &newval);
4883
4884 if (ARR_NDIM(path) > 1)
4885 ereport(ERROR,
4886 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4887 errmsg("wrong number of array subscripts")));
4888
4889 if (JB_ROOT_IS_SCALAR(in))
4890 ereport(ERROR,
4891 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4892 errmsg("cannot set path in scalar")));
4893
4894 if (JB_ROOT_COUNT(in) == 0 && !create)
4896
4897 deconstruct_array_builtin(path, TEXTOID, &path_elems, &path_nulls, &path_len);
4898
4899 if (path_len == 0)
4901
4902 it = JsonbIteratorInit(&in->root);
4903
4904 res = setPath(&it, path_elems, path_nulls, path_len, &st,
4905 0, &newval, create ? JB_PATH_CREATE : JB_PATH_REPLACE);
4906
4907 Assert(res != NULL);
4908
4910}
#define JB_PATH_CREATE
Definition: jsonfuncs.c:44
#define JB_PATH_REPLACE
Definition: jsonfuncs.c:46

References ARR_NDIM, Assert(), deconstruct_array_builtin(), ereport, errcode(), errmsg(), ERROR, 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, Jsonb::root, and setPath().

Referenced by jsonb_set_lax().

◆ jsonb_set_element()

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

Definition at line 1679 of file jsonfuncs.c.

1681{
1682 JsonbValue *res;
1683 JsonbParseState *state = NULL;
1684 JsonbIterator *it;
1685 bool *path_nulls = palloc0(path_len * sizeof(bool));
1686
1687 if (newval->type == jbvArray && newval->val.array.rawScalar)
1688 *newval = newval->val.array.elems[0];
1689
1690 it = JsonbIteratorInit(&jb->root);
1691
1692 res = setPath(&it, path, path_nulls, path_len, &state, 0, newval,
1695
1696 pfree(path_nulls);
1697
1699}
@ jbvArray
Definition: jsonb.h:233
#define JB_PATH_CONSISTENT_POSITION
Definition: jsonfuncs.c:52
#define JB_PATH_FILL_GAPS
Definition: jsonfuncs.c:51

References JB_PATH_CONSISTENT_POSITION, JB_PATH_CREATE, JB_PATH_FILL_GAPS, jbvArray, JsonbIteratorInit(), JsonbValueToJsonb(), newval, palloc0(), pfree(), PG_RETURN_JSONB_P, Jsonb::root, and setPath().

Referenced by jsonb_subscript_assign().

◆ jsonb_set_lax()

Datum jsonb_set_lax ( PG_FUNCTION_ARGS  )

Definition at line 4917 of file jsonfuncs.c.

4918{
4919 /* Jsonb *in = PG_GETARG_JSONB_P(0); */
4920 /* ArrayType *path = PG_GETARG_ARRAYTYPE_P(1); */
4921 /* Jsonb *newval = PG_GETARG_JSONB_P(2); */
4922 /* bool create = PG_GETARG_BOOL(3); */
4923 text *handle_null;
4924 char *handle_val;
4925
4926 if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(3))
4928
4929 /* could happen if they pass in an explicit NULL */
4930 if (PG_ARGISNULL(4))
4931 ereport(ERROR,
4932 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4933 errmsg("null_value_treatment must be \"delete_key\", \"return_target\", \"use_json_null\", or \"raise_exception\"")));
4934
4935 /* if the new value isn't an SQL NULL just call jsonb_set */
4936 if (!PG_ARGISNULL(2))
4937 return jsonb_set(fcinfo);
4938
4939 handle_null = PG_GETARG_TEXT_P(4);
4940 handle_val = text_to_cstring(handle_null);
4941
4942 if (strcmp(handle_val, "raise_exception") == 0)
4943 {
4944 ereport(ERROR,
4945 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4946 errmsg("JSON value must not be null"),
4947 errdetail("Exception was raised because null_value_treatment is \"raise_exception\"."),
4948 errhint("To avoid, either change the null_value_treatment argument or ensure that an SQL NULL is not passed.")));
4949 return (Datum) 0; /* silence stupider compilers */
4950 }
4951 else if (strcmp(handle_val, "use_json_null") == 0)
4952 {
4953 Datum newval;
4954
4956
4957 fcinfo->args[2].value = newval;
4958 fcinfo->args[2].isnull = false;
4959 return jsonb_set(fcinfo);
4960 }
4961 else if (strcmp(handle_val, "delete_key") == 0)
4962 {
4963 return jsonb_delete_path(fcinfo);
4964 }
4965 else if (strcmp(handle_val, "return_target") == 0)
4966 {
4967 Jsonb *in = PG_GETARG_JSONB_P(0);
4968
4970 }
4971 else
4972 {
4973 ereport(ERROR,
4974 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4975 errmsg("null_value_treatment must be \"delete_key\", \"return_target\", \"use_json_null\", or \"raise_exception\"")));
4976 return (Datum) 0; /* silence stupider compilers */
4977 }
4978}
int errdetail(const char *fmt,...)
Definition: elog.c:1204
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define PG_GETARG_TEXT_P(n)
Definition: fmgr.h:336
Datum jsonb_in(PG_FUNCTION_ARGS)
Definition: jsonb.c:73
Datum jsonb_delete_path(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4984
Datum jsonb_set(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4868
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:355

References CStringGetDatum(), DirectFunctionCall1, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, 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 4540 of file jsonfuncs.c.

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

References Assert(), JB_ROOT_IS_SCALAR, jbvNull, JsonbIteratorInit(), JsonbIteratorNext(), JsonbValueToJsonb(), PG_GETARG_BOOL, PG_GETARG_JSONB_P, PG_NARGS, PG_RETURN_POINTER, pushJsonbValue(), Jsonb::root, 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 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
1828 return cstring_to_text(DatumGetCString(cstr));
1829 }
1830
1831 case jbvBinary:
1832 {
1833 StringInfoData jtext;
1834
1835 initStringInfo(&jtext);
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}
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97

References cstring_to_text(), cstring_to_text_with_len(), StringInfoData::data, DatumGetCString(), DirectFunctionCall1, elog, ERROR, initStringInfo(), jbvBinary, jbvBool, jbvNull, jbvNumeric, jbvString, JsonbToCString(), StringInfoData::len, 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 =
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
3011 is_scalar = IsAJsonbScalar(jbv) ||
3012 (jbv->type == jbvBinary &&
3013 JsonContainerIsScalar(jbv->val.binary.data));
3014 errsave(escontext,
3015 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
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}
static HTAB * get_json_object_as_hash(const char *json, int len, const char *funcname, Node *escontext)
Definition: jsonfuncs.c:3811

References Assert(), errcode(), errmsg(), errsave, get_json_object_as_hash(), JsValue::is_json, JsObject::is_json, IsAJsonbScalar, jbvBinary, JsValue::json, JsObject::json_hash, JsValue::jsonb, JsObject::jsonb_cont, JsonContainerIsObject, JsonContainerIsScalar, JsValue::len, SOFT_ERROR_OCCURRED, JsValue::str, JsonbValue::type, JsValue::val, JsObject::val, and JsonbValue::val.

Referenced by populate_composite().

◆ makeJsonLexContext()

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

Definition at line 540 of file jsonfuncs.c.

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

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

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

◆ okeys_array_start()

static JsonParseErrorType okeys_array_start ( void *  state)
static

Definition at line 809 of file jsonfuncs.c.

810{
811 OkeysState *_state = (OkeysState *) state;
812
813 /* top level must be a json object */
814 if (_state->lex->lex_level == 0)
816 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
817 errmsg("cannot call %s on an array",
818 "json_object_keys")));
819
820 return JSON_SUCCESS;
821}
JsonLexContext * lex
Definition: jsonfuncs.c:57

References ereport, errcode(), errmsg(), ERROR, JSON_SUCCESS, OkeysState::lex, and JsonLexContext::lex_level.

Referenced by json_object_keys().

◆ okeys_object_field_start()

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

Definition at line 786 of file jsonfuncs.c.

787{
788 OkeysState *_state = (OkeysState *) state;
789
790 /* only collecting keys for the top level object */
791 if (_state->lex->lex_level != 1)
792 return JSON_SUCCESS;
793
794 /* enlarge result array if necessary */
795 if (_state->result_count >= _state->result_size)
796 {
797 _state->result_size *= 2;
798 _state->result = (char **)
799 repalloc(_state->result, sizeof(char *) * _state->result_size);
800 }
801
802 /* save a copy of the field name */
803 _state->result[_state->result_count++] = pstrdup(fname);
804
805 return JSON_SUCCESS;
806}
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1544
int result_size
Definition: jsonfuncs.c:59
char ** result
Definition: jsonfuncs.c:58
int result_count
Definition: jsonfuncs.c:60

References JSON_SUCCESS, OkeysState::lex, JsonLexContext::lex_level, pstrdup(), repalloc(), OkeysState::result, OkeysState::result_count, and OkeysState::result_size.

Referenced by json_object_keys().

◆ okeys_scalar()

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

Definition at line 824 of file jsonfuncs.c.

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

References ereport, errcode(), errmsg(), ERROR, JSON_SUCCESS, OkeysState::lex, and JsonLexContext::lex_level.

Referenced by json_object_keys().

◆ parse_jsonb_index_flags()

uint32 parse_jsonb_index_flags ( Jsonb jb)

Definition at line 5596 of file jsonfuncs.c.

5597{
5598 JsonbIterator *it;
5599 JsonbValue v;
5601 uint32 flags = 0;
5602
5603 it = JsonbIteratorInit(&jb->root);
5604
5605 type = JsonbIteratorNext(&it, &v, false);
5606
5607 /*
5608 * We iterate over array (scalar internally is represented as array, so,
5609 * we will accept it too) to check all its elements. Flag names are
5610 * chosen the same as jsonb_typeof uses.
5611 */
5612 if (type != WJB_BEGIN_ARRAY)
5613 ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5614 errmsg("wrong flag type, only arrays and scalars are allowed")));
5615
5616 while ((type = JsonbIteratorNext(&it, &v, false)) == WJB_ELEM)
5617 {
5618 if (v.type != jbvString)
5619 ereport(ERROR,
5620 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5621 errmsg("flag array element is not a string"),
5622 errhint("Possible values are: \"string\", \"numeric\", \"boolean\", \"key\", and \"all\".")));
5623
5624 if (v.val.string.len == 3 &&
5625 pg_strncasecmp(v.val.string.val, "all", 3) == 0)
5626 flags |= jtiAll;
5627 else if (v.val.string.len == 3 &&
5628 pg_strncasecmp(v.val.string.val, "key", 3) == 0)
5629 flags |= jtiKey;
5630 else if (v.val.string.len == 6 &&
5631 pg_strncasecmp(v.val.string.val, "string", 6) == 0)
5632 flags |= jtiString;
5633 else if (v.val.string.len == 7 &&
5634 pg_strncasecmp(v.val.string.val, "numeric", 7) == 0)
5635 flags |= jtiNumeric;
5636 else if (v.val.string.len == 7 &&
5637 pg_strncasecmp(v.val.string.val, "boolean", 7) == 0)
5638 flags |= jtiBool;
5639 else
5640 ereport(ERROR,
5641 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5642 errmsg("wrong flag in flag array: \"%s\"",
5643 pnstrdup(v.val.string.val, v.val.string.len)),
5644 errhint("Possible values are: \"string\", \"numeric\", \"boolean\", \"key\", and \"all\".")));
5645 }
5646
5647 /* expect end of array now */
5648 if (type != WJB_END_ARRAY)
5649 elog(ERROR, "unexpected end of flag array");
5650
5651 /* get final WJB_DONE and free iterator */
5652 type = JsonbIteratorNext(&it, &v, false);
5653 if (type != WJB_DONE)
5654 elog(ERROR, "unexpected end of flag array");
5655
5656 return flags;
5657}
@ jtiAll
Definition: jsonfuncs.h:31
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1710
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
Definition: pgstrcasecmp.c:69

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

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

◆ pg_parse_json_or_errsave()

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

Definition at line 519 of file jsonfuncs.c.

521{
522 JsonParseErrorType result;
523
524 result = pg_parse_json(lex, sem);
525 if (result != JSON_SUCCESS)
526 {
527 json_errsave_error(result, lex, escontext);
528 return false;
529 }
530 return true;
531}
JsonParseErrorType pg_parse_json(JsonLexContext *lex, const JsonSemAction *sem)
Definition: jsonapi.c:744

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(sizeof(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}
Datum makeMdArrayResult(ArrayBuildState *astate, int ndims, int *dims, int *lbs, MemoryContext rcontext, bool release)
Definition: arrayfuncs.c:5452
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5293
static bool populate_array_json(PopulateArrayContext *ctx, const char *json, int len)
Definition: jsonfuncs.c:2789
static bool populate_array_dim_jsonb(PopulateArrayContext *ctx, JsonbValue *jbv, int ndim)
Definition: jsonfuncs.c:2825
Oid element_type
Definition: jsonfuncs.c:169
ArrayBuildState * astate
Definition: jsonfuncs.c:261
MemoryContext mcxt
Definition: jsonfuncs.c:264
ArrayIOData * aio
Definition: jsonfuncs.c:262
MemoryContext acxt
Definition: jsonfuncs.c:263
const char * colname
Definition: jsonfuncs.c:265

References PopulateArrayContext::acxt, PopulateArrayContext::aio, Assert(), PopulateArrayContext::astate, PopulateArrayContext::colname, CurrentMemoryContext, PopulateArrayContext::dims, ArrayIOData::element_type, PopulateArrayContext::escontext, i, initArrayResult(), JsValue::is_json, JsValue::json, JsValue::jsonb, JsValue::len, makeMdArrayResult(), PopulateArrayContext::mcxt, PopulateArrayContext::ndims, palloc(), pfree(), populate_array_dim_jsonb(), populate_array_json(), PopulateArrayContext::sizes, JsValue::str, and JsValue::val.

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}
static bool populate_array_check_dimension(PopulateArrayContext *ctx, int ndim)
Definition: jsonfuncs.c:2590
static bool populate_array_assign_ndims(PopulateArrayContext *ctx, int ndims)
Definition: jsonfuncs.c:2560

References 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(sizeof(int) * ndims);
2576 ctx->sizes = palloc0(sizeof(int) * ndims);
2577
2578 for (i = 0; i < ndims; i++)
2579 ctx->dims[i] = -1; /* dimensions are unknown yet */
2580
2581 return true;
2582}
static void populate_array_report_expected_array(PopulateArrayContext *ctx, int ndim)
Definition: jsonfuncs.c:2510

References Assert(), PopulateArrayContext::dims, PopulateArrayContext::escontext, i, PopulateArrayContext::ndims, palloc(), palloc0(), 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,
2598 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
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}
#define ereturn(context, dummy_value,...)
Definition: elog.h:278

References PopulateArrayContext::dims, ereturn, errcode(), errdetail(), errmsg(), PopulateArrayContext::escontext, 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;
2830 JsonbIterator *it;
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);
2850 Assert(tok == WJB_BEGIN_ARRAY);
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
2900 Assert(tok == WJB_END_ARRAY);
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}
static bool populate_array_element(PopulateArrayContext *ctx, int ndim, JsValue *jsv)
Definition: jsonfuncs.c:2618
void check_stack_depth(void)
Definition: stack_depth.c:95

References Assert(), check_stack_depth(), PopulateArrayContext::dims, PopulateArrayContext::escontext, JsValue::is_json, jbvBinary, JsValue::jsonb, 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, JsonbValue::type, JsValue::val, JsonbValue::val, 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),
2628 jsv, &element_isnull, ctx->escontext,
2629 false);
2630 /* Nothing to do on an error. */
2632 return false;
2633
2634 accumArrayResult(ctx->astate, element, element_isnull,
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}
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5350
int32 element_typmod
Definition: jsonfuncs.c:170
ColumnIOData * element_info
Definition: jsonfuncs.c:168

References accumArrayResult(), PopulateArrayContext::acxt, PopulateArrayContext::aio, Assert(), PopulateArrayContext::astate, element(), ArrayIOData::element_info, ArrayIOData::element_type, ArrayIOData::element_typmod, PopulateArrayContext::escontext, 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 {
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(), JsValue::is_json, JsValue::json, JSON_SEM_ACTION_FAILED, JSON_SUCCESS, JSON_TOKEN_NULL, JsValue::len, PopulateArrayContext::ndims, populate_array_element(), JsValue::str, JsValue::type, and JsValue::val.

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 JSON_SUCCESS.

Referenced by populate_array_json().

◆ populate_array_json()

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

Definition at line 2789 of file jsonfuncs.c.

2790{
2793
2794 state.lex = makeJsonLexContextCstringLen(NULL, json, len,
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}
static JsonParseErrorType populate_array_scalar(void *_state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:2753
static JsonParseErrorType populate_array_object_start(void *_state)
Definition: jsonfuncs.c:2645
static JsonParseErrorType populate_array_element_end(void *_state, bool isnull)
Definition: jsonfuncs.c:2710
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

References JsonSemAction::array_element_end, JsonSemAction::array_element_start, JsonSemAction::array_end, Assert(), PopulateArrayContext::dims, PopulateArrayContext::escontext, freeJsonLexContext(), GetDatabaseEncoding(), len, makeJsonLexContextCstringLen(), PopulateArrayContext::ndims, JsonSemAction::object_start, pg_parse_json_or_errsave(), populate_array_array_end(), populate_array_element_end(), populate_array_element_start(), populate_array_object_start(), populate_array_scalar(), JsonSemAction::scalar, sem, JsonSemAction::semstate, and SOFT_ERROR_OCCURRED.

Referenced by populate_array().

◆ 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(), 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,
2516 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2517 errmsg("expected JSON array"),
2518 errhint("See the value of key \"%s\".", ctx->colname)));
2519 else
2520 errsave(ctx->escontext,
2521 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
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,
2539 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
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,
2545 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2546 errmsg("expected JSON array"),
2547 errhint("See the array element %s.",
2548 indices.data)));
2549 return;
2550 }
2551}
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:145

References appendStringInfo(), Assert(), PopulateArrayContext::colname, StringInfoData::data, errcode(), errhint(), errmsg(), errsave, PopulateArrayContext::escontext, 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, 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}
bool domain_check_safe(Datum value, bool isnull, Oid domainType, void **extra, MemoryContext mcxt, Node *escontext)
Definition: domains.c:355
Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple)
Definition: execTuples.c:2413
static void update_cached_tupdesc(CompositeIOData *io, MemoryContext mcxt)
Definition: jsonfuncs.c:3029
static bool JsValueToJsObject(JsValue *jsv, JsObject *jso, Node *escontext)
Definition: jsonfuncs.c:2982
static HeapTupleHeader populate_record(TupleDesc tupdesc, RecordIOData **record_p, HeapTupleHeader defaultval, MemoryContext mcxt, JsObject *obj, Node *escontext)
Definition: jsonfuncs.c:3520
#define JsObjectFree(jso)
Definition: jsonfuncs.c:335
RecordIOData * record_io
Definition: jsonfuncs.c:180
void * domain_info
Definition: jsonfuncs.c:186

References CompositeIOData::base_typid, domain_check_safe(), CompositeIOData::domain_info, 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}
void * domain_info
Definition: jsonfuncs.c:195
int32 base_typmod
Definition: jsonfuncs.c:194
Oid base_typid
Definition: jsonfuncs.c:193
ColumnIOData * base_io
Definition: jsonfuncs.c:192

References Assert(), DomainIOData::base_io, DomainIOData::base_typid, DomainIOData::base_typmod, domain_check_safe(), DomainIOData::domain_info, 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 */
3566 tuple.t_len = HeapTupleHeaderGetDatumLength(defaultval);
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 {
3585 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
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}
#define NameStr(name)
Definition: c.h:717
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1346
static uint32 HeapTupleHeaderGetDatumLength(const HeapTupleHeaderData *tup)
Definition: htup_details.h:492
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition: itemptr.h:184
static RecordIOData * allocate_record_info(MemoryContext mcxt, int ncolumns)
Definition: jsonfuncs.c:3476
#define JsObjectIsEmpty(jso)
Definition: jsonfuncs.c:329
static bool JsObjectGetField(JsObject *obj, char *field, JsValue *jsv)
Definition: jsonfuncs.c:3492
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:202
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
ColumnIOData columns[FLEXIBLE_ARRAY_MEMBER]
Definition: hstore_io.c:829
Oid record_type
Definition: hstore_io.c:824
int32 record_typmod
Definition: hstore_io.c:825
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160

References allocate_record_info(), RecordIOData::columns, 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,
3459 DatumGetPointer(defaultval)
3460 ? DatumGetHeapTupleHeader(defaultval)
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}
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:295
#define JsValueIsString(jsv)
Definition: jsonfuncs.c:325
#define JsValueIsNull(jsv)
Definition: jsonfuncs.c:320
static Datum populate_array(ArrayIOData *aio, const char *colname, MemoryContext mcxt, JsValue *jsv, bool *isnull, Node *escontext)
Definition: jsonfuncs.c:2915
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
static Datum populate_scalar(ScalarIOData *io, Oid typid, int32 typmod, JsValue *jsv, bool *isnull, Node *escontext, bool omit_quotes)
Definition: jsonfuncs.c:3125
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 Pointer DatumGetPointer(Datum X)
Definition: postgres.h:317
int32 typmod
Definition: jsonfuncs.c:214
ScalarIOData scalar_io
Definition: jsonfuncs.c:216
ArrayIOData array
Definition: jsonfuncs.c:220
DomainIOData domain
Definition: jsonfuncs.c:222

References ColumnIOData::array, check_stack_depth(), ColumnIOData::composite, DatumGetHeapTupleHeader, DatumGetPointer(), ColumnIOData::domain, elog, ERROR, ColumnIOData::io, JsValueIsNull, JsValueIsString, populate_array(), populate_composite(), populate_domain(), populate_scalar(), prepare_column_cache(), ColumnIOData::scalar_io, ColumnIOData::typcat, TYPECAT_ARRAY, TYPECAT_COMPOSITE, TYPECAT_COMPOSITE_DOMAIN, TYPECAT_DOMAIN, TYPECAT_SCALAR, ColumnIOData::typid, and ColumnIOData::typmod.

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;
3706 Datum rettuple;
3707 bool isnull;
3708 JsonbValue jbv;
3709 MemoryContext fnmcxt = fcinfo->flinfo->fn_mcxt;
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 */
3763 if (PG_ARGISNULL(json_arg_num))
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 {
3775 text *json = PG_GETARG_TEXT_PP(json_arg_num);
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 {
3784 Jsonb *jb = PG_GETARG_JSONB_P(json_arg_num);
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
3800 PG_RETURN_DATUM(rettuple);
3801}
#define PG_GETARG_HEAPTUPLEHEADER(n)
Definition: fmgr.h:312
static int32 HeapTupleHeaderGetTypMod(const HeapTupleHeaderData *tup)
Definition: htup_details.h:516
static Oid HeapTupleHeaderGetTypeId(const HeapTupleHeaderData *tup)
Definition: htup_details.h:504
static void get_record_type_from_argument(FunctionCallInfo fcinfo, const char *funcname, PopulateRecordCache *cache)
Definition: jsonfuncs.c:3636
static void get_record_type_from_query(FunctionCallInfo fcinfo, const char *funcname, PopulateRecordCache *cache)
Definition: jsonfuncs.c:3662
void * fn_extra
Definition: fmgr.h:64
MemoryContext fn_mcxt
Definition: fmgr.h:65

References PopulateRecordCache::argtype, Assert(), CompositeIOData::base_typid, CompositeIOData::base_typmod, PopulateRecordCache::c, ColumnIOData::composite, 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, JsValue::is_json, jbvBinary, JsValue::json, JSON_TOKEN_INVALID, JsValue::jsonb, JsValue::len, 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(), Jsonb::root, SOFT_ERROR_OCCURRED, JsValue::str, JsValue::type, JsonbValue::type, JsValue::val, JsonbValue::val, 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 &&
4274 ereport(ERROR,
4275 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4276 errmsg("argument of %s must be an array of objects",
4277 _state->function_name)));
4278
4279 return JSON_SUCCESS;
4280}
JsonLexContext * lex
Definition: jsonfuncs.c:247
const char * function_name
Definition: jsonfuncs.c:248

References ereport, errcode(), errmsg(), ERROR, PopulateRecordsetState::function_name, JSON_SUCCESS, JSON_TOKEN_OBJECT_START, PopulateRecordsetState::lex, JsonLexContext::lex_level, and JsonLexContext::token_type.

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 */
4258 populate_recordset_record(_state, &obj);
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}
static void populate_recordset_record(PopulateRecordsetState *state, JsObject *obj)
Definition: jsonfuncs.c:4002

References hash_destroy(), JsObject::is_json, PopulateRecordsetState::json_hash, JsObject::json_hash, JSON_SUCCESS, PopulateRecordsetState::lex, JsonLexContext::lex_level, 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{
4333 JsonHashEntry *hashentry;
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}
const char * save_json_start
Definition: jsonfuncs.c:251
JsonTokenType saved_token_type
Definition: jsonfuncs.c:252

References Assert(), HASH_ENTER, hash_search(), PopulateRecordsetState::json_hash, JSON_SUCCESS, JSON_TOKEN_NULL, len, PopulateRecordsetState::lex, JsonLexContext::lex_level, NAMEDATALEN, palloc(), JsonLexContext::prev_token_terminator, PopulateRecordsetState::save_json_start, PopulateRecordsetState::saved_scalar, PopulateRecordsetState::saved_token_type, JsonHashEntry::type, JsonHashEntry::val, 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 ||
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 JSON_SUCCESS, JSON_TOKEN_ARRAY_START, JSON_TOKEN_OBJECT_START, PopulateRecordsetState::lex, JsonLexContext::lex_level, PopulateRecordsetState::save_json_start, PopulateRecordsetState::saved_token_type, JsonLexContext::token_start, and JsonLexContext::token_type.

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,
4224 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
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, PopulateRecordsetState::function_name, HASH_CONTEXT, hash_create(), HASH_ELEM, HASH_STRINGS, PopulateRecordsetState::json_hash, JSON_SUCCESS, PopulateRecordsetState::lex, JsonLexContext::lex_level, 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;
4005 HeapTupleHeader tuphead;
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 */
4012 tuphead = populate_record(cache->c.io.composite.tupdesc,
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)
4021 (void) domain_check_safe(HeapTupleHeaderGetDatum(tuphead), false,
4022 cache->argtype,
4023 &cache->c.io.composite.domain_info,
4024 cache->fn_mcxt,
4025 NULL);
4026
4027 /* ok, save into tuplestore */
4028 tuple.t_len = HeapTupleHeaderGetDatumLength(tuphead);
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, 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,
4296 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
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, PopulateRecordsetState::function_name, JSON_SUCCESS, PopulateRecordsetState::lex, JsonLexContext::lex_level, PopulateRecordsetState::saved_scalar, 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;
4046 MemoryContext old_cxt;
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,
4055 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4056 errmsg("set-valued function called in context that cannot accept a set")));
4057
4058 if (!(rsi->allowedModes & SFRM_Materialize))
4059 ereport(ERROR,
4060 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
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 */
4116 if (PG_ARGISNULL(json_arg_num))
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);
4132 MemoryContextSwitchTo(old_cxt);
4133
4134 state->function_name = funcname;
4135 state->cache = cache;
4136 state->rec = rec;
4137
4138 if (is_json)
4139 {
4140 text *json = PG_GETARG_TEXT_PP(json_arg_num);
4141 JsonLexContext lex;
4143
4144 sem = palloc0(sizeof(JsonSemAction));
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 {
4166 Jsonb *jb = PG_GETARG_JSONB_P(json_arg_num);
4167 JsonbIterator *it;
4168 JsonbValue v;
4169 bool skipNested = false;
4171
4172 if (JB_ROOT_IS_SCALAR(jb) || !JB_ROOT_IS_ARRAY(jb))
4173 ereport(ERROR,
4174 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
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,
4191 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
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}
@ SFRM_Materialize_Random
Definition: execnodes.h:337
@ SFRM_Materialize
Definition: execnodes.h:336
int work_mem
Definition: globals.c:131
static JsonParseErrorType populate_recordset_array_start(void *state)
Definition: jsonfuncs.c:4283
static JsonParseErrorType populate_recordset_object_start(void *state)
Definition: jsonfuncs.c:4215
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_recordset_object_end(void *state)
Definition: jsonfuncs.c:4245
static JsonParseErrorType populate_recordset_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:4268
static JsonParseErrorType populate_recordset_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:4290
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:275
SetFunctionReturnMode returnMode
Definition: execnodes.h:355
ExprContext * econtext
Definition: execnodes.h:351
int allowedModes
Definition: execnodes.h:353
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:330

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, 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(), if(), 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(), 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, Jsonb::root, 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) &&
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}
#define unconstify(underlying_type, expr)
Definition: c.h:1216
bool InputFunctionCallSafe(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod, fmNodePtr escontext, Datum *result)
Definition: fmgr.c:1585
void escape_json_with_len(StringInfo buf, const char *str, int len)
Definition: json.c:1631
void escape_json(StringInfo buf, const char *str)
Definition: json.c:1602
static Datum JsonbPGetDatum(const Jsonb *p)
Definition: jsonb.h:386
static char * buf
Definition: pg_test_fsync.c:72
Oid typioparam
Definition: jsonfuncs.c:157
FmgrInfo typiofunc
Definition: jsonfuncs.c:158

References Assert(), buf, DatumGetCString(), DirectFunctionCall1, elog, ERROR, escape_json(), escape_json_with_len(), initStringInfo(), InputFunctionCallSafe(), JsValue::is_json, jbvBinary, jbvBool, jbvNumeric, jbvString, JsValue::json, JSON_TOKEN_STRING, JsValue::jsonb, JsonbPGetDatum(), JsonbToCString(), JsonbValueToJsonb(), JsValue::len, len, numeric_out(), palloc(), pfree(), pnstrdup(), PointerGetDatum(), pstrdup(), Jsonb::root, JsValue::str, str, JsValue::type, JsonbValue::type, ScalarIOData::typiofunc, ScalarIOData::typioparam, unconstify, JsValue::val, 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
3263 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3264 if (!HeapTupleIsValid(tup))
3265 elog(ERROR, "cache lookup failed for type %u", typid);
3266
3267 type = (Form_pg_type) GETSTRUCT(tup);
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;
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
3333 ReleaseSysCache(tup);
3334}
int32_t int32
Definition: c.h:498
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:137
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:3014
char get_typtype(Oid typid)
Definition: lsyscache.c:2769
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2678
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221

References ColumnIOData::array, DomainIOData::base_io, CompositeIOData::base_typid, DomainIOData::base_typid, CompositeIOData::base_typmod, DomainIOData::base_typmod, ColumnIOData::composite, ColumnIOData::domain, CompositeIOData::domain_info, DomainIOData::domain_info, ArrayIOData::element_info, ArrayIOData::element_type, ArrayIOData::element_typmod, elog, ERROR, fmgr_info_cxt(), get_typtype(), getBaseTypeAndTypmod(), GETSTRUCT(), getTypeInputInfo(), HeapTupleIsValid, ColumnIOData::io, MemoryContextAllocZero(), ObjectIdGetDatum(), CompositeIOData::record_io, ReleaseSysCache(), ColumnIOData::scalar_io, SearchSysCache1(), CompositeIOData::tupdesc, ColumnIOData::typcat, type, TYPECAT_ARRAY, TYPECAT_COMPOSITE, TYPECAT_COMPOSITE_DOMAIN, TYPECAT_DOMAIN, TYPECAT_SCALAR, ColumnIOData::typid, ScalarIOData::typiofunc, ScalarIOData::typioparam, and ColumnIOData::typmod.

Referenced by get_record_type_from_argument(), and populate_record_field().

◆ push_null_elements()

static void push_null_elements ( JsonbParseState **  ps,
int  num 
)
static

Definition at line 1702 of file jsonfuncs.c.

1703{
1704 JsonbValue null;
1705
1706 null.type = jbvNull;
1707
1708 while (num-- > 0)
1709 pushJsonbValue(ps, WJB_ELEM, &null);
1710}
struct parser_state ps

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

Referenced by push_path(), and setPathArray().

◆ push_path()

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

Definition at line 1721 of file jsonfuncs.c.

1723{
1724 /*
1725 * tpath contains expected type of an empty jsonb created at each level
1726 * higher or equal than the current one, either jbvObject or jbvArray.
1727 * Since it contains only information about path slice from level to the
1728 * end, the access index must be normalized by level.
1729 */
1730 enum jbvType *tpath = palloc0((path_len - level) * sizeof(enum jbvType));
1731 JsonbValue newkey;
1732
1733 /*
1734 * Create first part of the chain with beginning tokens. For the current
1735 * level WJB_BEGIN_OBJECT/WJB_BEGIN_ARRAY was already created, so start
1736 * with the next one.
1737 */
1738 for (int i = level + 1; i < path_len; i++)
1739 {
1740 char *c,
1741 *badp;
1742 int lindex;
1743
1744 if (path_nulls[i])
1745 break;
1746
1747 /*
1748 * Try to convert to an integer to find out the expected type, object
1749 * or array.
1750 */
1751 c = TextDatumGetCString(path_elems[i]);
1752 errno = 0;
1753 lindex = strtoint(c, &badp, 10);
1754 if (badp == c || *badp != '\0' || errno != 0)
1755 {
1756 /* text, an object is expected */
1757 newkey.type = jbvString;
1758 newkey.val.string.val = c;
1759 newkey.val.string.len = strlen(c);
1760
1761 (void) pushJsonbValue(st, WJB_BEGIN_OBJECT, NULL);
1762 (void) pushJsonbValue(st, WJB_KEY, &newkey);
1763
1764 tpath[i - level] = jbvObject;
1765 }
1766 else
1767 {
1768 /* integer, an array is expected */
1769 (void) pushJsonbValue(st, WJB_BEGIN_ARRAY, NULL);
1770
1771 push_null_elements(st, lindex);
1772
1773 tpath[i - level] = jbvArray;
1774 }
1775 }
1776
1777 /* Insert an actual value for either an object or array */
1778 if (tpath[(path_len - level) - 1] == jbvArray)
1779 {
1780 (void) pushJsonbValue(st, WJB_ELEM, newval);
1781 }
1782 else
1783 (void) pushJsonbValue(st, WJB_VALUE, newval);
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)
1795 (void) pushJsonbValue(st, WJB_END_OBJECT, NULL);
1796 else
1797 (void) pushJsonbValue(st, WJB_END_ARRAY, NULL);
1798 }
1799}
jbvType
Definition: jsonb.h:226
@ jbvObject
Definition: jsonb.h:234
static void push_null_elements(JsonbParseState **ps, int num)
Definition: jsonfuncs.c:1702
char * c

References i, jbvArray, jbvObject, jbvString, newval, palloc0(), push_null_elements(), pushJsonbValue(), strtoint(), TextDatumGetCString, JsonbValue::type, JsonbValue::val, WJB_BEGIN_ARRAY, WJB_BEGIN_OBJECT, WJB_ELEM, WJB_END_ARRAY, WJB_END_OBJECT, WJB_KEY, and WJB_VALUE.

Referenced by setPathArray(), and setPathObject().

◆ report_json_context()

static int report_json_context ( JsonLexContext lex)
static

Definition at line 677 of file jsonfuncs.c.

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

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

Referenced by json_errsave_error().

◆ setPath()

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

Definition at line 5204 of file jsonfuncs.c.

5207{
5208 JsonbValue v;
5210 JsonbValue *res;
5211
5213
5214 if (path_nulls[level])
5215 ereport(ERROR,
5216 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5217 errmsg("path element at position %d is null",
5218 level + 1)));
5219
5220 r = JsonbIteratorNext(it, &v, false);
5221
5222 switch (r)
5223 {
5224 case WJB_BEGIN_ARRAY:
5225
5226 /*
5227 * If instructed complain about attempts to replace within a raw
5228 * scalar value. This happens even when current level is equal to
5229 * path_len, because the last path key should also correspond to
5230 * an object or an array, not raw scalar.
5231 */
5232 if ((op_type & JB_PATH_FILL_GAPS) && (level <= path_len - 1) &&
5233 v.val.array.rawScalar)
5234 ereport(ERROR,
5235 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5236 errmsg("cannot replace existing key"),
5237 errdetail("The path assumes key is a composite object, "
5238 "but it is a scalar value.")));
5239
5240 (void) pushJsonbValue(st, r, NULL);
5241 setPathArray(it, path_elems, path_nulls, path_len, st, level,
5242 newval, v.val.array.nElems, op_type);
5243 r = JsonbIteratorNext(it, &v, false);
5244 Assert(r == WJB_END_ARRAY);
5245 res = pushJsonbValue(st, r, NULL);
5246 break;
5247 case WJB_BEGIN_OBJECT:
5248 (void) pushJsonbValue(st, r, NULL);
5249 setPathObject(it, path_elems, path_nulls, path_len, st, level,
5250 newval, v.val.object.nPairs, op_type);
5251 r = JsonbIteratorNext(it, &v, true);
5252 Assert(r == WJB_END_OBJECT);
5253 res = pushJsonbValue(st, r, NULL);
5254 break;
5255 case WJB_ELEM:
5256 case WJB_VALUE:
5257
5258 /*
5259 * If instructed complain about attempts to replace within a
5260 * scalar value. This happens even when current level is equal to
5261 * path_len, because the last path key should also correspond to
5262 * an object or an array, not an element or value.
5263 */
5264 if ((op_type & JB_PATH_FILL_GAPS) && (level <= path_len - 1))
5265 ereport(ERROR,
5266 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5267 errmsg("cannot replace existing key"),
5268 errdetail("The path assumes key is a composite object, "
5269 "but it is a scalar value.")));
5270
5271 res = pushJsonbValue(st, r, &v);
5272 break;
5273 default:
5274 elog(ERROR, "unrecognized iterator result: %d", (int) r);
5275 res = NULL; /* keep compiler quiet */
5276 break;
5277 }
5278
5279 return res;
5280}
static void setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, JsonbParseState **st, int level, JsonbValue *newval, uint32 nelems, int op_type)
Definition: jsonfuncs.c:5425
static void setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, JsonbParseState **st, int level, JsonbValue *newval, uint32 npairs, int op_type)
Definition: jsonfuncs.c:5286

References Assert(), check_stack_depth(), elog, ereport, errcode(), errdetail(), errmsg(), ERROR, 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,
Datum path_elems,
bool *  path_nulls,
int  path_len,
JsonbParseState **  st,
int  level,
JsonbValue newval,
uint32  nelems,
int  op_type 
)
static

Definition at line 5425 of file jsonfuncs.c.

5428{
5429 JsonbValue v;
5430 int idx,
5431 i;
5432 bool done = false;
5433
5434 /* pick correct index */
5435 if (level < path_len && !path_nulls[level])
5436 {
5437 char *c = TextDatumGetCString(path_elems[level]);
5438 char *badp;
5439
5440 errno = 0;
5441 idx = strtoint(c, &badp, 10);
5442 if (badp == c || *badp != '\0' || errno != 0)
5443 ereport(ERROR,
5444 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
5445 errmsg("path element at position %d is not an integer: \"%s\"",
5446 level + 1, c)));
5447 }
5448 else
5449 idx = nelems;
5450
5451 if (idx < 0)
5452 {
5453 if (pg_abs_s32(idx) > nelems)
5454 {
5455 /*
5456 * If asked to keep elements position consistent, it's not allowed
5457 * to prepend the array.
5458 */
5459 if (op_type & JB_PATH_CONSISTENT_POSITION)
5460 ereport(ERROR,
5461 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5462 errmsg("path element at position %d is out of range: %d",
5463 level + 1, idx)));
5464 else
5465 idx = PG_INT32_MIN;
5466 }
5467 else
5468 idx = nelems + idx;
5469 }
5470
5471 /*
5472 * Filling the gaps means there are no limits on the positive index are
5473 * imposed, we can set any element. Otherwise limit the index by nelems.
5474 */
5475 if (!(op_type & JB_PATH_FILL_GAPS))
5476 {
5477 if (idx > 0 && idx > nelems)
5478 idx = nelems;
5479 }
5480
5481 /*
5482 * if we're creating, and idx == INT_MIN, we prepend the new value to the
5483 * array also if the array is empty - in which case we don't really care
5484 * what the idx value is
5485 */
5486 if ((idx == INT_MIN || nelems == 0) && (level == path_len - 1) &&
5487 (op_type & JB_PATH_CREATE_OR_INSERT))
5488 {
5489 Assert(newval != NULL);
5490
5491 if (op_type & JB_PATH_FILL_GAPS && nelems == 0 && idx > 0)
5493
5494 (void) pushJsonbValue(st, WJB_ELEM, newval);
5495
5496 done = true;
5497 }
5498
5499 /* iterate over the array elements */
5500 for (i = 0; i < nelems; i++)
5501 {
5503
5504 if (i == idx && level < path_len)
5505 {
5506 done = true;
5507
5508 if (level == path_len - 1)
5509 {
5510 r = JsonbIteratorNext(it, &v, true); /* skip */
5511
5512 if (op_type & (JB_PATH_INSERT_BEFORE | JB_PATH_CREATE))
5513 (void) pushJsonbValue(st, WJB_ELEM, newval);
5514
5515 /*
5516 * We should keep current value only in case of
5517 * JB_PATH_INSERT_BEFORE or JB_PATH_INSERT_AFTER because
5518 * otherwise it should be deleted or replaced
5519 */
5521 (void) pushJsonbValue(st, r, &v);
5522
5523 if (op_type & (JB_PATH_INSERT_AFTER | JB_PATH_REPLACE))
5524 (void) pushJsonbValue(st, WJB_ELEM, newval);
5525 }
5526 else
5527 (void) setPath(it, path_elems, path_nulls, path_len,
5528 st, level + 1, newval, op_type);
5529 }
5530 else
5531 {
5532 r = JsonbIteratorNext(it, &v, false);
5533
5534 (void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5535
5536 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5537 {
5538 int walking_level = 1;
5539
5540 while (walking_level != 0)
5541 {
5542 r = JsonbIteratorNext(it, &v, false);
5543
5544 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5545 ++walking_level;
5546 if (r == WJB_END_ARRAY || r == WJB_END_OBJECT)
5547 --walking_level;
5548
5549 (void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5550 }
5551 }
5552 }
5553 }
5554
5555 if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done && level == path_len - 1)
5556 {
5557 /*
5558 * If asked to fill the gaps, idx could be bigger than nelems, so
5559 * prepend the new element with nulls if that's the case.
5560 */
5561 if (op_type & JB_PATH_FILL_GAPS && idx > nelems)
5562 push_null_elements(st, idx - nelems);
5563
5564 (void) pushJsonbValue(st, WJB_ELEM, newval);
5565 done = true;
5566 }
5567
5568 /*--
5569 * If we got here there are only few possibilities:
5570 * - no target path was found, and an open array with some keys/values was
5571 * pushed into the state
5572 * - an array is empty, only WJB_BEGIN_ARRAY is pushed
5573 *
5574 * In both cases if instructed to create the path when not present,
5575 * generate the whole chain of empty objects and insert the new value
5576 * there.
5577 */
5578 if (!done && (op_type & JB_PATH_FILL_GAPS) && (level < path_len - 1))
5579 {
5580 if (idx > 0)
5581 push_null_elements(st, idx - nelems);
5582
5583 (void) push_path(st, level, path_elems, path_nulls,
5584 path_len, newval);
5585
5586 /* Result is closed with WJB_END_OBJECT outside of this function */
5587 }
5588}
#define PG_INT32_MIN
Definition: c.h:559
#define JB_PATH_CREATE_OR_INSERT
Definition: jsonfuncs.c:49
static void push_path(JsonbParseState **st, int level, Datum *path_elems, bool *path_nulls, int path_len, JsonbValue *newval)
Definition: jsonfuncs.c:1721

References Assert(), ereport, errcode(), errmsg(), ERROR, 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,
Datum path_elems,
bool *  path_nulls,
int  path_len,
JsonbParseState **  st,
int  level,
JsonbValue newval,
uint32  npairs,
int  op_type 
)
static

Definition at line 5286 of file jsonfuncs.c.

5289{
5290 text *pathelem = NULL;
5291 int i;
5292 JsonbValue k,
5293 v;
5294 bool done = false;
5295
5296 if (level >= path_len || path_nulls[level])
5297 done = true;
5298 else
5299 {
5300 /* The path Datum could be toasted, in which case we must detoast it */
5301 pathelem = DatumGetTextPP(path_elems[level]);
5302 }
5303
5304 /* empty object is a special case for create */
5305 if ((npairs == 0) && (op_type & JB_PATH_CREATE_OR_INSERT) &&
5306 (level == path_len - 1))
5307 {
5308 JsonbValue newkey;
5309
5310 newkey.type = jbvString;
5311 newkey.val.string.val = VARDATA_ANY(pathelem);
5312 newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
5313
5314 (void) pushJsonbValue(st, WJB_KEY, &newkey);
5315 (void) pushJsonbValue(st, WJB_VALUE, newval);
5316 }
5317
5318 for (i = 0; i < npairs; i++)
5319 {
5320 JsonbIteratorToken r = JsonbIteratorNext(it, &k, true);
5321
5322 Assert(r == WJB_KEY);
5323
5324 if (!done &&
5325 k.val.string.len == VARSIZE_ANY_EXHDR(pathelem) &&
5326 memcmp(k.val.string.val, VARDATA_ANY(pathelem),
5327 k.val.string.len) == 0)
5328 {
5329 done = true;
5330
5331 if (level == path_len - 1)
5332 {
5333 /*
5334 * called from jsonb_insert(), it forbids redefining an
5335 * existing value
5336 */
5338 ereport(ERROR,
5339 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5340 errmsg("cannot replace existing key"),
5341 errhint("Try using the function jsonb_set "
5342 "to replace key value.")));
5343
5344 r = JsonbIteratorNext(it, &v, true); /* skip value */
5345 if (!(op_type & JB_PATH_DELETE))
5346 {
5347 (void) pushJsonbValue(st, WJB_KEY, &k);
5348 (void) pushJsonbValue(st, WJB_VALUE, newval);
5349 }
5350 }
5351 else
5352 {
5353 (void) pushJsonbValue(st, r, &k);
5354 setPath(it, path_elems, path_nulls, path_len,
5355 st, level + 1, newval, op_type);
5356 }
5357 }
5358 else
5359 {
5360 if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done &&
5361 level == path_len - 1 && i == npairs - 1)
5362 {
5363 JsonbValue newkey;
5364
5365 newkey.type = jbvString;
5366 newkey.val.string.val = VARDATA_ANY(pathelem);
5367 newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
5368
5369 (void) pushJsonbValue(st, WJB_KEY, &newkey);
5370 (void) pushJsonbValue(st, WJB_VALUE, newval);
5371 }
5372
5373 (void) pushJsonbValue(st, r, &k);
5374 r = JsonbIteratorNext(it, &v, false);
5375 (void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5376 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5377 {
5378 int walking_level = 1;
5379
5380 while (walking_level != 0)
5381 {
5382 r = JsonbIteratorNext(it, &v, false);
5383
5384 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5385 ++walking_level;
5386 if (r == WJB_END_ARRAY || r == WJB_END_OBJECT)
5387 --walking_level;
5388
5389 (void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5390 }
5391 }
5392 }
5393 }
5394
5395 /*--
5396 * If we got here there are only few possibilities:
5397 * - no target path was found, and an open object with some keys/values was
5398 * pushed into the state
5399 * - an object is empty, only WJB_BEGIN_OBJECT is pushed
5400 *
5401 * In both cases if instructed to create the path when not present,
5402 * generate the whole chain of empty objects and insert the new value
5403 * there.
5404 */
5405 if (!done && (op_type & JB_PATH_FILL_GAPS) && (level < path_len - 1))
5406 {
5407 JsonbValue newkey;
5408
5409 newkey.type = jbvString;
5410 newkey.val.string.val = VARDATA_ANY(pathelem);
5411 newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
5412
5413 (void) pushJsonbValue(st, WJB_KEY, &newkey);
5414 (void) push_path(st, level, path_elems, path_nulls,
5415 path_len, newval);
5416
5417 /* Result is closed with WJB_END_OBJECT outside of this function */
5418 }
5419}

References Assert(), DatumGetTextPP, ereport, errcode(), errhint(), errmsg(), ERROR, 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{
4462 StripnullState *_state = (StripnullState *) state;
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}
#define appendStringInfoCharMacro(str, ch)
Definition: stringinfo.h:231
bool skip_next_null
Definition: jsonfuncs.c:288
bool strip_in_arrays
Definition: jsonfuncs.c:289
StringInfo strval
Definition: jsonfuncs.c:287

References appendStringInfoCharMacro, StringInfoData::data, JSON_SUCCESS, StringInfoData::len, StripnullState::skip_next_null, StripnullState::strip_in_arrays, and StripnullState::strval.

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{
4422 StripnullState *_state = (StripnullState *) state;
4423
4424 appendStringInfoCharMacro(_state->strval, ']');
4425
4426 return JSON_SUCCESS;
4427}

References appendStringInfoCharMacro, JSON_SUCCESS, and StripnullState::strval.

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{
4412 StripnullState *_state = (StripnullState *) state;
4413
4414 appendStringInfoCharMacro(_state->strval, '[');
4415
4416 return JSON_SUCCESS;
4417}

References appendStringInfoCharMacro, JSON_SUCCESS, and StripnullState::strval.

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{
4402 StripnullState *_state = (StripnullState *) state;
4403
4404 appendStringInfoCharMacro(_state->strval, '}');
4405
4406 return JSON_SUCCESS;
4407}

References appendStringInfoCharMacro, JSON_SUCCESS, and StripnullState::strval.

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{
4432 StripnullState *_state = (StripnullState *) state;
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, StringInfoData::data, escape_json(), JSON_SUCCESS, StringInfoData::len, StripnullState::skip_next_null, and StripnullState::strval.

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{
4392 StripnullState *_state = (StripnullState *) state;
4393
4394 appendStringInfoCharMacro(_state->strval, '{');
4395
4396 return JSON_SUCCESS;
4397}

References appendStringInfoCharMacro, JSON_SUCCESS, and StripnullState::strval.

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{
4484 StripnullState *_state = (StripnullState *) state;
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}
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:230

References appendStringInfoString(), Assert(), escape_json(), JSON_SUCCESS, JSON_TOKEN_NULL, JSON_TOKEN_STRING, StripnullState::skip_next_null, and StripnullState::strval.

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

5855{
5856 JsonLexContext lex;
5859
5860 state->lex = makeJsonLexContext(&lex, json, true);
5861 state->strval = makeStringInfo();
5862 state->action = transform_action;
5863 state->action_state = action_state;
5864
5865 sem->semstate = state;
5873
5875 freeJsonLexContext(&lex);
5876
5877 return cstring_to_text_with_len(state->strval->data, state->strval->len);
5878}
static JsonParseErrorType transform_string_values_array_start(void *state)
Definition: jsonfuncs.c:5906
static JsonParseErrorType transform_string_values_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:5926
static JsonParseErrorType transform_string_values_array_end(void *state)
Definition: jsonfuncs.c:5916
static JsonParseErrorType transform_string_values_object_end(void *state)
Definition: jsonfuncs.c:5896
static JsonParseErrorType transform_string_values_object_start(void *state)
Definition: jsonfuncs.c:5886
static JsonParseErrorType transform_string_values_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:5944
static JsonParseErrorType transform_string_values_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:5955

References JsonSemAction::array_element_start, JsonSemAction::array_end, JsonSemAction::array_start, cstring_to_text_with_len(), freeJsonLexContext(), makeJsonLexContext(), makeStringInfo(), JsonSemAction::object_end, JsonSemAction::object_field_start, JsonSemAction::object_start, palloc0(), 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 5806 of file jsonfuncs.c.

5808{
5809 JsonbIterator *it;
5810 JsonbValue v,
5811 *res = NULL;
5813 JsonbParseState *st = NULL;
5814 text *out;
5815 bool is_scalar = false;
5816
5817 it = JsonbIteratorInit(&jsonb->root);
5818 is_scalar = it->isScalar;
5819
5820 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
5821 {
5822 if ((type == WJB_VALUE || type == WJB_ELEM) && v.type == jbvString)
5823 {
5824 out = transform_action(action_state, v.val.string.val, v.val.string.len);
5825 /* out is probably not toasted, but let's be sure */
5826 out = pg_detoast_datum_packed(out);
5827 v.val.string.val = VARDATA_ANY(out);
5828 v.val.string.len = VARSIZE_ANY_EXHDR(out);
5829 res = pushJsonbValue(&st, type, type < WJB_BEGIN_ARRAY ? &v : NULL);
5830 }
5831 else
5832 {
5833 res = pushJsonbValue(&st, type, (type == WJB_KEY ||
5834 type == WJB_VALUE ||
5835 type == WJB_ELEM) ? &v : NULL);
5836 }
5837 }
5838
5839 if (res->type == jbvArray)
5840 res->val.array.rawScalar = is_scalar;
5841
5842 return JsonbValueToJsonb(res);
5843}
bool isScalar
Definition: jsonb.h:347

References JsonbIterator::isScalar, jbvArray, jbvString, JsonbIteratorInit(), JsonbIteratorNext(), JsonbValueToJsonb(), pg_detoast_datum_packed(), pushJsonbValue(), 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 5944 of file jsonfuncs.c.

5945{
5947
5948 if (_state->strval->data[_state->strval->len - 1] != '[')
5949 appendStringInfoCharMacro(_state->strval, ',');
5950
5951 return JSON_SUCCESS;
5952}

References appendStringInfoCharMacro, StringInfoData::data, JSON_SUCCESS, StringInfoData::len, and TransformJsonStringValuesState::strval.

Referenced by transform_json_string_values().

◆ transform_string_values_array_end()

static JsonParseErrorType transform_string_values_array_end ( void *  state)
static

◆ transform_string_values_array_start()

static JsonParseErrorType transform_string_values_array_start ( void *  state)
static

◆ transform_string_values_object_end()

static JsonParseErrorType transform_string_values_object_end ( void *  state)
static

◆ transform_string_values_object_field_start()

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

Definition at line 5926 of file jsonfuncs.c.

5927{
5929
5930 if (_state->strval->data[_state->strval->len - 1] != '{')
5931 appendStringInfoCharMacro(_state->strval, ',');
5932
5933 /*
5934 * Unfortunately we don't have the quoted and escaped string any more, so
5935 * we have to re-escape it.
5936 */
5937 escape_json(_state->strval, fname);
5938 appendStringInfoCharMacro(_state->strval, ':');
5939
5940 return JSON_SUCCESS;
5941}

References appendStringInfoCharMacro, StringInfoData::data, escape_json(), JSON_SUCCESS, StringInfoData::len, and TransformJsonStringValuesState::strval.

Referenced by transform_json_string_values().

◆ transform_string_values_object_start()

static JsonParseErrorType transform_string_values_object_start ( void *  state)
static

◆ transform_string_values_scalar()

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

Definition at line 5955 of file jsonfuncs.c.

5956{
5958
5959 if (tokentype == JSON_TOKEN_STRING)
5960 {
5961 text *out = _state->action(_state->action_state, token, strlen(token));
5962
5963 escape_json_text(_state->strval, out);
5964 }
5965 else
5967
5968 return JSON_SUCCESS;
5969}
void escape_json_text(StringInfo buf, const text *txt)
Definition: json.c:1736
JsonTransformStringValuesAction action
Definition: jsonfuncs.c:80

References TransformJsonStringValuesState::action, TransformJsonStringValuesState::action_state, appendStringInfoString(), escape_json_text(), JSON_SUCCESS, JSON_TOKEN_STRING, and TransformJsonStringValuesState::strval.

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);
3037 MemoryContext oldcxt;
3038
3039 if (io->tupdesc)
3041
3042 /* copy tuple desc without constraints into cache memory context */
3043 oldcxt = MemoryContextSwitchTo(mcxt);
3044 io->tupdesc = CreateTupleDescCopy(tupdesc);
3045 MemoryContextSwitchTo(oldcxt);
3046
3047 ReleaseTupleDesc(tupdesc);
3048 }
3049}
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:219
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1922

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

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