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

Go to the source code of this file.

Data Structures

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

Macros

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

Typedefs

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

Enumerations

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

Functions

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

Macro Definition Documentation

◆ JB_PATH_CONSISTENT_POSITION

#define JB_PATH_CONSISTENT_POSITION   0x0040

Definition at line 52 of file jsonfuncs.c.

◆ JB_PATH_CREATE

#define JB_PATH_CREATE   0x0001

Definition at line 44 of file jsonfuncs.c.

◆ JB_PATH_CREATE_OR_INSERT

#define JB_PATH_CREATE_OR_INSERT    (JB_PATH_INSERT_BEFORE | JB_PATH_INSERT_AFTER | JB_PATH_CREATE)

Definition at line 49 of file jsonfuncs.c.

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

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:230

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:231

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

1926{
1927 AlenState *_state = (AlenState *) state;
1928
1929 /* just count up all the level 1 elements */
1930 if (_state->lex->lex_level == 1)
1931 _state->count++;
1932
1933 return JSON_SUCCESS;
1934}
@ 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 1897 of file jsonfuncs.c.

1898{
1899 AlenState *_state = (AlenState *) state;
1900
1901 /* json structure check */
1902 if (_state->lex->lex_level == 0)
1903 ereport(ERROR,
1904 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1905 errmsg("cannot get array length of a non-array")));
1906
1907 return JSON_SUCCESS;
1908}
int errcode(int sqlerrcode)
Definition: elog.c:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:150

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

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

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

3474{
3476 MemoryContextAlloc(mcxt,
3477 offsetof(RecordIOData, columns) +
3478 ncolumns * sizeof(ColumnIOData));
3479
3480 data->record_type = InvalidOid;
3481 data->record_typmod = 0;
3482 data->ncolumns = ncolumns;
3483 MemSet(data->columns, 0, sizeof(ColumnIOData) * ncolumns);
3484
3485 return data;
3486}
#define MemSet(start, val, len)
Definition: c.h:1022
struct ColumnIOData ColumnIOData
Definition: jsonfuncs.c:162
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1229
const void * data
#define InvalidOid
Definition: postgres_ext.h:37

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

Referenced by populate_record().

◆ each_array_start()

static JsonParseErrorType each_array_start ( void *  state)
static

Definition at line 2165 of file jsonfuncs.c.

2166{
2167 EachState *_state = (EachState *) state;
2168
2169 /* json structure check */
2170 if (_state->lex->lex_level == 0)
2171 ereport(ERROR,
2172 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2173 errmsg("cannot deconstruct an array as an object")));
2174
2175 return JSON_SUCCESS;
2176}
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 2117 of file jsonfuncs.c.

2118{
2119 EachState *_state = (EachState *) state;
2120 MemoryContext old_cxt;
2121 int len;
2122 text *val;
2123 HeapTuple tuple;
2124 Datum values[2];
2125 bool nulls[2] = {false, false};
2126
2127 /* skip over nested objects */
2128 if (_state->lex->lex_level != 1)
2129 return JSON_SUCCESS;
2130
2131 /* use the tmp context so we can clean up after each tuple is done */
2132 old_cxt = MemoryContextSwitchTo(_state->tmp_cxt);
2133
2134 values[0] = CStringGetTextDatum(fname);
2135
2136 if (isnull && _state->normalize_results)
2137 {
2138 nulls[1] = true;
2139 values[1] = (Datum) 0;
2140 }
2141 else if (_state->next_scalar)
2142 {
2144 _state->next_scalar = false;
2145 }
2146 else
2147 {
2148 len = _state->lex->prev_token_terminator - _state->result_start;
2151 }
2152
2153 tuple = heap_form_tuple(_state->ret_tdesc, values, nulls);
2154
2155 tuplestore_puttuple(_state->tuple_store, tuple);
2156
2157 /* clean up and switch back */
2158 MemoryContextSwitchTo(old_cxt);
2159 MemoryContextReset(_state->tmp_cxt);
2160
2161 return JSON_SUCCESS;
2162}
static Datum values[MAXATTR]
Definition: bootstrap.c:153
#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:400
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
const void size_t len
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:332
uint64_t Datum
Definition: postgres.h:70
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:695
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:193

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

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

2180{
2181 EachState *_state = (EachState *) state;
2182
2183 /* json structure check */
2184 if (_state->lex->lex_level == 0)
2185 ereport(ERROR,
2186 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2187 errmsg("cannot deconstruct a scalar")));
2188
2189 /* supply de-escaped value if required */
2190 if (_state->next_scalar)
2191 _state->normalized_scalar = token;
2192
2193 return JSON_SUCCESS;
2194}
#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 2055 of file jsonfuncs.c.

2056{
2057 text *json = PG_GETARG_TEXT_PP(0);
2058 JsonLexContext lex;
2060 ReturnSetInfo *rsi;
2062
2063 state = palloc0(sizeof(EachState));
2064 sem = palloc0(sizeof(JsonSemAction));
2065
2066 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2067
2069 state->tuple_store = rsi->setResult;
2070 state->ret_tdesc = rsi->setDesc;
2071
2072 sem->semstate = state;
2077
2078 state->normalize_results = as_text;
2079 state->next_scalar = false;
2080 state->lex = makeJsonLexContext(&lex, json, true);
2082 "json_each temporary cxt",
2084
2086
2087 MemoryContextDelete(state->tmp_cxt);
2088 freeJsonLexContext(&lex);
2089
2091}
#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:2117
static JsonParseErrorType each_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:2179
static JsonParseErrorType each_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:2095
static JsonParseErrorType each_array_start(void *state)
Definition: jsonfuncs.c:2165
#define pg_parse_json_or_ereport(lex, sem)
Definition: jsonfuncs.h:47
void * palloc0(Size size)
Definition: mcxt.c:1395
MemoryContext CurrentMemoryContext
Definition: mcxt.c:160
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:469
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
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:364
Tuplestorestate * setResult
Definition: execnodes.h:363
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 1971 of file jsonfuncs.c.

1972{
1973 Jsonb *jb = PG_GETARG_JSONB_P(0);
1974 ReturnSetInfo *rsi;
1975 MemoryContext old_cxt,
1976 tmp_cxt;
1977 bool skipNested = false;
1978 JsonbIterator *it;
1979 JsonbValue v;
1981
1982 if (!JB_ROOT_IS_OBJECT(jb))
1983 ereport(ERROR,
1984 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1985 errmsg("cannot call %s on a non-object",
1986 funcname)));
1987
1988 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
1990
1992 "jsonb_each temporary cxt",
1994
1995 it = JsonbIteratorInit(&jb->root);
1996
1997 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
1998 {
1999 skipNested = true;
2000
2001 if (r == WJB_KEY)
2002 {
2003 text *key;
2004 Datum values[2];
2005 bool nulls[2] = {false, false};
2006
2007 /* Use the tmp context so we can clean up after each tuple is done */
2008 old_cxt = MemoryContextSwitchTo(tmp_cxt);
2009
2010 key = cstring_to_text_with_len(v.val.string.val, v.val.string.len);
2011
2012 /*
2013 * The next thing the iterator fetches should be the value, no
2014 * matter what shape it is.
2015 */
2016 r = JsonbIteratorNext(&it, &v, skipNested);
2017 Assert(r != WJB_DONE);
2018
2020
2021 if (as_text)
2022 {
2023 if (v.type == jbvNull)
2024 {
2025 /* a json null is an sql null in text mode */
2026 nulls[1] = true;
2027 values[1] = (Datum) 0;
2028 }
2029 else
2031 }
2032 else
2033 {
2034 /* Not in text mode, just return the Jsonb */
2036
2038 }
2039
2040 tuplestore_putvalues(rsi->setResult, rsi->setDesc, values, nulls);
2041
2042 /* clean up and switch back */
2043 MemoryContextSwitchTo(old_cxt);
2044 MemoryContextReset(tmp_cxt);
2045 }
2046 }
2047
2048 MemoryContextDelete(tmp_cxt);
2049
2051}
Assert(PointerIsAligned(start, uint64))
#define funcname
Definition: indent_codes.h:69
#define JB_ROOT_IS_OBJECT(jbp_)
Definition: jsonb.h:223
#define PG_GETARG_JSONB_P(x)
Definition: jsonb.h:418
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:935
JsonbIteratorToken JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested)
Definition: jsonb_util.c:973
Jsonb * JsonbValueToJsonb(JsonbValue *val)
Definition: jsonb_util.c:96
static text * JsonbValueAsText(JsonbValue *v)
Definition: jsonfuncs.c:1802
enum jbvType type
Definition: jsonb.h:257
char * val
Definition: jsonb.h:266
Definition: jsonb.h:215
JsonbContainer root
Definition: jsonb.h:217
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 2369 of file jsonfuncs.c.

2370{
2371 ElementsState *_state = (ElementsState *) state;
2372 MemoryContext old_cxt;
2373 int len;
2374 text *val;
2375 HeapTuple tuple;
2376 Datum values[1];
2377 bool nulls[1] = {false};
2378
2379 /* skip over nested objects */
2380 if (_state->lex->lex_level != 1)
2381 return JSON_SUCCESS;
2382
2383 /* use the tmp context so we can clean up after each tuple is done */
2384 old_cxt = MemoryContextSwitchTo(_state->tmp_cxt);
2385
2386 if (isnull && _state->normalize_results)
2387 {
2388 nulls[0] = true;
2389 values[0] = (Datum) 0;
2390 }
2391 else if (_state->next_scalar)
2392 {
2394 _state->next_scalar = false;
2395 }
2396 else
2397 {
2398 len = _state->lex->prev_token_terminator - _state->result_start;
2401 }
2402
2403 tuple = heap_form_tuple(_state->ret_tdesc, values, nulls);
2404
2405 tuplestore_puttuple(_state->tuple_store, tuple);
2406
2407 /* clean up and switch back */
2408 MemoryContextSwitchTo(old_cxt);
2409 MemoryContextReset(_state->tmp_cxt);
2410
2411 return JSON_SUCCESS;
2412}
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 2347 of file jsonfuncs.c.

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

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

2416{
2417 ElementsState *_state = (ElementsState *) state;
2418
2419 /* json structure check */
2420 if (_state->lex->lex_level == 0)
2421 ereport(ERROR,
2422 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2423 errmsg("cannot call %s on a non-array",
2424 _state->function_name)));
2425
2426 return JSON_SUCCESS;
2427}
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 2430 of file jsonfuncs.c.

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

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

2306{
2307 text *json = PG_GETARG_TEXT_PP(0);
2308 JsonLexContext lex;
2310 ReturnSetInfo *rsi;
2312
2313 /* elements only needs escaped strings when as_text */
2314 makeJsonLexContext(&lex, json, as_text);
2315
2316 state = palloc0(sizeof(ElementsState));
2317 sem = palloc0(sizeof(JsonSemAction));
2318
2320 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2321 state->tuple_store = rsi->setResult;
2322 state->ret_tdesc = rsi->setDesc;
2323
2324 sem->semstate = state;
2329
2330 state->function_name = funcname;
2331 state->normalize_results = as_text;
2332 state->next_scalar = false;
2333 state->lex = &lex;
2335 "json_array_elements temporary cxt",
2337
2339
2340 MemoryContextDelete(state->tmp_cxt);
2341 freeJsonLexContext(&lex);
2342
2344}
#define MAT_SRF_USE_EXPECTED_DESC
Definition: funcapi.h:296
static JsonParseErrorType elements_object_start(void *state)
Definition: jsonfuncs.c:2415
static JsonParseErrorType elements_array_element_end(void *state, bool isnull)
Definition: jsonfuncs.c:2369
static JsonParseErrorType elements_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:2430
static JsonParseErrorType elements_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:2347
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 2217 of file jsonfuncs.c.

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

3810{
3811 HASHCTL ctl;
3812 HTAB *tab;
3815
3816 ctl.keysize = NAMEDATALEN;
3817 ctl.entrysize = sizeof(JsonHashEntry);
3819 tab = hash_create("json object hashtable",
3820 100,
3821 &ctl,
3823
3824 state = palloc0(sizeof(JHashState));
3825 sem = palloc0(sizeof(JsonSemAction));
3826
3827 state->function_name = funcname;
3828 state->hash = tab;
3829 state->lex = makeJsonLexContextCstringLen(NULL, json, len,
3830 GetDatabaseEncoding(), true);
3831
3832 sem->semstate = state;
3837
3838 if (!pg_parse_json_or_errsave(state->lex, sem, escontext))
3839 {
3840 hash_destroy(state->hash);
3841 tab = NULL;
3842 }
3843
3845
3846 return tab;
3847}
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:358
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:865
#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:3927
static JsonParseErrorType hash_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:3940
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:3876
static JsonParseErrorType hash_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:3850
int GetDatabaseEncoding(void)
Definition: mbutils.c:1262
#define NAMEDATALEN
tree ctl
Definition: radixtree.h:1838
Definition: dynahash.c:222

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(const ArrayType *array)
Definition: arrayfuncs.c:3768
void deconstruct_array_builtin(const ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3698
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
Datum jsonb_get_element(Jsonb *jb, const 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:1365
int strtoint(const char *restrict str, char **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 3633 of file jsonfuncs.c.

3636{
3637 cache->argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
3638 prepare_column_cache(&cache->c,
3639 cache->argtype, -1,
3640 cache->fn_mcxt, false);
3641 if (cache->c.typcat != TYPECAT_COMPOSITE &&
3643 ereport(ERROR,
3644 (errcode(ERRCODE_DATATYPE_MISMATCH),
3645 /* translator: %s is a function name, eg json_to_record */
3646 errmsg("first argument of %s must be a row type",
3647 funcname)));
3648}
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1875
static void prepare_column_cache(ColumnIOData *column, Oid typid, int32 typmod, MemoryContext mcxt, bool need_scalar)
Definition: jsonfuncs.c:3248
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 3659 of file jsonfuncs.c.

3662{
3663 TupleDesc tupdesc;
3664 MemoryContext old_cxt;
3665
3666 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
3667 ereport(ERROR,
3668 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3669 /* translator: %s is a function name, eg json_to_record */
3670 errmsg("could not determine row type for result of %s",
3671 funcname),
3672 errhint("Provide a non-null record argument, "
3673 "or call the function in the FROM clause "
3674 "using a column definition list.")));
3675
3676 Assert(tupdesc);
3677 cache->argtype = tupdesc->tdtypeid;
3678
3679 /* If we go through this more than once, avoid memory leak */
3680 if (cache->c.io.composite.tupdesc)
3682
3683 /* Save identified tupdesc */
3684 old_cxt = MemoryContextSwitchTo(cache->fn_mcxt);
3685 cache->c.io.composite.tupdesc = CreateTupleDescCopy(tupdesc);
3686 cache->c.io.composite.base_typid = tupdesc->tdtypeid;
3687 cache->c.io.composite.base_typmod = tupdesc->tdtypmod;
3688 MemoryContextSwitchTo(old_cxt);
3689}
int errhint(const char *fmt,...)
Definition: elog.c:1330
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149
CompositeIOData composite
Definition: jsonfuncs.c:221
union ColumnIOData::@26 io
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:502
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:252

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:181

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

3928{
3929 JHashState *_state = (JHashState *) state;
3930
3931 if (_state->lex->lex_level == 0)
3932 ereport(ERROR,
3933 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3934 errmsg("cannot call %s on an array", _state->function_name)));
3935
3936 return JSON_SUCCESS;
3937}
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 3876 of file jsonfuncs.c.

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

3851{
3852 JHashState *_state = (JHashState *) state;
3853
3854 if (_state->lex->lex_level > 1)
3855 return JSON_SUCCESS;
3856
3857 /* remember token type */
3858 _state->saved_token_type = _state->lex->token_type;
3859
3860 if (_state->lex->token_type == JSON_TOKEN_ARRAY_START ||
3862 {
3863 /* remember start position of the whole text of the subobject */
3864 _state->save_json_start = _state->lex->token_start;
3865 }
3866 else
3867 {
3868 /* must be a scalar */
3869 _state->save_json_start = NULL;
3870 }
3871
3872 return JSON_SUCCESS;
3873}
@ 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 3940 of file jsonfuncs.c.

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

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

5701{
5702 JsonLexContext lex;
5705
5706 state->lex = makeJsonLexContext(&lex, json, true);
5707 state->action = action;
5708 state->action_state = action_state;
5709 state->flags = flags;
5710
5711 sem->semstate = state;
5714
5716 freeJsonLexContext(&lex);
5717}
static JsonParseErrorType iterate_values_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:5752
static JsonParseErrorType iterate_values_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:5724

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

5633{
5634 JsonbIterator *it;
5635 JsonbValue v;
5637
5638 it = JsonbIteratorInit(&jb->root);
5639
5640 /*
5641 * Just recursively iterating over jsonb and call callback on all
5642 * corresponding elements
5643 */
5644 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
5645 {
5646 if (type == WJB_KEY)
5647 {
5648 if (flags & jtiKey)
5649 action(state, v.val.string.val, v.val.string.len);
5650
5651 continue;
5652 }
5653 else if (!(type == WJB_VALUE || type == WJB_ELEM))
5654 {
5655 /* do not call callback for composite JsonbValue */
5656 continue;
5657 }
5658
5659 /* JsonbValue is a value of object or element of array */
5660 switch (v.type)
5661 {
5662 case jbvString:
5663 if (flags & jtiString)
5664 action(state, v.val.string.val, v.val.string.len);
5665 break;
5666 case jbvNumeric:
5667 if (flags & jtiNumeric)
5668 {
5669 char *val;
5670
5672 NumericGetDatum(v.val.numeric)));
5673
5674 action(state, val, strlen(val));
5675 pfree(val);
5676 }
5677 break;
5678 case jbvBool:
5679 if (flags & jtiBool)
5680 {
5681 if (v.val.boolean)
5682 action(state, "true", 4);
5683 else
5684 action(state, "false", 5);
5685 }
5686 break;
5687 default:
5688 /* do not call callback for composite JsonbValue */
5689 break;
5690 }
5691 }
5692}
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:799
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:682
@ jbvNumeric
Definition: jsonb.h:232
@ jbvBool
Definition: jsonb.h:233
@ 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:1594
static Datum NumericGetDatum(Numeric X)
Definition: numeric.h:76
static char * DatumGetCString(Datum X)
Definition: postgres.h:345
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 5752 of file jsonfuncs.c.

5753{
5755
5756 if (_state->flags & jtiKey)
5757 {
5758 char *val = pstrdup(fname);
5759
5760 _state->action(_state->action_state, val, strlen(val));
5761 }
5762
5763 return JSON_SUCCESS;
5764}
char * pstrdup(const char *in)
Definition: mcxt.c:1759
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 5724 of file jsonfuncs.c.

5725{
5727
5728 switch (tokentype)
5729 {
5730 case JSON_TOKEN_STRING:
5731 if (_state->flags & jtiString)
5732 _state->action(_state->action_state, token, strlen(token));
5733 break;
5734 case JSON_TOKEN_NUMBER:
5735 if (_state->flags & jtiNumeric)
5736 _state->action(_state->action_state, token, strlen(token));
5737 break;
5738 case JSON_TOKEN_TRUE:
5739 case JSON_TOKEN_FALSE:
5740 if (_state->flags & jtiBool)
5741 _state->action(_state->action_state, token, strlen(token));
5742 break;
5743 default:
5744 /* do not call callback for any other token */
5745 break;
5746 }
5747
5748 return JSON_SUCCESS;
5749}
@ 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 void IteratorConcat ( JsonbIterator **  it1,
JsonbIterator **  it2,
JsonbInState state 
)
static

Definition at line 5052 of file jsonfuncs.c.

5054{
5055 JsonbValue v1,
5056 v2;
5058 r2,
5059 rk1,
5060 rk2;
5061
5062 rk1 = JsonbIteratorNext(it1, &v1, false);
5063 rk2 = JsonbIteratorNext(it2, &v2, false);
5064
5065 /*
5066 * JsonbIteratorNext reports raw scalars as if they were single-element
5067 * arrays; hence we only need consider "object" and "array" cases here.
5068 */
5069 if (rk1 == WJB_BEGIN_OBJECT && rk2 == WJB_BEGIN_OBJECT)
5070 {
5071 /*
5072 * Both inputs are objects.
5073 *
5074 * Append all the tokens from v1 to res, except last WJB_END_OBJECT
5075 * (because res will not be finished yet).
5076 */
5077 pushJsonbValue(state, rk1, NULL);
5078 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_OBJECT)
5079 pushJsonbValue(state, r1, &v1);
5080
5081 /*
5082 * Append all the tokens from v2 to res, including last WJB_END_OBJECT
5083 * (the concatenation will be completed). Any duplicate keys will
5084 * automatically override the value from the first object.
5085 */
5086 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5087 pushJsonbValue(state, r2, r2 != WJB_END_OBJECT ? &v2 : NULL);
5088 }
5089 else if (rk1 == WJB_BEGIN_ARRAY && rk2 == WJB_BEGIN_ARRAY)
5090 {
5091 /*
5092 * Both inputs are arrays.
5093 */
5094 pushJsonbValue(state, rk1, NULL);
5095
5096 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_ARRAY)
5097 {
5098 Assert(r1 == WJB_ELEM);
5099 pushJsonbValue(state, r1, &v1);
5100 }
5101
5102 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_END_ARRAY)
5103 {
5104 Assert(r2 == WJB_ELEM);
5106 }
5107
5108 pushJsonbValue(state, WJB_END_ARRAY, NULL /* signal to sort */ );
5109 }
5110 else if (rk1 == WJB_BEGIN_OBJECT)
5111 {
5112 /*
5113 * We have object || array.
5114 */
5115 Assert(rk2 == WJB_BEGIN_ARRAY);
5116
5118
5120 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_DONE)
5121 pushJsonbValue(state, r1, r1 != WJB_END_OBJECT ? &v1 : NULL);
5122
5123 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5124 pushJsonbValue(state, r2, r2 != WJB_END_ARRAY ? &v2 : NULL);
5125 }
5126 else
5127 {
5128 /*
5129 * We have array || object.
5130 */
5131 Assert(rk1 == WJB_BEGIN_ARRAY);
5132 Assert(rk2 == WJB_BEGIN_OBJECT);
5133
5135
5136 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_ARRAY)
5137 pushJsonbValue(state, r1, &v1);
5138
5140 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5141 pushJsonbValue(state, r2, r2 != WJB_END_OBJECT ? &v2 : NULL);
5142
5144 }
5145}
@ 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
void pushJsonbValue(JsonbInState *pstate, JsonbIteratorToken seq, JsonbValue *jbval)
Definition: jsonb_util.c:583

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

3490{
3491 jsv->is_json = obj->is_json;
3492
3493 if (jsv->is_json)
3494 {
3495 JsonHashEntry *hashentry = hash_search(obj->val.json_hash, field,
3496 HASH_FIND, NULL);
3497
3498 jsv->val.json.type = hashentry ? hashentry->type : JSON_TOKEN_NULL;
3499 jsv->val.json.str = jsv->val.json.type == JSON_TOKEN_NULL ? NULL :
3500 hashentry->val;
3501 jsv->val.json.len = jsv->val.json.str ? -1 : 0; /* null-terminated */
3502
3503 return hashentry != NULL;
3504 }
3505 else
3506 {
3507 jsv->val.jsonb = !obj->val.jsonb_cont ? NULL :
3508 getKeyJsonValueFromContainer(obj->val.jsonb_cont, field, strlen(field),
3509 NULL);
3510
3511 return jsv->val.jsonb != NULL;
3512 }
3513}
@ HASH_FIND
Definition: hsearch.h:113
JsonbValue * getKeyJsonValueFromContainer(JsonbContainer *container, const char *keyVal, int keyLen, JsonbValue *res)
Definition: jsonb_util.c:402
bool is_json
Definition: jsonfuncs.c:311
JsonbContainer * jsonb_cont
Definition: jsonfuncs.c:315
HTAB * json_hash
Definition: jsonfuncs.c:314
union JsObject::@29 val
const char * str
Definition: jsonfuncs.c:300
union JsValue::@27 val
JsonbValue * jsonb
Definition: jsonfuncs.c:305
int len
Definition: jsonfuncs.c:301
JsonTokenType type
Definition: jsonfuncs.c:302
struct JsValue::@27::@28 json
bool is_json
Definition: jsonfuncs.c:295

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

2294{
2295 return elements_worker(fcinfo, "json_array_elements", false);
2296}
static Datum elements_worker(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
Definition: jsonfuncs.c:2305

References elements_worker().

◆ json_array_elements_text()

Datum json_array_elements_text ( PG_FUNCTION_ARGS  )

Definition at line 2299 of file jsonfuncs.c.

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

References elements_worker().

◆ json_array_length()

Datum json_array_length ( PG_FUNCTION_ARGS  )

Definition at line 1849 of file jsonfuncs.c.

1850{
1851 text *json = PG_GETARG_TEXT_PP(0);
1853 JsonLexContext lex;
1855
1856 state = palloc0(sizeof(AlenState));
1857 state->lex = makeJsonLexContext(&lex, json, false);
1858 /* palloc0 does this for us */
1859#if 0
1860 state->count = 0;
1861#endif
1862
1863 sem = palloc0(sizeof(JsonSemAction));
1864 sem->semstate = state;
1868
1870
1871 PG_RETURN_INT32(state->count);
1872}
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
static JsonParseErrorType alen_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:1911
static JsonParseErrorType alen_object_start(void *state)
Definition: jsonfuncs.c:1897
static JsonParseErrorType alen_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:1925

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

5970{
5971 bool typisvarlena;
5972
5973 /* Look through any domain */
5974 typoid = getBaseType(typoid);
5975
5976 *outfuncoid = InvalidOid;
5977
5978 switch (typoid)
5979 {
5980 case BOOLOID:
5981 *outfuncoid = F_BOOLOUT;
5982 *tcategory = JSONTYPE_BOOL;
5983 break;
5984
5985 case INT2OID:
5986 case INT4OID:
5987 case INT8OID:
5988 case FLOAT4OID:
5989 case FLOAT8OID:
5990 case NUMERICOID:
5991 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
5992 *tcategory = JSONTYPE_NUMERIC;
5993 break;
5994
5995 case DATEOID:
5996 *outfuncoid = F_DATE_OUT;
5997 *tcategory = JSONTYPE_DATE;
5998 break;
5999
6000 case TIMESTAMPOID:
6001 *outfuncoid = F_TIMESTAMP_OUT;
6002 *tcategory = JSONTYPE_TIMESTAMP;
6003 break;
6004
6005 case TIMESTAMPTZOID:
6006 *outfuncoid = F_TIMESTAMPTZ_OUT;
6007 *tcategory = JSONTYPE_TIMESTAMPTZ;
6008 break;
6009
6010 case JSONOID:
6011 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6012 *tcategory = JSONTYPE_JSON;
6013 break;
6014
6015 case JSONBOID:
6016 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6017 *tcategory = is_jsonb ? JSONTYPE_JSONB : JSONTYPE_JSON;
6018 break;
6019
6020 default:
6021 /* Check for arrays and composites */
6022 if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
6023 || typoid == ANYCOMPATIBLEARRAYOID || typoid == RECORDARRAYOID)
6024 {
6025 *outfuncoid = F_ARRAY_OUT;
6026 *tcategory = JSONTYPE_ARRAY;
6027 }
6028 else if (type_is_rowtype(typoid)) /* includes RECORDOID */
6029 {
6030 *outfuncoid = F_RECORD_OUT;
6031 *tcategory = JSONTYPE_COMPOSITE;
6032 }
6033 else
6034 {
6035 /*
6036 * It's probably the general case. But let's look for a cast
6037 * to json (note: not to jsonb even if is_jsonb is true), if
6038 * it's not built-in.
6039 */
6040 *tcategory = JSONTYPE_OTHER;
6041 if (typoid >= FirstNormalObjectId)
6042 {
6043 Oid castfunc;
6044 CoercionPathType ctype;
6045
6046 ctype = find_coercion_pathway(JSONOID, typoid,
6048 &castfunc);
6049 if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc))
6050 {
6051 *outfuncoid = castfunc;
6052 *tcategory = JSONTYPE_CAST;
6053 }
6054 else
6055 {
6056 /* non builtin type with no cast */
6057 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6058 }
6059 }
6060 else
6061 {
6062 /* any other builtin type */
6063 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6064 }
6065 }
6066 break;
6067 }
6068}
#define OidIsValid(objectId)
Definition: c.h:777
@ 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:2926
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2822
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:3074
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2688
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:32
@ COERCION_EXPLICIT
Definition: primnodes.h:749
#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 1947 of file jsonfuncs.c.

1948{
1949 return each_worker(fcinfo, false);
1950}
static Datum each_worker(FunctionCallInfo fcinfo, bool as_text)
Definition: jsonfuncs.c:2055

References each_worker().

◆ json_each_text()

Datum json_each_text ( PG_FUNCTION_ARGS  )

Definition at line 1959 of file jsonfuncs.c.

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

References each_worker().

◆ json_errsave_error()

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

Definition at line 641 of file jsonfuncs.c.

643{
647 errsave(escontext,
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:1243
#define errsave(context,...)
Definition: elog.h:262
#define elog(elevel,...)
Definition: elog.h:226
char * json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
Definition: jsonapi.c:2404
@ 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 5941 of file jsonfuncs.c.

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

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

2493{
2494 return populate_record_worker(fcinfo, "json_populate_record",
2495 true, true, NULL);
2496}
static Datum populate_record_worker(FunctionCallInfo fcinfo, const char *funcname, bool is_json, bool have_record_arg, Node *escontext)
Definition: jsonfuncs.c:3696

References populate_record_worker().

◆ json_populate_recordset()

Datum json_populate_recordset ( PG_FUNCTION_ARGS  )

Definition at line 3985 of file jsonfuncs.c.

3986{
3987 return populate_recordset_worker(fcinfo, "json_populate_recordset",
3988 true, true);
3989}
static Datum populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname, bool is_json, bool have_record_arg)
Definition: jsonfuncs.c:4038

References populate_recordset_worker().

◆ json_populate_type()

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

Definition at line 3342 of file jsonfuncs.c.

3347{
3348 JsValue jsv = {0};
3349 JsonbValue jbv;
3350
3351 jsv.is_json = json_type == JSONOID;
3352
3353 if (*isnull)
3354 {
3355 if (jsv.is_json)
3356 jsv.val.json.str = NULL;
3357 else
3358 jsv.val.jsonb = NULL;
3359 }
3360 else if (jsv.is_json)
3361 {
3362 text *json = DatumGetTextPP(json_val);
3363
3364 jsv.val.json.str = VARDATA_ANY(json);
3365 jsv.val.json.len = VARSIZE_ANY_EXHDR(json);
3366 jsv.val.json.type = JSON_TOKEN_INVALID; /* not used in
3367 * populate_composite() */
3368 }
3369 else
3370 {
3371 Jsonb *jsonb = DatumGetJsonbP(json_val);
3372
3373 jsv.val.jsonb = &jbv;
3374
3375 if (omit_quotes)
3376 {
3377 char *str = JsonbUnquote(DatumGetJsonbP(json_val));
3378
3379 /* fill the quote-stripped string */
3380 jbv.type = jbvString;
3381 jbv.val.string.len = strlen(str);
3382 jbv.val.string.val = str;
3383 }
3384 else
3385 {
3386 /* fill binary jsonb value pointing to jb */
3387 jbv.type = jbvBinary;
3388 jbv.val.binary.data = &jsonb->root;
3389 jbv.val.binary.len = VARSIZE(jsonb) - VARHDRSZ;
3390 }
3391 }
3392
3393 if (*cache == NULL)
3394 *cache = MemoryContextAllocZero(mcxt, sizeof(ColumnIOData));
3395
3396 return populate_record_field(*cache, typid, typmod, NULL, mcxt,
3397 PointerGetDatum(NULL), &jsv, isnull,
3398 escontext, omit_quotes);
3399}
#define VARHDRSZ
Definition: c.h:700
#define DatumGetTextPP(X)
Definition: fmgr.h:292
const char * str
char * JsonbUnquote(Jsonb *jb)
Definition: jsonb.c:2039
@ jbvBinary
Definition: jsonb.h:238
static Jsonb * DatumGetJsonbP(Datum d)
Definition: jsonb.h:401
static Datum populate_record_field(ColumnIOData *col, Oid typid, int32 typmod, const char *colname, MemoryContext mcxt, Datum defaultval, JsValue *jsv, bool *isnull, Node *escontext, bool omit_scalar_quotes)
Definition: jsonfuncs.c:3403
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1263
static Size VARSIZE_ANY_EXHDR(const void *PTR)
Definition: varatt.h:472
static Size VARSIZE(const void *PTR)
Definition: varatt.h:298
static char * VARDATA_ANY(const void *PTR)
Definition: varatt.h:486

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

4503{
4504 text *json = PG_GETARG_TEXT_PP(0);
4505 bool strip_in_arrays = PG_NARGS() == 2 ? PG_GETARG_BOOL(1) : false;
4507 StringInfoData strbuf;
4508 JsonLexContext lex;
4510
4511 state = palloc0(sizeof(StripnullState));
4512 sem = palloc0(sizeof(JsonSemAction));
4513 initStringInfo(&strbuf);
4514
4515 state->lex = makeJsonLexContext(&lex, json, true);
4516 state->strval = &strbuf;
4517 state->skip_next_null = false;
4518 state->strip_in_arrays = strip_in_arrays;
4519
4520 sem->semstate = state;
4525 sem->scalar = sn_scalar;
4528
4530
4532 state->strval->len));
4533}
#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:4397
static JsonParseErrorType sn_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:4457
static JsonParseErrorType sn_object_start(void *state)
Definition: jsonfuncs.c:4387
static JsonParseErrorType sn_array_start(void *state)
Definition: jsonfuncs.c:4407
static JsonParseErrorType sn_array_end(void *state)
Definition: jsonfuncs.c:4417
static JsonParseErrorType sn_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:4427
static JsonParseErrorType sn_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:4479
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97

References JsonSemAction::array_element_start, JsonSemAction::array_end, JsonSemAction::array_start, cstring_to_text_with_len(), initStringInfo(), makeJsonLexContext(), 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 2499 of file jsonfuncs.c.

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

References populate_record_worker().

◆ json_to_recordset()

Datum json_to_recordset ( PG_FUNCTION_ARGS  )

Definition at line 3992 of file jsonfuncs.c.

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

References populate_recordset_worker().

◆ jsonb_array_element()

Datum jsonb_array_element ( PG_FUNCTION_ARGS  )

Definition at line 937 of file jsonfuncs.c.

938{
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:541
static uint32 pg_abs_s32(int32 a)
Definition: int.h:221
#define PG_RETURN_JSONB_P(x)
Definition: jsonb.h:420
#define JB_ROOT_COUNT(jbp_)
Definition: jsonb.h:221
JsonbValue * getIthJsonbValueFromContainer(JsonbContainer *container, uint32 i)
Definition: jsonb_util.c:472

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

2206{
2207 return elements_worker_jsonb(fcinfo, "jsonb_array_elements", false);
2208}
static Datum elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
Definition: jsonfuncs.c:2217

References elements_worker_jsonb().

◆ jsonb_array_elements_text()

Datum jsonb_array_elements_text ( PG_FUNCTION_ARGS  )

Definition at line 2211 of file jsonfuncs.c.

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

References elements_worker_jsonb().

◆ jsonb_array_length()

Datum jsonb_array_length ( PG_FUNCTION_ARGS  )

Definition at line 1875 of file jsonfuncs.c.

1876{
1877 Jsonb *jb = PG_GETARG_JSONB_P(0);
1878
1879 if (JB_ROOT_IS_SCALAR(jb))
1880 ereport(ERROR,
1881 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1882 errmsg("cannot get array length of a scalar")));
1883 else if (!JB_ROOT_IS_ARRAY(jb))
1884 ereport(ERROR,
1885 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1886 errmsg("cannot get array length of a non-array")));
1887
1889}

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

4621{
4622 Jsonb *jb1 = PG_GETARG_JSONB_P(0);
4623 Jsonb *jb2 = PG_GETARG_JSONB_P(1);
4624 JsonbInState state = {0};
4625 JsonbIterator *it1,
4626 *it2;
4627
4628 /*
4629 * If one of the jsonb is empty, just return the other if it's not scalar
4630 * and both are of the same kind. If it's a scalar or they are of
4631 * different kinds we need to perform the concatenation even if one is
4632 * empty.
4633 */
4634 if (JB_ROOT_IS_OBJECT(jb1) == JB_ROOT_IS_OBJECT(jb2))
4635 {
4636 if (JB_ROOT_COUNT(jb1) == 0 && !JB_ROOT_IS_SCALAR(jb2))
4637 PG_RETURN_JSONB_P(jb2);
4638 else if (JB_ROOT_COUNT(jb2) == 0 && !JB_ROOT_IS_SCALAR(jb1))
4639 PG_RETURN_JSONB_P(jb1);
4640 }
4641
4642 it1 = JsonbIteratorInit(&jb1->root);
4643 it2 = JsonbIteratorInit(&jb2->root);
4644
4645 IteratorConcat(&it1, &it2, &state);
4646
4648}
static void IteratorConcat(JsonbIterator **it1, JsonbIterator **it2, JsonbInState *state)
Definition: jsonfuncs.c:5052

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

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

References 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(), JsonbInState::result, Jsonb::root, JsonbValue::type, JsonbValue::val, VARDATA_ANY(), VARSIZE_ANY_EXHDR(), WJB_BEGIN_ARRAY, WJB_DONE, WJB_ELEM, and WJB_KEY.

◆ jsonb_delete_array()

Datum jsonb_delete_array ( PG_FUNCTION_ARGS  )

Definition at line 4708 of file jsonfuncs.c.

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

References ARR_NDIM, DatumGetPointer(), 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(), JsonbInState::result, Jsonb::root, JsonbValue::type, JsonbValue::val, VARDATA_ANY(), VARSIZE_ANY_EXHDR(), WJB_BEGIN_ARRAY, WJB_DONE, WJB_ELEM, and WJB_KEY.

◆ jsonb_delete_idx()

Datum jsonb_delete_idx ( PG_FUNCTION_ARGS  )

Definition at line 4792 of file jsonfuncs.c.

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

◆ jsonb_delete_path()

Datum jsonb_delete_path ( PG_FUNCTION_ARGS  )

Definition at line 4966 of file jsonfuncs.c.

4967{
4968 Jsonb *in = PG_GETARG_JSONB_P(0);
4970 Datum *path_elems;
4971 bool *path_nulls;
4972 int path_len;
4973 JsonbIterator *it;
4974 JsonbInState st = {0};
4975
4976 if (ARR_NDIM(path) > 1)
4977 ereport(ERROR,
4978 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4979 errmsg("wrong number of array subscripts")));
4980
4981 if (JB_ROOT_IS_SCALAR(in))
4982 ereport(ERROR,
4983 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4984 errmsg("cannot delete path in scalar")));
4985
4986 if (JB_ROOT_COUNT(in) == 0)
4988
4989 deconstruct_array_builtin(path, TEXTOID, &path_elems, &path_nulls, &path_len);
4990
4991 if (path_len == 0)
4993
4994 it = JsonbIteratorInit(&in->root);
4995
4996 setPath(&it, path_elems, path_nulls, path_len, &st,
4997 0, NULL, JB_PATH_DELETE);
4998
5000}
#define JB_PATH_DELETE
Definition: jsonfuncs.c:45
static void setPath(JsonbIterator **it, const Datum *path_elems, const bool *path_nulls, int path_len, JsonbInState *st, int level, JsonbValue *newval, int op_type)
Definition: jsonfuncs.c:5177

References ARR_NDIM, 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, JsonbInState::result, Jsonb::root, and setPath().

Referenced by jsonb_set_lax().

◆ jsonb_each()

Datum jsonb_each ( PG_FUNCTION_ARGS  )

Definition at line 1953 of file jsonfuncs.c.

1954{
1955 return each_worker_jsonb(fcinfo, "jsonb_each", false);
1956}
static Datum each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
Definition: jsonfuncs.c:1971

References each_worker_jsonb().

◆ jsonb_each_text()

Datum jsonb_each_text ( PG_FUNCTION_ARGS  )

Definition at line 1965 of file jsonfuncs.c.

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

References each_worker_jsonb().

◆ jsonb_extract_path()

Datum jsonb_extract_path ( PG_FUNCTION_ARGS  )

Definition at line 1488 of file jsonfuncs.c.

1489{
1490 return get_jsonb_path_all(fcinfo, false);
1491}
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,
const Datum path,
int  npath,
bool *  isnull,
bool  as_text 
)

Definition at line 1531 of file jsonfuncs.c.

1532{
1533 JsonbContainer *container = &jb->root;
1534 JsonbValue *jbvp = NULL;
1535 int i;
1536 bool have_object = false,
1537 have_array = false;
1538
1539 *isnull = false;
1540
1541 /* Identify whether we have object, array, or scalar at top-level */
1542 if (JB_ROOT_IS_OBJECT(jb))
1543 have_object = true;
1544 else if (JB_ROOT_IS_ARRAY(jb) && !JB_ROOT_IS_SCALAR(jb))
1545 have_array = true;
1546 else
1547 {
1549 /* Extract the scalar value, if it is what we'll return */
1550 if (npath <= 0)
1551 jbvp = getIthJsonbValueFromContainer(container, 0);
1552 }
1553
1554 /*
1555 * If the array is empty, return the entire LHS object, on the grounds
1556 * that we should do zero field or element extractions. For the
1557 * non-scalar case we can just hand back the object without much work. For
1558 * the scalar case, fall through and deal with the value below the loop.
1559 * (This inconsistency arises because there's no easy way to generate a
1560 * JsonbValue directly for root-level containers.)
1561 */
1562 if (npath <= 0 && jbvp == NULL)
1563 {
1564 if (as_text)
1565 {
1567 container,
1568 VARSIZE(jb))));
1569 }
1570 else
1571 {
1572 /* not text mode - just hand back the jsonb */
1574 }
1575 }
1576
1577 for (i = 0; i < npath; i++)
1578 {
1579 if (have_object)
1580 {
1581 text *subscr = DatumGetTextPP(path[i]);
1582
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:466
#define JsonContainerIsScalar(jc)
Definition: jsonb.h:209
#define JsonContainerIsArray(jc)
Definition: jsonb.h:211
#define JsonContainerSize(jc)
Definition: jsonb.h:208
#define IsAJsonbScalar(jsonbval)
Definition: jsonb.h:299
#define JsonContainerIsObject(jc)
Definition: jsonb.h:210
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 5006 of file jsonfuncs.c.

5007{
5008 Jsonb *in = PG_GETARG_JSONB_P(0);
5010 Jsonb *newjsonb = PG_GETARG_JSONB_P(2);
5012 bool after = PG_GETARG_BOOL(3);
5013 Datum *path_elems;
5014 bool *path_nulls;
5015 int path_len;
5016 JsonbIterator *it;
5017 JsonbInState st = {0};
5018
5019 JsonbToJsonbValue(newjsonb, &newval);
5020
5021 if (ARR_NDIM(path) > 1)
5022 ereport(ERROR,
5023 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
5024 errmsg("wrong number of array subscripts")));
5025
5026 if (JB_ROOT_IS_SCALAR(in))
5027 ereport(ERROR,
5028 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5029 errmsg("cannot set path in scalar")));
5030
5031 deconstruct_array_builtin(path, TEXTOID, &path_elems, &path_nulls, &path_len);
5032
5033 if (path_len == 0)
5035
5036 it = JsonbIteratorInit(&in->root);
5037
5038 setPath(&it, path_elems, path_nulls, path_len, &st, 0, &newval,
5040
5042}
#define newval
void JsonbToJsonbValue(Jsonb *jsonb, JsonbValue *val)
Definition: jsonb_util.c:76
#define JB_PATH_INSERT_BEFORE
Definition: jsonfuncs.c:47
#define JB_PATH_INSERT_AFTER
Definition: jsonfuncs.c:48

References ARR_NDIM, 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, JsonbInState::result, 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 2461 of file jsonfuncs.c.

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

References populate_record_worker().

◆ jsonb_populate_record_valid()

Datum jsonb_populate_record_valid ( PG_FUNCTION_ARGS  )

Definition at line 2474 of file jsonfuncs.c.

2475{
2476 ErrorSaveContext escontext = {T_ErrorSaveContext};
2477
2478 (void) populate_record_worker(fcinfo, "jsonb_populate_record",
2479 false, true, (Node *) &escontext);
2480
2481 return BoolGetDatum(!escontext.error_occurred);
2482}
static Datum BoolGetDatum(bool X)
Definition: postgres.h:112
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 3971 of file jsonfuncs.c.

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

References populate_recordset_worker().

◆ jsonb_pretty()

Datum jsonb_pretty ( PG_FUNCTION_ARGS  )

Definition at line 4603 of file jsonfuncs.c.

4604{
4605 Jsonb *jb = PG_GETARG_JSONB_P(0);
4607
4609 JsonbToCStringIndent(&str, &jb->root, VARSIZE(jb));
4610
4612}
char * JsonbToCStringIndent(StringInfo out, JsonbContainer *in, int estimated_len)
Definition: jsonb.c:475

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

◆ jsonb_set()

Datum jsonb_set ( PG_FUNCTION_ARGS  )

Definition at line 4853 of file jsonfuncs.c.

4854{
4855 Jsonb *in = PG_GETARG_JSONB_P(0);
4857 Jsonb *newjsonb = PG_GETARG_JSONB_P(2);
4859 bool create = PG_GETARG_BOOL(3);
4860 Datum *path_elems;
4861 bool *path_nulls;
4862 int path_len;
4863 JsonbIterator *it;
4864 JsonbInState st = {0};
4865
4866 JsonbToJsonbValue(newjsonb, &newval);
4867
4868 if (ARR_NDIM(path) > 1)
4869 ereport(ERROR,
4870 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4871 errmsg("wrong number of array subscripts")));
4872
4873 if (JB_ROOT_IS_SCALAR(in))
4874 ereport(ERROR,
4875 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4876 errmsg("cannot set path in scalar")));
4877
4878 if (JB_ROOT_COUNT(in) == 0 && !create)
4880
4881 deconstruct_array_builtin(path, TEXTOID, &path_elems, &path_nulls, &path_len);
4882
4883 if (path_len == 0)
4885
4886 it = JsonbIteratorInit(&in->root);
4887
4888 setPath(&it, path_elems, path_nulls, path_len, &st,
4889 0, &newval, create ? JB_PATH_CREATE : JB_PATH_REPLACE);
4890
4892}
#define JB_PATH_CREATE
Definition: jsonfuncs.c:44
#define JB_PATH_REPLACE
Definition: jsonfuncs.c:46

References ARR_NDIM, 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, JsonbInState::result, Jsonb::root, and setPath().

Referenced by jsonb_set_lax().

◆ jsonb_set_element()

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

Definition at line 1679 of file jsonfuncs.c.

1681{
1682 JsonbInState state = {0};
1683 JsonbIterator *it;
1684 bool *path_nulls = palloc0(path_len * sizeof(bool));
1685
1686 if (newval->type == jbvArray && newval->val.array.rawScalar)
1687 *newval = newval->val.array.elems[0];
1688
1689 it = JsonbIteratorInit(&jb->root);
1690
1691 setPath(&it, path, path_nulls, path_len, &state, 0, newval,
1694
1695 pfree(path_nulls);
1696
1698}
@ jbvArray
Definition: jsonb.h:235
#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 4899 of file jsonfuncs.c.

4900{
4901 /* Jsonb *in = PG_GETARG_JSONB_P(0); */
4902 /* ArrayType *path = PG_GETARG_ARRAYTYPE_P(1); */
4903 /* Jsonb *newval = PG_GETARG_JSONB_P(2); */
4904 /* bool create = PG_GETARG_BOOL(3); */
4905 text *handle_null;
4906 char *handle_val;
4907
4908 if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(3))
4910
4911 /* could happen if they pass in an explicit NULL */
4912 if (PG_ARGISNULL(4))
4913 ereport(ERROR,
4914 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4915 errmsg("null_value_treatment must be \"delete_key\", \"return_target\", \"use_json_null\", or \"raise_exception\"")));
4916
4917 /* if the new value isn't an SQL NULL just call jsonb_set */
4918 if (!PG_ARGISNULL(2))
4919 return jsonb_set(fcinfo);
4920
4921 handle_null = PG_GETARG_TEXT_P(4);
4922 handle_val = text_to_cstring(handle_null);
4923
4924 if (strcmp(handle_val, "raise_exception") == 0)
4925 {
4926 ereport(ERROR,
4927 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4928 errmsg("JSON value must not be null"),
4929 errdetail("Exception was raised because null_value_treatment is \"raise_exception\"."),
4930 errhint("To avoid, either change the null_value_treatment argument or ensure that an SQL NULL is not passed.")));
4931 return (Datum) 0; /* silence stupider compilers */
4932 }
4933 else if (strcmp(handle_val, "use_json_null") == 0)
4934 {
4935 Datum newval;
4936
4938
4939 fcinfo->args[2].value = newval;
4940 fcinfo->args[2].isnull = false;
4941 return jsonb_set(fcinfo);
4942 }
4943 else if (strcmp(handle_val, "delete_key") == 0)
4944 {
4945 return jsonb_delete_path(fcinfo);
4946 }
4947 else if (strcmp(handle_val, "return_target") == 0)
4948 {
4949 Jsonb *in = PG_GETARG_JSONB_P(0);
4950
4952 }
4953 else
4954 {
4955 ereport(ERROR,
4956 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4957 errmsg("null_value_treatment must be \"delete_key\", \"return_target\", \"use_json_null\", or \"raise_exception\"")));
4958 return (Datum) 0; /* silence stupider compilers */
4959 }
4960}
int errdetail(const char *fmt,...)
Definition: elog.c:1216
#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:65
Datum jsonb_delete_path(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4966
Datum jsonb_set(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4853
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:360

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

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

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

References populate_record_worker().

◆ jsonb_to_recordset()

Datum jsonb_to_recordset ( PG_FUNCTION_ARGS  )

Definition at line 3978 of file jsonfuncs.c.

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

References populate_recordset_worker().

◆ JsonbValueAsText()

static text * JsonbValueAsText ( JsonbValue v)
static

Definition at line 1802 of file jsonfuncs.c.

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

References cstring_to_text(), cstring_to_text_with_len(), 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 2979 of file jsonfuncs.c.

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

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:1829

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:1610
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 5563 of file jsonfuncs.c.

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

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

2918{
2920 Datum result;
2921 int *lbs;
2922 int i;
2923
2924 ctx.aio = aio;
2925 ctx.mcxt = mcxt;
2927 ctx.astate = initArrayResult(aio->element_type, ctx.acxt, true);
2928 ctx.colname = colname;
2929 ctx.ndims = 0; /* unknown yet */
2930 ctx.dims = NULL;
2931 ctx.sizes = NULL;
2932 ctx.escontext = escontext;
2933
2934 if (jsv->is_json)
2935 {
2936 /* Return null if an error was found. */
2937 if (!populate_array_json(&ctx, jsv->val.json.str,
2938 jsv->val.json.len >= 0 ? jsv->val.json.len
2939 : strlen(jsv->val.json.str)))
2940 {
2941 *isnull = true;
2942 return (Datum) 0;
2943 }
2944 }
2945 else
2946 {
2947 /* Return null if an error was found. */
2948 if (!populate_array_dim_jsonb(&ctx, jsv->val.jsonb, 1))
2949 {
2950 *isnull = true;
2951 return (Datum) 0;
2952 }
2953 ctx.dims[0] = ctx.sizes[0];
2954 }
2955
2956 Assert(ctx.ndims > 0);
2957
2958 lbs = palloc(sizeof(int) * ctx.ndims);
2959
2960 for (i = 0; i < ctx.ndims; i++)
2961 lbs[i] = 1;
2962
2963 result = makeMdArrayResult(ctx.astate, ctx.ndims, ctx.dims, lbs,
2964 ctx.acxt, true);
2965
2966 pfree(ctx.dims);
2967 pfree(ctx.sizes);
2968 pfree(lbs);
2969
2970 *isnull = false;
2971 return result;
2972}
Datum makeMdArrayResult(ArrayBuildState *astate, int ndims, int *dims, int *lbs, MemoryContext rcontext, bool release)
Definition: arrayfuncs.c:5453
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5294
static bool populate_array_json(PopulateArrayContext *ctx, const char *json, int len)
Definition: jsonfuncs.c:2786
static bool populate_array_dim_jsonb(PopulateArrayContext *ctx, JsonbValue *jbv, int ndim)
Definition: jsonfuncs.c:2822
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 2665 of file jsonfuncs.c.

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

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

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

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

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

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

2616{
2617 Datum element;
2618 bool element_isnull;
2619
2620 /* populate the array element */
2622 ctx->aio->element_type,
2623 ctx->aio->element_typmod,
2624 NULL, ctx->mcxt, PointerGetDatum(NULL),
2625 jsv, &element_isnull, ctx->escontext,
2626 false);
2627 /* Nothing to do on an error. */
2629 return false;
2630
2631 accumArrayResult(ctx->astate, element, element_isnull,
2632 ctx->aio->element_type, ctx->acxt);
2633
2634 Assert(ndim > 0);
2635 ctx->sizes[ndim - 1]++; /* increment current dimension counter */
2636
2637 return true;
2638}
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5351
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 2707 of file jsonfuncs.c.

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

References Assert(), 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 2689 of file jsonfuncs.c.

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

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

2787{
2790
2791 state.lex = makeJsonLexContextCstringLen(NULL, json, len,
2792 GetDatabaseEncoding(), true);
2793 state.ctx = ctx;
2794
2795 memset(&sem, 0, sizeof(sem));
2796 sem.semstate = &state;
2802
2804 {
2805 /* number of dimensions should be already known */
2806 Assert(ctx->ndims > 0 && ctx->dims);
2807 }
2808
2810
2811 return !SOFT_ERROR_OCCURRED(ctx->escontext);
2812}
static JsonParseErrorType populate_array_scalar(void *_state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:2750
static JsonParseErrorType populate_array_object_start(void *_state)
Definition: jsonfuncs.c:2642
static JsonParseErrorType populate_array_element_end(void *_state, bool isnull)
Definition: jsonfuncs.c:2707
static JsonParseErrorType populate_array_element_start(void *_state, bool isnull)
Definition: jsonfuncs.c:2689
static JsonParseErrorType populate_array_array_end(void *_state)
Definition: jsonfuncs.c:2665

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

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

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

Referenced by populate_array_json().

◆ populate_array_report_expected_array()

static void populate_array_report_expected_array ( PopulateArrayContext ctx,
int  ndim 
)
static

Definition at line 2507 of file jsonfuncs.c.

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

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

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

Referenced by populate_array_json().

◆ populate_composite()

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

Definition at line 3055 of file jsonfuncs.c.

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

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

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

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

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

4266{
4268
4269 if (_state->lex->lex_level == 1 &&
4271 ereport(ERROR,
4272 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4273 errmsg("argument of %s must be an array of objects",
4274 _state->function_name)));
4275
4276 return JSON_SUCCESS;
4277}
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 4280 of file jsonfuncs.c.

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

References JSON_SUCCESS.

Referenced by populate_recordset_worker().

◆ populate_recordset_object_end()

static JsonParseErrorType populate_recordset_object_end ( void *  state)
static

Definition at line 4242 of file jsonfuncs.c.

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

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

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

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

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

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

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

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

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

Referenced by populate_recordset_object_end(), and populate_recordset_worker().

◆ populate_recordset_scalar()

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

Definition at line 4287 of file jsonfuncs.c.

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

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

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

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

3253{
3254 HeapTuple tup;
3256
3257 column->typid = typid;
3258 column->typmod = typmod;
3259
3260 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3261 if (!HeapTupleIsValid(tup))
3262 elog(ERROR, "cache lookup failed for type %u", typid);
3263
3264 type = (Form_pg_type) GETSTRUCT(tup);
3265
3266 if (type->typtype == TYPTYPE_DOMAIN)
3267 {
3268 /*
3269 * We can move directly to the bottom base type; domain_check() will
3270 * take care of checking all constraints for a stack of domains.
3271 */
3272 Oid base_typid;
3273 int32 base_typmod = typmod;
3274
3275 base_typid = getBaseTypeAndTypmod(typid, &base_typmod);
3276 if (get_typtype(base_typid) == TYPTYPE_COMPOSITE)
3277 {
3278 /* domain over composite has its own code path */
3280 column->io.composite.record_io = NULL;
3281 column->io.composite.tupdesc = NULL;
3282 column->io.composite.base_typid = base_typid;
3283 column->io.composite.base_typmod = base_typmod;
3284 column->io.composite.domain_info = NULL;
3285 }
3286 else
3287 {
3288 /* domain over anything else */
3289 column->typcat = TYPECAT_DOMAIN;
3290 column->io.domain.base_typid = base_typid;
3291 column->io.domain.base_typmod = base_typmod;
3292 column->io.domain.base_io =
3293 MemoryContextAllocZero(mcxt, sizeof(ColumnIOData));
3294 column->io.domain.domain_info = NULL;
3295 }
3296 }
3297 else if (type->typtype == TYPTYPE_COMPOSITE || typid == RECORDOID)
3298 {
3299 column->typcat = TYPECAT_COMPOSITE;
3300 column->io.composite.record_io = NULL;
3301 column->io.composite.tupdesc = NULL;
3302 column->io.composite.base_typid = typid;
3303 column->io.composite.base_typmod = typmod;
3304 column->io.composite.domain_info = NULL;
3305 }
3306 else if (IsTrueArrayType(type))
3307 {
3308 column->typcat = TYPECAT_ARRAY;
3310 sizeof(ColumnIOData));
3311 column->io.array.element_type = type->typelem;
3312 /* array element typemod stored in attribute's typmod */
3313 column->io.array.element_typmod = typmod;
3314 }
3315 else
3316 {
3317 column->typcat = TYPECAT_SCALAR;
3318 need_scalar = true;
3319 }
3320
3321 /* caller can force us to look up scalar_io info even for non-scalars */
3322 if (need_scalar)
3323 {
3324 Oid typioproc;
3325
3326 getTypeInputInfo(typid, &typioproc, &column->scalar_io.typioparam);
3327 fmgr_info_cxt(typioproc, &column->scalar_io.typiofunc, mcxt);
3328 }
3329
3330 ReleaseSysCache(tup);
3331}
int32_t int32
Definition: c.h:537
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:138
#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:3041
char get_typtype(Oid typid)
Definition: lsyscache.c:2796
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2705
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:220

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 ( JsonbInState ps,
int  num 
)
static

Definition at line 1701 of file jsonfuncs.c.

1702{
1703 JsonbValue null;
1704
1705 null.type = jbvNull;
1706
1707 while (num-- > 0)
1708 pushJsonbValue(ps, WJB_ELEM, &null);
1709}
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 ( JsonbInState st,
int  level,
const Datum path_elems,
const bool *  path_nulls,
int  path_len,
JsonbValue newval 
)
static

Definition at line 1720 of file jsonfuncs.c.

1722{
1723 /*
1724 * tpath contains expected type of an empty jsonb created at each level
1725 * higher or equal to the current one, either jbvObject or jbvArray. Since
1726 * it contains only information about path slice from level to the end,
1727 * the access index must be normalized by level.
1728 */
1729 enum jbvType *tpath = palloc0((path_len - level) * sizeof(enum jbvType));
1730 JsonbValue newkey;
1731
1732 /*
1733 * Create first part of the chain with beginning tokens. For the current
1734 * level WJB_BEGIN_OBJECT/WJB_BEGIN_ARRAY was already created, so start
1735 * with the next one.
1736 */
1737 for (int i = level + 1; i < path_len; i++)
1738 {
1739 char *c,
1740 *badp;
1741 int lindex;
1742
1743 if (path_nulls[i])
1744 break;
1745
1746 /*
1747 * Try to convert to an integer to find out the expected type, object
1748 * or array.
1749 */
1750 c = TextDatumGetCString(path_elems[i]);
1751 errno = 0;
1752 lindex = strtoint(c, &badp, 10);
1753 if (badp == c || *badp != '\0' || errno != 0)
1754 {
1755 /* text, an object is expected */
1756 newkey.type = jbvString;
1757 newkey.val.string.val = c;
1758 newkey.val.string.len = strlen(c);
1759
1761 pushJsonbValue(st, WJB_KEY, &newkey);
1762
1763 tpath[i - level] = jbvObject;
1764 }
1765 else
1766 {
1767 /* integer, an array is expected */
1769
1770 push_null_elements(st, lindex);
1771
1772 tpath[i - level] = jbvArray;
1773 }
1774 }
1775
1776 /* Insert an actual value for either an object or array */
1777 if (tpath[(path_len - level) - 1] == jbvArray)
1779 else
1781
1782 /*
1783 * Close everything up to the last but one level. The last one will be
1784 * closed outside of this function.
1785 */
1786 for (int i = path_len - 1; i > level; i--)
1787 {
1788 if (path_nulls[i])
1789 break;
1790
1791 if (tpath[i - level] == jbvObject)
1792 pushJsonbValue(st, WJB_END_OBJECT, NULL);
1793 else
1794 pushJsonbValue(st, WJB_END_ARRAY, NULL);
1795 }
1796}
jbvType
Definition: jsonb.h:228
@ jbvObject
Definition: jsonb.h:236
static void push_null_elements(JsonbInState *ps, int num)
Definition: jsonfuncs.c:1701
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:1143
#define errcontext
Definition: elog.h:198
@ JSON_TOKEN_END
Definition: jsonapi.h:31
int pg_mblen(const char *mbstr)
Definition: mbutils.c:1024
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 void setPath ( JsonbIterator **  it,
const Datum path_elems,
const bool *  path_nulls,
int  path_len,
JsonbInState st,
int  level,
JsonbValue newval,
int  op_type 
)
static

Definition at line 5177 of file jsonfuncs.c.

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

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,
const Datum path_elems,
const bool *  path_nulls,
int  path_len,
JsonbInState st,
int  level,
JsonbValue newval,
uint32  nelems,
int  op_type 
)
static

Definition at line 5393 of file jsonfuncs.c.

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

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,
const Datum path_elems,
const bool *  path_nulls,
int  path_len,
JsonbInState st,
int  level,
JsonbValue newval,
uint32  npairs,
int  op_type 
)
static

Definition at line 5255 of file jsonfuncs.c.

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

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

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

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

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

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

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

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

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

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

References appendStringInfoCharMacro, 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 4387 of file jsonfuncs.c.

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

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

4480{
4481 StripnullState *_state = (StripnullState *) state;
4482
4483 if (_state->skip_next_null)
4484 {
4485 Assert(tokentype == JSON_TOKEN_NULL);
4486 _state->skip_next_null = false;
4487 return JSON_SUCCESS;
4488 }
4489
4490 if (tokentype == JSON_TOKEN_STRING)
4491 escape_json(_state->strval, token);
4492 else
4494
4495 return JSON_SUCCESS;
4496}
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 5819 of file jsonfuncs.c.

5821{
5822 JsonLexContext lex;
5825 StringInfoData strbuf;
5826
5827 initStringInfo(&strbuf);
5828
5829 state->lex = makeJsonLexContext(&lex, json, true);
5830 state->strval = &strbuf;
5831 state->action = transform_action;
5832 state->action_state = action_state;
5833
5834 sem->semstate = state;
5842
5844 freeJsonLexContext(&lex);
5845
5846 return cstring_to_text_with_len(state->strval->data, state->strval->len);
5847}
static JsonParseErrorType transform_string_values_array_start(void *state)
Definition: jsonfuncs.c:5875
static JsonParseErrorType transform_string_values_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:5895
static JsonParseErrorType transform_string_values_array_end(void *state)
Definition: jsonfuncs.c:5885
static JsonParseErrorType transform_string_values_object_end(void *state)
Definition: jsonfuncs.c:5865
static JsonParseErrorType transform_string_values_object_start(void *state)
Definition: jsonfuncs.c:5855
static JsonParseErrorType transform_string_values_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:5913
static JsonParseErrorType transform_string_values_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:5924

References JsonSemAction::array_element_start, JsonSemAction::array_end, JsonSemAction::array_start, cstring_to_text_with_len(), freeJsonLexContext(), initStringInfo(), makeJsonLexContext(), 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 5773 of file jsonfuncs.c.

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

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

Referenced by ts_headline_jsonb_byid_opt().

◆ transform_string_values_array_element_start()

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

Definition at line 5913 of file jsonfuncs.c.

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

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

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

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

5925{
5927
5928 if (tokentype == JSON_TOKEN_STRING)
5929 {
5930 text *out = _state->action(_state->action_state, token, strlen(token));
5931
5932 escape_json_text(_state->strval, out);
5933 }
5934 else
5936
5937 return JSON_SUCCESS;
5938}
void escape_json_text(StringInfo buf, const text *txt)
Definition: json.c:1738
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 3026 of file jsonfuncs.c.

3027{
3028 if (!io->tupdesc ||
3029 io->tupdesc->tdtypeid != io->base_typid ||
3030 io->tupdesc->tdtypmod != io->base_typmod)
3031 {
3033 io->base_typmod);
3034 MemoryContext oldcxt;
3035
3036 if (io->tupdesc)
3038
3039 /* copy tuple desc without constraints into cache memory context */
3040 oldcxt = MemoryContextSwitchTo(mcxt);
3041 io->tupdesc = CreateTupleDescCopy(tupdesc);
3042 MemoryContextSwitchTo(oldcxt);
3043
3044 ReleaseTupleDesc(tupdesc);
3045 }
3046}
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:219
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1921

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