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/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 (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)
 
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)
 
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, 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)
 
static JsonbValueIteratorConcat (JsonbIterator **it1, JsonbIterator **it2, JsonbParseState **state)
 
static JsonbValuesetPath (JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, JsonbParseState **st, int level, JsonbValue *newval, int op_type)
 
static void setPathObject (JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, JsonbParseState **st, int level, JsonbValue *newval, uint32 npairs, int op_type)
 
static void setPathArray (JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, JsonbParseState **st, int level, JsonbValue *newval, uint32 nelems, int op_type)
 
static JsonParseErrorType iterate_values_scalar (void *state, char *token, JsonTokenType tokentype)
 
static JsonParseErrorType iterate_values_object_field_start (void *state, char *fname, bool isnull)
 
static JsonParseErrorType transform_string_values_object_start (void *state)
 
static JsonParseErrorType transform_string_values_object_end (void *state)
 
static JsonParseErrorType transform_string_values_array_start (void *state)
 
static JsonParseErrorType transform_string_values_array_end (void *state)
 
static JsonParseErrorType transform_string_values_object_field_start (void *state, char *fname, bool isnull)
 
static JsonParseErrorType transform_string_values_array_element_start (void *state, bool isnull)
 
static JsonParseErrorType transform_string_values_scalar (void *state, char *token, JsonTokenType tokentype)
 
bool pg_parse_json_or_errsave (JsonLexContext *lex, JsonSemAction *sem, Node *escontext)
 
JsonLexContextmakeJsonLexContext (JsonLexContext *lex, text *json, bool need_escapes)
 
Datum jsonb_object_keys (PG_FUNCTION_ARGS)
 
void json_errsave_error (JsonParseErrorType error, JsonLexContext *lex, Node *escontext)
 
Datum json_object_keys (PG_FUNCTION_ARGS)
 
Datum json_object_field (PG_FUNCTION_ARGS)
 
Datum jsonb_object_field (PG_FUNCTION_ARGS)
 
Datum json_object_field_text (PG_FUNCTION_ARGS)
 
Datum jsonb_object_field_text (PG_FUNCTION_ARGS)
 
Datum json_array_element (PG_FUNCTION_ARGS)
 
Datum jsonb_array_element (PG_FUNCTION_ARGS)
 
Datum json_array_element_text (PG_FUNCTION_ARGS)
 
Datum jsonb_array_element_text (PG_FUNCTION_ARGS)
 
Datum json_extract_path (PG_FUNCTION_ARGS)
 
Datum json_extract_path_text (PG_FUNCTION_ARGS)
 
Datum jsonb_extract_path (PG_FUNCTION_ARGS)
 
Datum jsonb_extract_path_text (PG_FUNCTION_ARGS)
 
Datum jsonb_get_element (Jsonb *jb, Datum *path, int npath, bool *isnull, bool as_text)
 
Datum jsonb_set_element (Jsonb *jb, Datum *path, int path_len, JsonbValue *newval)
 
static void push_null_elements (JsonbParseState **ps, int num)
 
static void push_path (JsonbParseState **st, int level, Datum *path_elems, bool *path_nulls, int path_len, JsonbValue *newval)
 
Datum json_array_length (PG_FUNCTION_ARGS)
 
Datum jsonb_array_length (PG_FUNCTION_ARGS)
 
Datum json_each (PG_FUNCTION_ARGS)
 
Datum jsonb_each (PG_FUNCTION_ARGS)
 
Datum json_each_text (PG_FUNCTION_ARGS)
 
Datum jsonb_each_text (PG_FUNCTION_ARGS)
 
Datum jsonb_array_elements (PG_FUNCTION_ARGS)
 
Datum jsonb_array_elements_text (PG_FUNCTION_ARGS)
 
Datum json_array_elements (PG_FUNCTION_ARGS)
 
Datum json_array_elements_text (PG_FUNCTION_ARGS)
 
Datum jsonb_populate_record (PG_FUNCTION_ARGS)
 
Datum jsonb_populate_record_valid (PG_FUNCTION_ARGS)
 
Datum jsonb_to_record (PG_FUNCTION_ARGS)
 
Datum json_populate_record (PG_FUNCTION_ARGS)
 
Datum json_to_record (PG_FUNCTION_ARGS)
 
static void update_cached_tupdesc (CompositeIOData *io, MemoryContext mcxt)
 
Datum json_populate_type (Datum json_val, Oid json_type, Oid typid, int32 typmod, void **cache, MemoryContext mcxt, bool *isnull, 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 51 of file jsonfuncs.c.

◆ JB_PATH_CREATE

#define JB_PATH_CREATE   0x0001

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

◆ JB_PATH_DELETE

#define JB_PATH_DELETE   0x0002

Definition at line 44 of file jsonfuncs.c.

◆ JB_PATH_FILL_GAPS

#define JB_PATH_FILL_GAPS   0x0020

Definition at line 50 of file jsonfuncs.c.

◆ JB_PATH_INSERT_AFTER

#define JB_PATH_INSERT_AFTER   0x0010

Definition at line 47 of file jsonfuncs.c.

◆ JB_PATH_INSERT_BEFORE

#define JB_PATH_INSERT_BEFORE   0x0008

Definition at line 46 of file jsonfuncs.c.

◆ JB_PATH_REPLACE

#define JB_PATH_REPLACE   0x0004

Definition at line 45 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:670

Definition at line 333 of file jsonfuncs.c.

◆ JsObjectIsEmpty

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

Definition at line 327 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:32
@ jbvNull
Definition: jsonb.h:228

Definition at line 318 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:22
@ jbvString
Definition: jsonb.h:229

Definition at line 323 of file jsonfuncs.c.

Typedef Documentation

◆ AlenState

typedef struct AlenState AlenState

◆ ArrayIOData

typedef struct ArrayIOData ArrayIOData

◆ ColumnIOData

typedef struct ColumnIOData ColumnIOData

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

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

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:38
int count
Definition: jsonfuncs.c:104
JsonLexContext * lex
Definition: jsonfuncs.c:103
int lex_level
Definition: jsonapi.h:99
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:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149

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

Referenced by json_array_length().

◆ alen_scalar()

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

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

3454 {
3456  MemoryContextAlloc(mcxt,
3457  offsetof(RecordIOData, columns) +
3458  ncolumns * sizeof(ColumnIOData));
3459 
3460  data->record_type = InvalidOid;
3461  data->record_typmod = 0;
3462  data->ncolumns = ncolumns;
3463  MemSet(data->columns, 0, sizeof(ColumnIOData) * ncolumns);
3464 
3465  return data;
3466 }
#define MemSet(start, val, len)
Definition: c.h:1020
struct ColumnIOData ColumnIOData
Definition: jsonfuncs.c:161
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1180
const void * data
#define InvalidOid
Definition: postgres_ext.h:36

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

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;
2150  values[1] = PointerGetDatum(val);
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:152
#define CStringGetTextDatum(s)
Definition: builtins.h:97
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
const void size_t len
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
MemoryContextSwitchTo(old_ctx)
bool normalize_results
Definition: jsonfuncs.c:115
TupleDesc ret_tdesc
Definition: jsonfuncs.c:112
char * result_start
Definition: jsonfuncs.c:114
char * normalized_scalar
Definition: jsonfuncs.c:117
Tuplestorestate * tuple_store
Definition: jsonfuncs.c:111
MemoryContext tmp_cxt
Definition: jsonfuncs.c:113
bool next_scalar
Definition: jsonfuncs.c:116
char * prev_token_terminator
Definition: jsonapi.h:96
Definition: c.h:687
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
Definition: tuplestore.c:730
text * cstring_to_text_with_len(const char *s, int len)
Definition: varlena.c:196

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 }
char * token_start
Definition: jsonapi.h:94
JsonTokenType token_type
Definition: jsonapi.h:98

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;
2059  JsonSemAction *sem;
2060  ReturnSetInfo *rsi;
2061  EachState *state;
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 = (void *) state;
2074  sem->scalar = each_scalar;
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 
2090  PG_RETURN_NULL();
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:482
JsonLexContext * makeJsonLexContext(JsonLexContext *lex, text *json, bool need_escapes)
Definition: jsonfuncs.c:537
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:1346
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
fmNodePtr resultinfo
Definition: fmgr.h:89
json_ofield_action object_field_start
Definition: jsonapi.h:139
json_scalar_action scalar
Definition: jsonapi.h:143
void * semstate
Definition: jsonapi.h:134
json_struct_action array_start
Definition: jsonapi.h:137
json_ofield_action object_field_end
Definition: jsonapi.h:140
TupleDesc setDesc
Definition: execnodes.h:340
Tuplestorestate * setResult
Definition: execnodes.h:339
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 
2019  values[0] = PointerGetDatum(key);
2020 
2021  if (as_text)
2022  {
2023  if (v.type == jbvNull)
2024  {
2025  /* a json null is an sql null in text mode */
2026  nulls[1] = true;
2027  values[1] = (Datum) NULL;
2028  }
2029  else
2031  }
2032  else
2033  {
2034  /* Not in text mode, just return the Jsonb */
2035  Jsonb *val = JsonbValueToJsonb(&v);
2036 
2037  values[1] = PointerGetDatum(val);
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 
2050  PG_RETURN_NULL();
2051 }
#define Assert(condition)
Definition: c.h:858
#define funcname
Definition: indent_codes.h:69
#define JB_ROOT_IS_OBJECT(jbp_)
Definition: jsonb.h:221
#define PG_GETARG_JSONB_P(x)
Definition: jsonb.h:391
JsonbIteratorToken
Definition: jsonb.h:21
@ WJB_KEY
Definition: jsonb.h:23
@ WJB_DONE
Definition: jsonb.h:22
JsonbIterator * JsonbIteratorInit(JsonbContainer *container)
Definition: jsonb_util.c:817
Jsonb * JsonbValueToJsonb(JsonbValue *val)
Definition: jsonb_util.c:92
JsonbIteratorToken JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested)
Definition: jsonb_util.c:853
static text * JsonbValueAsText(JsonbValue *v)
Definition: jsonfuncs.c:1802
enum jbvType type
Definition: jsonb.h:255
char * val
Definition: jsonb.h:264
Definition: jsonb.h:213
JsonbContainer root
Definition: jsonb.h:215
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:750

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) NULL;
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;
2400  values[0] = PointerGetDatum(val);
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 }
char * result_start
Definition: jsonfuncs.c:128
bool next_scalar
Definition: jsonfuncs.c:130
TupleDesc ret_tdesc
Definition: jsonfuncs.c:126
Tuplestorestate * tuple_store
Definition: jsonfuncs.c:125
bool normalize_results
Definition: jsonfuncs.c:129
MemoryContext tmp_cxt
Definition: jsonfuncs.c:127
JsonLexContext * lex
Definition: jsonfuncs.c:123
char * normalized_scalar
Definition: jsonfuncs.c:131

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

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;
2309  JsonSemAction *sem;
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 = (void *) 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 
2343  PG_RETURN_NULL();
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:135
json_aelem_action array_element_start
Definition: jsonapi.h:141
json_aelem_action array_element_end
Definition: jsonapi.h:142

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) NULL;
2267  }
2268  else
2270  }
2271  else
2272  {
2273  /* Not in text mode, just return the Jsonb */
2274  Jsonb *val = JsonbValueToJsonb(&v);
2275 
2276  values[0] = PointerGetDatum(val);
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 
2289  PG_RETURN_NULL();
2290 }
#define JB_ROOT_IS_ARRAY(jbp_)
Definition: jsonb.h:222
#define JB_ROOT_IS_SCALAR(jbp_)
Definition: jsonb.h:220
@ WJB_ELEM
Definition: jsonb.h:25

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

Referenced by jsonb_array_elements(), and jsonb_array_elements_text().

◆ get_array_element_end()

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

Definition at line 1398 of file jsonfuncs.c.

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

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

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

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

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

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

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

Definition at line 3787 of file jsonfuncs.c.

3789 {
3790  HASHCTL ctl;
3791  HTAB *tab;
3792  JHashState *state;
3793  JsonSemAction *sem;
3794 
3795  ctl.keysize = NAMEDATALEN;
3796  ctl.entrysize = sizeof(JsonHashEntry);
3797  ctl.hcxt = CurrentMemoryContext;
3798  tab = hash_create("json object hashtable",
3799  100,
3800  &ctl,
3802 
3803  state = palloc0(sizeof(JHashState));
3804  sem = palloc0(sizeof(JsonSemAction));
3805 
3806  state->function_name = funcname;
3807  state->hash = tab;
3808  state->lex = makeJsonLexContextCstringLen(NULL, json, len,
3809  GetDatabaseEncoding(), true);
3810 
3811  sem->semstate = (void *) state;
3813  sem->scalar = hash_scalar;
3816 
3817  if (!pg_parse_json_or_errsave(state->lex, sem, escontext))
3818  {
3819  hash_destroy(state->hash);
3820  tab = NULL;
3821  }
3822 
3823  freeJsonLexContext(state->lex);
3824 
3825  return tab;
3826 }
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:865
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
#define HASH_STRINGS
Definition: hsearch.h:96
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
JsonLexContext * makeJsonLexContextCstringLen(JsonLexContext *lex, char *json, int len, int encoding, bool need_escapes)
Definition: jsonapi.c:326
static JsonParseErrorType hash_array_start(void *state)
Definition: jsonfuncs.c:3906
static JsonParseErrorType hash_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:3919
struct JsonHashEntry JsonHashEntry
bool pg_parse_json_or_errsave(JsonLexContext *lex, JsonSemAction *sem, Node *escontext)
Definition: jsonfuncs.c:516
static JsonParseErrorType hash_object_field_end(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:3855
static JsonParseErrorType hash_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:3829
int GetDatabaseEncoding(void)
Definition: mbutils.c:1261
#define NAMEDATALEN
tree ctl
Definition: radixtree.h:1851
Definition: dynahash.c:220

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

Referenced by JsValueToJsObject().

◆ get_jsonb_path_all()

static Datum get_jsonb_path_all ( FunctionCallInfo  fcinfo,
bool  as_text 
)
static

Definition at line 1497 of file jsonfuncs.c.

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

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

Referenced by jsonb_extract_path(), and jsonb_extract_path_text().

◆ get_object_end()

static JsonParseErrorType get_object_end ( void *  state)
static

Definition at line 1176 of file jsonfuncs.c.

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

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

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

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

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

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

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

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

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

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

3615 {
3616  cache->argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
3617  prepare_column_cache(&cache->c,
3618  cache->argtype, -1,
3619  cache->fn_mcxt, false);
3620  if (cache->c.typcat != TYPECAT_COMPOSITE &&
3621  cache->c.typcat != TYPECAT_COMPOSITE_DOMAIN)
3622  ereport(ERROR,
3623  (errcode(ERRCODE_DATATYPE_MISMATCH),
3624  /* translator: %s is a function name, eg json_to_record */
3625  errmsg("first argument of %s must be a row type",
3626  funcname)));
3627 }
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1910
static void prepare_column_cache(ColumnIOData *column, Oid typid, int32 typmod, MemoryContext mcxt, bool need_scalar)
Definition: jsonfuncs.c:3241
TypeCat typcat
Definition: jsonfuncs.c:214
FmgrInfo * flinfo
Definition: fmgr.h:87
ColumnIOData c
Definition: jsonfuncs.c:239
MemoryContext fn_mcxt
Definition: jsonfuncs.c:240

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

3641 {
3642  TupleDesc tupdesc;
3643  MemoryContext old_cxt;
3644 
3645  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
3646  ereport(ERROR,
3647  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3648  /* translator: %s is a function name, eg json_to_record */
3649  errmsg("could not determine row type for result of %s",
3650  funcname),
3651  errhint("Provide a non-null record argument, "
3652  "or call the function in the FROM clause "
3653  "using a column definition list.")));
3654 
3655  Assert(tupdesc);
3656  cache->argtype = tupdesc->tdtypeid;
3657 
3658  /* If we go through this more than once, avoid memory leak */
3659  if (cache->c.io.composite.tupdesc)
3661 
3662  /* Save identified tupdesc */
3663  old_cxt = MemoryContextSwitchTo(cache->fn_mcxt);
3664  cache->c.io.composite.tupdesc = CreateTupleDescCopy(tupdesc);
3665  cache->c.io.composite.base_typid = tupdesc->tdtypeid;
3666  cache->c.io.composite.base_typmod = tupdesc->tdtypmod;
3667  MemoryContextSwitchTo(old_cxt);
3668 }
int errhint(const char *fmt,...)
Definition: elog.c:1319
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:220
union ColumnIOData::@26 io
int32 base_typmod
Definition: jsonfuncs.c:183
TupleDesc tupdesc
Definition: jsonfuncs.c:180
int32 tdtypmod
Definition: tupdesc.h:83
Oid tdtypeid
Definition: tupdesc.h:82
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:331
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:133

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

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

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, token, 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 1100 of file jsonfuncs.c.

1105 {
1106  JsonSemAction *sem = palloc0(sizeof(JsonSemAction));
1107  GetState *state = palloc0(sizeof(GetState));
1108 
1109  Assert(npath >= 0);
1110 
1111  state->lex = makeJsonLexContext(NULL, json, true);
1112 
1113  /* is it "_as_text" variant? */
1114  state->normalize_results = normalize_results;
1115  state->npath = npath;
1116  state->path_names = tpath;
1117  state->path_indexes = ipath;
1118  state->pathok = palloc0(sizeof(bool) * npath);
1119  state->array_cur_index = palloc(sizeof(int) * npath);
1120 
1121  if (npath > 0)
1122  state->pathok[0] = true;
1123 
1124  sem->semstate = (void *) state;
1125 
1126  /*
1127  * Not all variants need all the semantic routines. Only set the ones that
1128  * are actually needed for maximum efficiency.
1129  */
1130  sem->scalar = get_scalar;
1131  if (npath == 0)
1132  {
1137  }
1138  if (tpath != NULL)
1139  {
1142  }
1143  if (ipath != NULL)
1144  {
1148  }
1149 
1151  freeJsonLexContext(state->lex);
1152 
1153  return state->tresult;
1154 }
static JsonParseErrorType get_array_element_end(void *state, bool isnull)
Definition: jsonfuncs.c:1398
static JsonParseErrorType get_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:1194
static JsonParseErrorType get_object_start(void *state)
Definition: jsonfuncs.c:1157
static JsonParseErrorType get_array_start(void *state)
Definition: jsonfuncs.c:1292
static JsonParseErrorType get_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:1442
static JsonParseErrorType get_object_end(void *state)
Definition: jsonfuncs.c:1176
static JsonParseErrorType get_object_field_end(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:1241
static JsonParseErrorType get_array_end(void *state)
Definition: jsonfuncs.c:1332
static JsonParseErrorType get_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:1350
json_struct_action array_end
Definition: jsonapi.h:138
json_struct_action object_end
Definition: jsonapi.h:136

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

3907 {
3908  JHashState *_state = (JHashState *) state;
3909 
3910  if (_state->lex->lex_level == 0)
3911  ereport(ERROR,
3912  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3913  errmsg("cannot call %s on an array", _state->function_name)));
3914 
3915  return JSON_SUCCESS;
3916 }
const char * function_name
Definition: jsonfuncs.c:138
JsonLexContext * lex
Definition: jsonfuncs.c:137

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

3856 {
3857  JHashState *_state = (JHashState *) state;
3858  JsonHashEntry *hashentry;
3859  bool found;
3860 
3861  /*
3862  * Ignore nested fields.
3863  */
3864  if (_state->lex->lex_level > 1)
3865  return JSON_SUCCESS;
3866 
3867  /*
3868  * Ignore field names >= NAMEDATALEN - they can't match a record field.
3869  * (Note: without this test, the hash code would truncate the string at
3870  * NAMEDATALEN-1, and could then match against a similarly-truncated
3871  * record field name. That would be a reasonable behavior, but this code
3872  * has previously insisted on exact equality, so we keep this behavior.)
3873  */
3874  if (strlen(fname) >= NAMEDATALEN)
3875  return JSON_SUCCESS;
3876 
3877  hashentry = hash_search(_state->hash, fname, HASH_ENTER, &found);
3878 
3879  /*
3880  * found being true indicates a duplicate. We don't do anything about
3881  * that, a later field with the same name overrides the earlier field.
3882  */
3883 
3884  hashentry->type = _state->saved_token_type;
3885  Assert(isnull == (hashentry->type == JSON_TOKEN_NULL));
3886 
3887  if (_state->save_json_start != NULL)
3888  {
3889  int len = _state->lex->prev_token_terminator - _state->save_json_start;
3890  char *val = palloc((len + 1) * sizeof(char));
3891 
3892  memcpy(val, _state->save_json_start, len);
3893  val[len] = '\0';
3894  hashentry->val = val;
3895  }
3896  else
3897  {
3898  /* must have had a scalar instead */
3899  hashentry->val = _state->saved_scalar;
3900  }
3901 
3902  return JSON_SUCCESS;
3903 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
@ HASH_ENTER
Definition: hsearch.h:114
char * saved_scalar
Definition: jsonfuncs.c:140
JsonTokenType saved_token_type
Definition: jsonfuncs.c:142
char * save_json_start
Definition: jsonfuncs.c:141
HTAB * hash
Definition: jsonfuncs.c:139
char * val
Definition: jsonfuncs.c:149
JsonTokenType type
Definition: jsonfuncs.c:150

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

3830 {
3831  JHashState *_state = (JHashState *) state;
3832 
3833  if (_state->lex->lex_level > 1)
3834  return JSON_SUCCESS;
3835 
3836  /* remember token type */
3837  _state->saved_token_type = _state->lex->token_type;
3838 
3839  if (_state->lex->token_type == JSON_TOKEN_ARRAY_START ||
3841  {
3842  /* remember start position of the whole text of the subobject */
3843  _state->save_json_start = _state->lex->token_start;
3844  }
3845  else
3846  {
3847  /* must be a scalar */
3848  _state->save_json_start = NULL;
3849  }
3850 
3851  return JSON_SUCCESS;
3852 }
@ JSON_TOKEN_OBJECT_START
Definition: jsonapi.h:24
@ JSON_TOKEN_ARRAY_START
Definition: jsonapi.h:26

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

3920 {
3921  JHashState *_state = (JHashState *) state;
3922 
3923  if (_state->lex->lex_level == 0)
3924  ereport(ERROR,
3925  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3926  errmsg("cannot call %s on a scalar", _state->function_name)));
3927 
3928  if (_state->lex->lex_level == 1)
3929  {
3930  _state->saved_scalar = token;
3931  /* saved_token_type must already be set in hash_object_field_start() */
3932  Assert(_state->saved_token_type == tokentype);
3933  }
3934 
3935  return JSON_SUCCESS;
3936 }

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

5688 {
5689  JsonLexContext lex;
5690  JsonSemAction *sem = palloc0(sizeof(JsonSemAction));
5692 
5693  state->lex = makeJsonLexContext(&lex, json, true);
5694  state->action = action;
5695  state->action_state = action_state;
5696  state->flags = flags;
5697 
5698  sem->semstate = (void *) state;
5701 
5703  freeJsonLexContext(&lex);
5704 }
static JsonParseErrorType iterate_values_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:5739
static JsonParseErrorType iterate_values_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:5711

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

5620 {
5621  JsonbIterator *it;
5622  JsonbValue v;
5624 
5625  it = JsonbIteratorInit(&jb->root);
5626 
5627  /*
5628  * Just recursively iterating over jsonb and call callback on all
5629  * corresponding elements
5630  */
5631  while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
5632  {
5633  if (type == WJB_KEY)
5634  {
5635  if (flags & jtiKey)
5636  action(state, v.val.string.val, v.val.string.len);
5637 
5638  continue;
5639  }
5640  else if (!(type == WJB_VALUE || type == WJB_ELEM))
5641  {
5642  /* do not call callback for composite JsonbValue */
5643  continue;
5644  }
5645 
5646  /* JsonbValue is a value of object or element of array */
5647  switch (v.type)
5648  {
5649  case jbvString:
5650  if (flags & jtiString)
5651  action(state, v.val.string.val, v.val.string.len);
5652  break;
5653  case jbvNumeric:
5654  if (flags & jtiNumeric)
5655  {
5656  char *val;
5657 
5659  NumericGetDatum(v.val.numeric)));
5660 
5661  action(state, val, strlen(val));
5662  pfree(val);
5663  }
5664  break;
5665  case jbvBool:
5666  if (flags & jtiBool)
5667  {
5668  if (v.val.boolean)
5669  action(state, "true", 4);
5670  else
5671  action(state, "false", 5);
5672  }
5673  break;
5674  default:
5675  /* do not call callback for composite JsonbValue */
5676  break;
5677  }
5678  }
5679 }
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:807
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:642
@ jbvNumeric
Definition: jsonb.h:230
@ jbvBool
Definition: jsonb.h:231
@ WJB_VALUE
Definition: jsonb.h:24
@ jtiKey
Definition: jsonfuncs.h:27
@ jtiNumeric
Definition: jsonfuncs.h:29
@ jtiBool
Definition: jsonfuncs.h:30
@ jtiString
Definition: jsonfuncs.h:28
void pfree(void *pointer)
Definition: mcxt.c:1520
static Datum NumericGetDatum(Numeric X)
Definition: numeric.h:73
static char * DatumGetCString(Datum X)
Definition: postgres.h:335
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 5739 of file jsonfuncs.c.

5740 {
5742 
5743  if (_state->flags & jtiKey)
5744  {
5745  char *val = pstrdup(fname);
5746 
5747  _state->action(_state->action_state, val, strlen(val));
5748  }
5749 
5750  return JSON_SUCCESS;
5751 }
char * pstrdup(const char *in)
Definition: mcxt.c:1695
JsonIterateStringValuesAction action
Definition: jsonfuncs.c:67

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

5712 {
5714 
5715  switch (tokentype)
5716  {
5717  case JSON_TOKEN_STRING:
5718  if (_state->flags & jtiString)
5719  _state->action(_state->action_state, token, strlen(token));
5720  break;
5721  case JSON_TOKEN_NUMBER:
5722  if (_state->flags & jtiNumeric)
5723  _state->action(_state->action_state, token, strlen(token));
5724  break;
5725  case JSON_TOKEN_TRUE:
5726  case JSON_TOKEN_FALSE:
5727  if (_state->flags & jtiBool)
5728  _state->action(_state->action_state, token, strlen(token));
5729  break;
5730  default:
5731  /* do not call callback for any other token */
5732  break;
5733  }
5734 
5735  return JSON_SUCCESS;
5736 }
@ JSON_TOKEN_FALSE
Definition: jsonapi.h:31
@ JSON_TOKEN_TRUE
Definition: jsonapi.h:30
@ JSON_TOKEN_NUMBER
Definition: jsonapi.h:23

References IterateJsonStringValuesState::action, IterateJsonStringValuesState::action_state, IterateJsonStringValuesState::flags, JSON_SUCCESS, JSON_TOKEN_FALSE, JSON_TOKEN_NUMBER, JSON_TOKEN_STRING, JSON_TOKEN_TRUE, jtiBool, jtiNumeric, jtiString, and token.

Referenced by iterate_json_values().

◆ IteratorConcat()

static JsonbValue * IteratorConcat ( JsonbIterator **  it1,
JsonbIterator **  it2,
JsonbParseState **  state 
)
static

Definition at line 5030 of file jsonfuncs.c.

5032 {
5033  JsonbValue v1,
5034  v2,
5035  *res = NULL;
5036  JsonbIteratorToken r1,
5037  r2,
5038  rk1,
5039  rk2;
5040 
5041  rk1 = JsonbIteratorNext(it1, &v1, false);
5042  rk2 = JsonbIteratorNext(it2, &v2, false);
5043 
5044  /*
5045  * JsonbIteratorNext reports raw scalars as if they were single-element
5046  * arrays; hence we only need consider "object" and "array" cases here.
5047  */
5048  if (rk1 == WJB_BEGIN_OBJECT && rk2 == WJB_BEGIN_OBJECT)
5049  {
5050  /*
5051  * Both inputs are objects.
5052  *
5053  * Append all the tokens from v1 to res, except last WJB_END_OBJECT
5054  * (because res will not be finished yet).
5055  */
5056  pushJsonbValue(state, rk1, NULL);
5057  while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_OBJECT)
5058  pushJsonbValue(state, r1, &v1);
5059 
5060  /*
5061  * Append all the tokens from v2 to res, including last WJB_END_OBJECT
5062  * (the concatenation will be completed). Any duplicate keys will
5063  * automatically override the value from the first object.
5064  */
5065  while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5066  res = pushJsonbValue(state, r2, r2 != WJB_END_OBJECT ? &v2 : NULL);
5067  }
5068  else if (rk1 == WJB_BEGIN_ARRAY && rk2 == WJB_BEGIN_ARRAY)
5069  {
5070  /*
5071  * Both inputs are arrays.
5072  */
5073  pushJsonbValue(state, rk1, NULL);
5074 
5075  while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_ARRAY)
5076  {
5077  Assert(r1 == WJB_ELEM);
5078  pushJsonbValue(state, r1, &v1);
5079  }
5080 
5081  while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_END_ARRAY)
5082  {
5083  Assert(r2 == WJB_ELEM);
5084  pushJsonbValue(state, WJB_ELEM, &v2);
5085  }
5086 
5087  res = pushJsonbValue(state, WJB_END_ARRAY, NULL /* signal to sort */ );
5088  }
5089  else if (rk1 == WJB_BEGIN_OBJECT)
5090  {
5091  /*
5092  * We have object || array.
5093  */
5094  Assert(rk2 == WJB_BEGIN_ARRAY);
5095 
5097 
5099  while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_DONE)
5100  pushJsonbValue(state, r1, r1 != WJB_END_OBJECT ? &v1 : NULL);
5101 
5102  while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5103  res = pushJsonbValue(state, r2, r2 != WJB_END_ARRAY ? &v2 : NULL);
5104  }
5105  else
5106  {
5107  /*
5108  * We have array || object.
5109  */
5110  Assert(rk1 == WJB_BEGIN_ARRAY);
5111  Assert(rk2 == WJB_BEGIN_OBJECT);
5112 
5114 
5115  while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_ARRAY)
5116  pushJsonbValue(state, r1, &v1);
5117 
5119  while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5120  pushJsonbValue(state, r2, r2 != WJB_END_OBJECT ? &v2 : NULL);
5121 
5123  }
5124 
5125  return res;
5126 }
@ WJB_END_ARRAY
Definition: jsonb.h:27
@ WJB_END_OBJECT
Definition: jsonb.h:29
@ WJB_BEGIN_OBJECT
Definition: jsonb.h:28
@ WJB_BEGIN_ARRAY
Definition: jsonb.h:26
JsonbValue * pushJsonbValue(JsonbParseState **pstate, JsonbIteratorToken seq, JsonbValue *jbval)
Definition: jsonb_util.c:566

References Assert, JsonbIteratorNext(), pushJsonbValue(), res, 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 3469 of file jsonfuncs.c.

3470 {
3471  jsv->is_json = obj->is_json;
3472 
3473  if (jsv->is_json)
3474  {
3475  JsonHashEntry *hashentry = hash_search(obj->val.json_hash, field,
3476  HASH_FIND, NULL);
3477 
3478  jsv->val.json.type = hashentry ? hashentry->type : JSON_TOKEN_NULL;
3479  jsv->val.json.str = jsv->val.json.type == JSON_TOKEN_NULL ? NULL :
3480  hashentry->val;
3481  jsv->val.json.len = jsv->val.json.str ? -1 : 0; /* null-terminated */
3482 
3483  return hashentry != NULL;
3484  }
3485  else
3486  {
3487  jsv->val.jsonb = !obj->val.jsonb_cont ? NULL :
3488  getKeyJsonValueFromContainer(obj->val.jsonb_cont, field, strlen(field),
3489  NULL);
3490 
3491  return jsv->val.jsonb != NULL;
3492  }
3493 }
@ HASH_FIND
Definition: hsearch.h:113
JsonbValue * getKeyJsonValueFromContainer(JsonbContainer *container, const char *keyVal, int keyLen, JsonbValue *res)
Definition: jsonb_util.c:398
bool is_json
Definition: jsonfuncs.c:309
JsonbContainer * jsonb_cont
Definition: jsonfuncs.c:313
HTAB * json_hash
Definition: jsonfuncs.c:312
union JsObject::@29 val
union JsValue::@27 val
JsonbValue * jsonb
Definition: jsonfuncs.c:303
struct JsValue::@27::@28 json
bool is_json
Definition: jsonfuncs.c:293

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, JsonHashEntry::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 919 of file jsonfuncs.c.

920 {
921  text *json = PG_GETARG_TEXT_PP(0);
922  int element = PG_GETARG_INT32(1);
923  text *result;
924 
925  result = get_worker(json, NULL, &element, 1, false);
926 
927  if (result != NULL)
928  PG_RETURN_TEXT_P(result);
929  else
930  PG_RETURN_NULL();
931 }
#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 962 of file jsonfuncs.c.

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

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);
1852  AlenState *state;
1853  JsonLexContext lex;
1854  JsonSemAction *sem;
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 = (void *) state;
1866  sem->scalar = alen_scalar;
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 5953 of file jsonfuncs.c.

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

640 {
644  errsave(escontext,
645  (errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
646  errmsg("unsupported Unicode escape sequence"),
648  report_json_context(lex)));
649  else if (error == JSON_SEM_ACTION_FAILED)
650  {
651  /* semantic action function had better have reported something */
652  if (!SOFT_ERROR_OCCURRED(escontext))
653  elog(ERROR, "JSON semantic action function did not provide error information");
654  }
655  else
656  errsave(escontext,
657  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
658  errmsg("invalid input syntax for type %s", "json"),
660  report_json_context(lex)));
661 }
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1232
#define errsave(context,...)
Definition: elog.h:260
#define elog(elevel,...)
Definition: elog.h:224
char * json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
Definition: jsonapi.c:2096
@ JSON_SEM_ACTION_FAILED
Definition: jsonapi.h:60
@ JSON_UNICODE_CODE_POINT_ZERO
Definition: jsonapi.h:54
@ JSON_UNICODE_UNTRANSLATABLE
Definition: jsonapi.h:57
@ JSON_UNICODE_HIGH_ESCAPE
Definition: jsonapi.h:56
static int report_json_context(JsonLexContext *lex)
Definition: jsonfuncs.c:674
#define SOFT_ERROR_OCCURRED(escontext)
Definition: miscnodes.h:52

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

1007 {
1008  return get_path_all(fcinfo, false);
1009 }
static Datum get_path_all(FunctionCallInfo fcinfo, bool as_text)
Definition: jsonfuncs.c:1021

References get_path_all().

◆ json_extract_path_text()

Datum json_extract_path_text ( PG_FUNCTION_ARGS  )

Definition at line 1012 of file jsonfuncs.c.

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

References get_path_all().

◆ json_get_first_token()

JsonTokenType json_get_first_token ( text json,
bool  throw_error 
)

Definition at line 5926 of file jsonfuncs.c.

5927 {
5928  JsonLexContext lex;
5929  JsonParseErrorType result;
5930 
5931  makeJsonLexContext(&lex, json, false);
5932 
5933  /* Lex exactly one token from the input and check its type. */
5934  result = json_lex(&lex);
5935 
5936  if (result == JSON_SUCCESS)
5937  return lex.token_type;
5938 
5939  if (throw_error)
5940  json_errsave_error(result, &lex, NULL);
5941 
5942  return JSON_TOKEN_INVALID; /* invalid json */
5943 }
JsonParseErrorType json_lex(JsonLexContext *lex)
Definition: jsonapi.c:1308
@ JSON_TOKEN_INVALID
Definition: jsonapi.h:21

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

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

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

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

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

730 {
731  FuncCallContext *funcctx;
732  OkeysState *state;
733 
734  if (SRF_IS_FIRSTCALL())
735  {
736  text *json = PG_GETARG_TEXT_PP(0);
737  JsonLexContext lex;
739  MemoryContext oldcontext;
740 
741  funcctx = SRF_FIRSTCALL_INIT();
742  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
743 
744  state = palloc(sizeof(OkeysState));
745  sem = palloc0(sizeof(JsonSemAction));
746 
747  state->lex = makeJsonLexContext(&lex, json, true);
748  state->result_size = 256;
749  state->result_count = 0;
750  state->sent_count = 0;
751  state->result = palloc(256 * sizeof(char *));
752 
753  sem->semstate = (void *) state;
757  /* remainder are all NULL, courtesy of palloc0 above */
758 
760  /* keys are now in state->result */
761 
762  freeJsonLexContext(&lex);
763  pfree(sem);
764 
765  MemoryContextSwitchTo(oldcontext);
766  funcctx->user_fctx = (void *) state;
767  }
768 
769  funcctx = SRF_PERCALL_SETUP();
770  state = (OkeysState *) funcctx->user_fctx;
771 
772  if (state->sent_count < state->result_count)
773  {
774  char *nxt = state->result[state->sent_count++];
775 
776  SRF_RETURN_NEXT(funcctx, CStringGetTextDatum(nxt));
777  }
778 
779  SRF_RETURN_DONE(funcctx);
780 }
#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:77
static JsonParseErrorType okeys_array_start(void *state)
Definition: jsonfuncs.c:806
static JsonParseErrorType okeys_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:783
static JsonParseErrorType okeys_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:821
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:3675

References populate_record_worker().

◆ json_populate_recordset()

Datum json_populate_recordset ( PG_FUNCTION_ARGS  )

Definition at line 3964 of file jsonfuncs.c.

3965 {
3966  return populate_recordset_worker(fcinfo, "json_populate_recordset",
3967  true, true);
3968 }
static Datum populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname, bool is_json, bool have_record_arg)
Definition: jsonfuncs.c:4017

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,
Node escontext 
)

Definition at line 3335 of file jsonfuncs.c.

3340 {
3341  JsValue jsv = {0};
3342  JsonbValue jbv;
3343 
3344  jsv.is_json = json_type == JSONOID;
3345 
3346  if (*isnull)
3347  {
3348  if (jsv.is_json)
3349  jsv.val.json.str = NULL;
3350  else
3351  jsv.val.jsonb = NULL;
3352  }
3353  else if (jsv.is_json)
3354  {
3355  text *json = DatumGetTextPP(json_val);
3356 
3357  jsv.val.json.str = VARDATA_ANY(json);
3358  jsv.val.json.len = VARSIZE_ANY_EXHDR(json);
3359  jsv.val.json.type = JSON_TOKEN_INVALID; /* not used in
3360  * populate_composite() */
3361  }
3362  else
3363  {
3364  Jsonb *jsonb = DatumGetJsonbP(json_val);
3365 
3366  jsv.val.jsonb = &jbv;
3367 
3368  /* fill binary jsonb value pointing to jb */
3369  jbv.type = jbvBinary;
3370  jbv.val.binary.data = &jsonb->root;
3371  jbv.val.binary.len = VARSIZE(jsonb) - VARHDRSZ;
3372  }
3373 
3374  if (*cache == NULL)
3375  *cache = MemoryContextAllocZero(mcxt, sizeof(ColumnIOData));
3376 
3377  return populate_record_field(*cache, typid, typmod, NULL, mcxt,
3378  PointerGetDatum(NULL), &jsv, isnull,
3379  escontext);
3380 }
#define VARHDRSZ
Definition: c.h:692
#define DatumGetTextPP(X)
Definition: fmgr.h:292
@ jbvBinary
Definition: jsonb.h:236
static Jsonb * DatumGetJsonbP(Datum d)
Definition: jsonb.h:374
static Datum populate_record_field(ColumnIOData *col, Oid typid, int32 typmod, const char *colname, MemoryContext mcxt, Datum defaultval, JsValue *jsv, bool *isnull, Node *escontext)
Definition: jsonfuncs.c:3384
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1214
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define VARSIZE(PTR)
Definition: varatt.h:279
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317

References DatumGetJsonbP(), DatumGetTextPP, JsValue::is_json, jbvBinary, JsValue::json, JSON_TOKEN_INVALID, JsValue::jsonb, MemoryContextAllocZero(), PointerGetDatum(), populate_record_field(), Jsonb::root, 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 4470 of file jsonfuncs.c.

4471 {
4472  text *json = PG_GETARG_TEXT_PP(0);
4474  JsonLexContext lex;
4475  JsonSemAction *sem;
4476 
4477  state = palloc0(sizeof(StripnullState));
4478  sem = palloc0(sizeof(JsonSemAction));
4479 
4480  state->lex = makeJsonLexContext(&lex, json, true);
4481  state->strval = makeStringInfo();
4482  state->skip_next_null = false;
4483 
4484  sem->semstate = (void *) state;
4489  sem->scalar = sn_scalar;
4492 
4494 
4496  state->strval->len));
4497 }
static JsonParseErrorType sn_object_end(void *state)
Definition: jsonfuncs.c:4376
static JsonParseErrorType sn_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:4436
static JsonParseErrorType sn_object_start(void *state)
Definition: jsonfuncs.c:4366
static JsonParseErrorType sn_array_start(void *state)
Definition: jsonfuncs.c:4386
static JsonParseErrorType sn_array_end(void *state)
Definition: jsonfuncs.c:4396
static JsonParseErrorType sn_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:4406
static JsonParseErrorType sn_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:4447
StringInfo makeStringInfo(void)
Definition: stringinfo.c:41

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

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

References populate_recordset_worker().

◆ jsonb_array_element()

Datum jsonb_array_element ( PG_FUNCTION_ARGS  )

Definition at line 934 of file jsonfuncs.c.

935 {
936  Jsonb *jb = PG_GETARG_JSONB_P(0);
937  int element = PG_GETARG_INT32(1);
938  JsonbValue *v;
939 
940  if (!JB_ROOT_IS_ARRAY(jb))
941  PG_RETURN_NULL();
942 
943  /* Handle negative subscript */
944  if (element < 0)
945  {
946  uint32 nelements = JB_ROOT_COUNT(jb);
947 
948  if (-element > nelements)
949  PG_RETURN_NULL();
950  else
951  element += nelements;
952  }
953 
955  if (v != NULL)
957 
958  PG_RETURN_NULL();
959 }
unsigned int uint32
Definition: c.h:506
#define PG_RETURN_JSONB_P(x)
Definition: jsonb.h:393
#define JB_ROOT_COUNT(jbp_)
Definition: jsonb.h:219
JsonbValue * getIthJsonbValueFromContainer(JsonbContainer *container, uint32 i)
Definition: jsonb_util.c:468

References element(), getIthJsonbValueFromContainer(), JB_ROOT_COUNT, JB_ROOT_IS_ARRAY, JsonbValueToJsonb(), 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 977 of file jsonfuncs.c.

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

References element(), getIthJsonbValueFromContainer(), JB_ROOT_COUNT, JB_ROOT_IS_ARRAY, jbvNull, JsonbValueAsText(), 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 4577 of file jsonfuncs.c.

4578 {
4579  Jsonb *jb1 = PG_GETARG_JSONB_P(0);
4580  Jsonb *jb2 = PG_GETARG_JSONB_P(1);
4581  JsonbParseState *state = NULL;
4582  JsonbValue *res;
4583  JsonbIterator *it1,
4584  *it2;
4585 
4586  /*
4587  * If one of the jsonb is empty, just return the other if it's not scalar
4588  * and both are of the same kind. If it's a scalar or they are of
4589  * different kinds we need to perform the concatenation even if one is
4590  * empty.
4591  */
4592  if (JB_ROOT_IS_OBJECT(jb1) == JB_ROOT_IS_OBJECT(jb2))
4593  {
4594  if (JB_ROOT_COUNT(jb1) == 0 && !JB_ROOT_IS_SCALAR(jb2))
4595  PG_RETURN_JSONB_P(jb2);
4596  else if (JB_ROOT_COUNT(jb2) == 0 && !JB_ROOT_IS_SCALAR(jb1))
4597  PG_RETURN_JSONB_P(jb1);
4598  }
4599 
4600  it1 = JsonbIteratorInit(&jb1->root);
4601  it2 = JsonbIteratorInit(&jb2->root);
4602 
4603  res = IteratorConcat(&it1, &it2, &state);
4604 
4605  Assert(res != NULL);
4606 
4608 }
static JsonbValue * IteratorConcat(JsonbIterator **it1, JsonbIterator **it2, JsonbParseState **state)
Definition: jsonfuncs.c:5030

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

◆ jsonb_delete()

Datum jsonb_delete ( PG_FUNCTION_ARGS  )

Definition at line 4618 of file jsonfuncs.c.

4619 {
4620  Jsonb *in = PG_GETARG_JSONB_P(0);
4621  text *key = PG_GETARG_TEXT_PP(1);
4622  char *keyptr = VARDATA_ANY(key);
4623  int keylen = VARSIZE_ANY_EXHDR(key);
4624  JsonbParseState *state = NULL;
4625  JsonbIterator *it;
4626  JsonbValue v,
4627  *res = NULL;
4628  bool skipNested = false;
4630 
4631  if (JB_ROOT_IS_SCALAR(in))
4632  ereport(ERROR,
4633  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4634  errmsg("cannot delete from scalar")));
4635 
4636  if (JB_ROOT_COUNT(in) == 0)
4637  PG_RETURN_JSONB_P(in);
4638 
4639  it = JsonbIteratorInit(&in->root);
4640 
4641  while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4642  {
4643  skipNested = true;
4644 
4645  if ((r == WJB_ELEM || r == WJB_KEY) &&
4646  (v.type == jbvString && keylen == v.val.string.len &&
4647  memcmp(keyptr, v.val.string.val, keylen) == 0))
4648  {
4649  /* skip corresponding value as well */
4650  if (r == WJB_KEY)
4651  (void) JsonbIteratorNext(&it, &v, true);
4652 
4653  continue;
4654  }
4655 
4656  res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4657  }
4658 
4659  Assert(res != NULL);
4660 
4662 }

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

4672 {
4673  Jsonb *in = PG_GETARG_JSONB_P(0);
4674  ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1);
4675  Datum *keys_elems;
4676  bool *keys_nulls;
4677  int keys_len;
4678  JsonbParseState *state = NULL;
4679  JsonbIterator *it;
4680  JsonbValue v,
4681  *res = NULL;
4682  bool skipNested = false;
4684 
4685  if (ARR_NDIM(keys) > 1)
4686  ereport(ERROR,
4687  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4688  errmsg("wrong number of array subscripts")));
4689 
4690  if (JB_ROOT_IS_SCALAR(in))
4691  ereport(ERROR,
4692  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4693  errmsg("cannot delete from scalar")));
4694 
4695  if (JB_ROOT_COUNT(in) == 0)
4696  PG_RETURN_JSONB_P(in);
4697 
4698  deconstruct_array_builtin(keys, TEXTOID, &keys_elems, &keys_nulls, &keys_len);
4699 
4700  if (keys_len == 0)
4701  PG_RETURN_JSONB_P(in);
4702 
4703  it = JsonbIteratorInit(&in->root);
4704 
4705  while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4706  {
4707  skipNested = true;
4708 
4709  if ((r == WJB_ELEM || r == WJB_KEY) && v.type == jbvString)
4710  {
4711  int i;
4712  bool found = false;
4713 
4714  for (i = 0; i < keys_len; i++)
4715  {
4716  char *keyptr;
4717  int keylen;
4718 
4719  if (keys_nulls[i])
4720  continue;
4721 
4722  /* We rely on the array elements not being toasted */
4723  keyptr = VARDATA_ANY(keys_elems[i]);
4724  keylen = VARSIZE_ANY_EXHDR(keys_elems[i]);
4725  if (keylen == v.val.string.len &&
4726  memcmp(keyptr, v.val.string.val, keylen) == 0)
4727  {
4728  found = true;
4729  break;
4730  }
4731  }
4732  if (found)
4733  {
4734  /* skip corresponding value as well */
4735  if (r == WJB_KEY)
4736  (void) JsonbIteratorNext(&it, &v, true);
4737 
4738  continue;
4739  }
4740  }
4741 
4742  res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4743  }
4744 
4745  Assert(res != NULL);
4746 
4748 }
#define ARR_NDIM(a)
Definition: array.h:290

References ARR_NDIM, Assert, deconstruct_array_builtin(), ereport, errcode(), errmsg(), ERROR, i, JB_ROOT_COUNT, JB_ROOT_IS_SCALAR, jbvString, JsonbIteratorInit(), JsonbIteratorNext(), JsonbValueToJsonb(), PG_GETARG_ARRAYTYPE_P, PG_GETARG_JSONB_P, PG_RETURN_JSONB_P, pushJsonbValue(), res, 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 4758 of file jsonfuncs.c.

4759 {
4760  Jsonb *in = PG_GETARG_JSONB_P(0);
4761  int idx = PG_GETARG_INT32(1);
4762  JsonbParseState *state = NULL;
4763  JsonbIterator *it;
4764  uint32 i = 0,
4765  n;
4766  JsonbValue v,
4767  *res = NULL;
4769 
4770  if (JB_ROOT_IS_SCALAR(in))
4771  ereport(ERROR,
4772  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4773  errmsg("cannot delete from scalar")));
4774 
4775  if (JB_ROOT_IS_OBJECT(in))
4776  ereport(ERROR,
4777  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4778  errmsg("cannot delete from object using integer index")));
4779 
4780  if (JB_ROOT_COUNT(in) == 0)
4781  PG_RETURN_JSONB_P(in);
4782 
4783  it = JsonbIteratorInit(&in->root);
4784 
4785  r = JsonbIteratorNext(&it, &v, false);
4786  Assert(r == WJB_BEGIN_ARRAY);
4787  n = v.val.array.nElems;
4788 
4789  if (idx < 0)
4790  {
4791  if (-idx > n)
4792  idx = n;
4793  else
4794  idx = n + idx;
4795  }
4796 
4797  if (idx >= n)
4798  PG_RETURN_JSONB_P(in);
4799 
4800  pushJsonbValue(&state, r, NULL);
4801 
4802  while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
4803  {
4804  if (r == WJB_ELEM)
4805  {
4806  if (i++ == idx)
4807  continue;
4808  }
4809 
4810  res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4811  }
4812 
4813  Assert(res != NULL);
4814 
4816 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259

References Assert, ereport, errcode(), errmsg(), ERROR, i, idx(), JB_ROOT_COUNT, JB_ROOT_IS_OBJECT, JB_ROOT_IS_SCALAR, JsonbIteratorInit(), JsonbIteratorNext(), JsonbValueToJsonb(), PG_GETARG_INT32, PG_GETARG_JSONB_P, PG_RETURN_JSONB_P, pushJsonbValue(), res, 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 4938 of file jsonfuncs.c.

4939 {
4940  Jsonb *in = PG_GETARG_JSONB_P(0);
4941  ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
4942  JsonbValue *res = NULL;
4943  Datum *path_elems;
4944  bool *path_nulls;
4945  int path_len;
4946  JsonbIterator *it;
4947  JsonbParseState *st = NULL;
4948 
4949  if (ARR_NDIM(path) > 1)
4950  ereport(ERROR,
4951  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4952  errmsg("wrong number of array subscripts")));
4953 
4954  if (JB_ROOT_IS_SCALAR(in))
4955  ereport(ERROR,
4956  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4957  errmsg("cannot delete path in scalar")));
4958 
4959  if (JB_ROOT_COUNT(in) == 0)
4960  PG_RETURN_JSONB_P(in);
4961 
4962  deconstruct_array_builtin(path, TEXTOID, &path_elems, &path_nulls, &path_len);
4963 
4964  if (path_len == 0)
4965  PG_RETURN_JSONB_P(in);
4966 
4967  it = JsonbIteratorInit(&in->root);
4968 
4969  res = setPath(&it, path_elems, path_nulls, path_len, &st,
4970  0, NULL, JB_PATH_DELETE);
4971 
4972  Assert(res != NULL);
4973 
4975 }
static JsonbValue * setPath(JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, JsonbParseState **st, int level, JsonbValue *newval, int op_type)
Definition: jsonfuncs.c:5158
#define JB_PATH_DELETE
Definition: jsonfuncs.c:44

References ARR_NDIM, Assert, deconstruct_array_builtin(), ereport, errcode(), errmsg(), ERROR, JB_PATH_DELETE, JB_ROOT_COUNT, JB_ROOT_IS_SCALAR, JsonbIteratorInit(), JsonbValueToJsonb(), PG_GETARG_ARRAYTYPE_P, PG_GETARG_JSONB_P, PG_RETURN_JSONB_P, res, 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 1485 of file jsonfuncs.c.

1486 {
1487  return get_jsonb_path_all(fcinfo, false);
1488 }
static Datum get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
Definition: jsonfuncs.c:1497

References get_jsonb_path_all().

◆ jsonb_extract_path_text()

Datum jsonb_extract_path_text ( PG_FUNCTION_ARGS  )

Definition at line 1491 of file jsonfuncs.c.

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

References get_jsonb_path_all().

◆ jsonb_get_element()

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

Definition at line 1528 of file jsonfuncs.c.

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

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(), res, 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 4981 of file jsonfuncs.c.

4982 {
4983  Jsonb *in = PG_GETARG_JSONB_P(0);
4984  ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
4985  Jsonb *newjsonb = PG_GETARG_JSONB_P(2);
4987  bool after = PG_GETARG_BOOL(3);
4988  JsonbValue *res = NULL;
4989  Datum *path_elems;
4990  bool *path_nulls;
4991  int path_len;
4992  JsonbIterator *it;
4993  JsonbParseState *st = NULL;
4994 
4995  JsonbToJsonbValue(newjsonb, &newval);
4996 
4997  if (ARR_NDIM(path) > 1)
4998  ereport(ERROR,
4999  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
5000  errmsg("wrong number of array subscripts")));
5001 
5002  if (JB_ROOT_IS_SCALAR(in))
5003  ereport(ERROR,
5004  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5005  errmsg("cannot set path in scalar")));
5006 
5007  deconstruct_array_builtin(path, TEXTOID, &path_elems, &path_nulls, &path_len);
5008 
5009  if (path_len == 0)
5010  PG_RETURN_JSONB_P(in);
5011 
5012  it = JsonbIteratorInit(&in->root);
5013 
5014  res = setPath(&it, path_elems, path_nulls, path_len, &st, 0, &newval,
5016 
5017  Assert(res != NULL);
5018 
5020 }
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
#define newval
void JsonbToJsonbValue(Jsonb *jsonb, JsonbValue *val)
Definition: jsonb_util.c:72
#define JB_PATH_INSERT_BEFORE
Definition: jsonfuncs.c:46
#define JB_PATH_INSERT_AFTER
Definition: jsonfuncs.c:47

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

◆ jsonb_object_field()

Datum jsonb_object_field ( PG_FUNCTION_ARGS  )

Definition at line 859 of file jsonfuncs.c.

860 {
861  Jsonb *jb = PG_GETARG_JSONB_P(0);
862  text *key = PG_GETARG_TEXT_PP(1);
863  JsonbValue *v;
864  JsonbValue vbuf;
865 
866  if (!JB_ROOT_IS_OBJECT(jb))
867  PG_RETURN_NULL();
868 
870  VARDATA_ANY(key),
872  &vbuf);
873 
874  if (v != NULL)
876 
877  PG_RETURN_NULL();
878 }

References getKeyJsonValueFromContainer(), JB_ROOT_IS_OBJECT, JsonbValueToJsonb(), sort-test::key, PG_GETARG_JSONB_P, PG_GETARG_TEXT_PP, PG_RETURN_JSONB_P, PG_RETURN_NULL, Jsonb::root, VARDATA_ANY, and VARSIZE_ANY_EXHDR.

◆ jsonb_object_field_text()

Datum jsonb_object_field_text ( PG_FUNCTION_ARGS  )

Definition at line 897 of file jsonfuncs.c.

898 {
899  Jsonb *jb = PG_GETARG_JSONB_P(0);
900  text *key = PG_GETARG_TEXT_PP(1);
901  JsonbValue *v;
902  JsonbValue vbuf;
903 
904  if (!JB_ROOT_IS_OBJECT(jb))
905  PG_RETURN_NULL();
906 
908  VARDATA_ANY(key),
910  &vbuf);
911 
912  if (v != NULL && v->type != jbvNull)
914 
915  PG_RETURN_NULL();
916 }

References getKeyJsonValueFromContainer(), JB_ROOT_IS_OBJECT, jbvNull, JsonbValueAsText(), sort-test::key, PG_GETARG_JSONB_P, PG_GETARG_TEXT_PP, PG_RETURN_NULL, PG_RETURN_TEXT_P, Jsonb::root, JsonbValue::type, VARDATA_ANY, and VARSIZE_ANY_EXHDR.

◆ jsonb_object_keys()

Datum jsonb_object_keys ( PG_FUNCTION_ARGS  )

Definition at line 565 of file jsonfuncs.c.

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

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:102
bool error_occurred
Definition: miscnodes.h:46
Definition: nodes.h:129

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

◆ jsonb_populate_recordset()

Datum jsonb_populate_recordset ( PG_FUNCTION_ARGS  )

Definition at line 3950 of file jsonfuncs.c.

3951 {
3952  return populate_recordset_worker(fcinfo, "jsonb_populate_recordset",
3953  false, true);
3954 }

References populate_recordset_worker().

◆ jsonb_pretty()

Datum jsonb_pretty ( PG_FUNCTION_ARGS  )

Definition at line 4561 of file jsonfuncs.c.

4562 {
4563  Jsonb *jb = PG_GETARG_JSONB_P(0);
4565 
4566  JsonbToCStringIndent(str, &jb->root, VARSIZE(jb));
4567 
4569 }
const char * str
char * JsonbToCStringIndent(StringInfo out, JsonbContainer *in, int estimated_len)
Definition: jsonb.c:482

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

◆ jsonb_set()

Datum jsonb_set ( PG_FUNCTION_ARGS  )

Definition at line 4822 of file jsonfuncs.c.

4823 {
4824  Jsonb *in = PG_GETARG_JSONB_P(0);
4825  ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
4826  Jsonb *newjsonb = PG_GETARG_JSONB_P(2);
4828  bool create = PG_GETARG_BOOL(3);
4829  JsonbValue *res = NULL;
4830  Datum *path_elems;
4831  bool *path_nulls;
4832  int path_len;
4833  JsonbIterator *it;
4834  JsonbParseState *st = NULL;
4835 
4836  JsonbToJsonbValue(newjsonb, &newval);
4837 
4838  if (ARR_NDIM(path) > 1)
4839  ereport(ERROR,
4840  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4841  errmsg("wrong number of array subscripts")));
4842 
4843  if (JB_ROOT_IS_SCALAR(in))
4844  ereport(ERROR,
4845  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4846  errmsg("cannot set path in scalar")));
4847 
4848  if (JB_ROOT_COUNT(in) == 0 && !create)
4849  PG_RETURN_JSONB_P(in);
4850 
4851  deconstruct_array_builtin(path, TEXTOID, &path_elems, &path_nulls, &path_len);
4852 
4853  if (path_len == 0)
4854  PG_RETURN_JSONB_P(in);
4855 
4856  it = JsonbIteratorInit(&in->root);
4857 
4858  res = setPath(&it, path_elems, path_nulls, path_len, &st,
4859  0, &newval, create ? JB_PATH_CREATE : JB_PATH_REPLACE);
4860 
4861  Assert(res != NULL);
4862 
4864 }
#define JB_PATH_CREATE
Definition: jsonfuncs.c:43
#define JB_PATH_REPLACE
Definition: jsonfuncs.c:45

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

Referenced by jsonb_set_lax().

◆ jsonb_set_element()

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

Definition at line 1676 of file jsonfuncs.c.

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

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

Referenced by jsonb_subscript_assign().

◆ jsonb_set_lax()

Datum jsonb_set_lax ( PG_FUNCTION_ARGS  )

Definition at line 4871 of file jsonfuncs.c.

4872 {
4873  /* Jsonb *in = PG_GETARG_JSONB_P(0); */
4874  /* ArrayType *path = PG_GETARG_ARRAYTYPE_P(1); */
4875  /* Jsonb *newval = PG_GETARG_JSONB_P(2); */
4876  /* bool create = PG_GETARG_BOOL(3); */
4877  text *handle_null;
4878  char *handle_val;
4879 
4880  if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(3))
4881  PG_RETURN_NULL();
4882 
4883  /* could happen if they pass in an explicit NULL */
4884  if (PG_ARGISNULL(4))
4885  ereport(ERROR,
4886  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4887  errmsg("null_value_treatment must be \"delete_key\", \"return_target\", \"use_json_null\", or \"raise_exception\"")));
4888 
4889  /* if the new value isn't an SQL NULL just call jsonb_set */
4890  if (!PG_ARGISNULL(2))
4891  return jsonb_set(fcinfo);
4892 
4893  handle_null = PG_GETARG_TEXT_P(4);
4894  handle_val = text_to_cstring(handle_null);
4895 
4896  if (strcmp(handle_val, "raise_exception") == 0)
4897  {
4898  ereport(ERROR,
4899  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4900  errmsg("JSON value must not be null"),
4901  errdetail("Exception was raised because null_value_treatment is \"raise_exception\"."),
4902  errhint("To avoid, either change the null_value_treatment argument or ensure that an SQL NULL is not passed.")));
4903  return (Datum) 0; /* silence stupider compilers */
4904  }
4905  else if (strcmp(handle_val, "use_json_null") == 0)
4906  {
4907  Datum newval;
4908 
4910 
4911  fcinfo->args[2].value = newval;
4912  fcinfo->args[2].isnull = false;
4913  return jsonb_set(fcinfo);
4914  }
4915  else if (strcmp(handle_val, "delete_key") == 0)
4916  {
4917  return jsonb_delete_path(fcinfo);
4918  }
4919  else if (strcmp(handle_val, "return_target") == 0)
4920  {
4921  Jsonb *in = PG_GETARG_JSONB_P(0);
4922 
4923  PG_RETURN_JSONB_P(in);
4924  }
4925  else
4926  {
4927  ereport(ERROR,
4928  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4929  errmsg("null_value_treatment must be \"delete_key\", \"return_target\", \"use_json_null\", or \"raise_exception\"")));
4930  return (Datum) 0; /* silence stupider compilers */
4931  }
4932 }
int errdetail(const char *fmt,...)
Definition: elog.c:1205
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define PG_GETARG_TEXT_P(n)
Definition: fmgr.h:336
Datum jsonb_in(PG_FUNCTION_ARGS)
Definition: jsonb.c:73
Datum jsonb_delete_path(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4938
Datum jsonb_set(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4822
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350

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

4504 {
4505  Jsonb *jb = PG_GETARG_JSONB_P(0);
4506  JsonbIterator *it;
4507  JsonbParseState *parseState = NULL;
4508  JsonbValue *res = NULL;
4509  JsonbValue v,
4510  k;
4512  bool last_was_key = false;
4513 
4514  if (JB_ROOT_IS_SCALAR(jb))
4515  PG_RETURN_POINTER(jb);
4516 
4517  it = JsonbIteratorInit(&jb->root);
4518 
4519  while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
4520  {
4521  Assert(!(type == WJB_KEY && last_was_key));
4522 
4523  if (type == WJB_KEY)
4524  {
4525  /* stash the key until we know if it has a null value */
4526  k = v;
4527  last_was_key = true;
4528  continue;
4529  }
4530 
4531  if (last_was_key)
4532  {
4533  /* if the last element was a key this one can't be */
4534  last_was_key = false;
4535 
4536  /* skip this field if value is null */
4537  if (type == WJB_VALUE && v.type == jbvNull)
4538  continue;
4539 
4540  /* otherwise, do a delayed push of the key */
4541  (void) pushJsonbValue(&parseState, WJB_KEY, &k);
4542  }
4543 
4544  if (type == WJB_VALUE || type == WJB_ELEM)
4545  res = pushJsonbValue(&parseState, type, &v);
4546  else
4547  res = pushJsonbValue(&parseState, type, NULL);
4548  }
4549 
4550  Assert(res != NULL);
4551 
4553 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361

References Assert, JB_ROOT_IS_SCALAR, jbvNull, JsonbIteratorInit(), JsonbIteratorNext(), JsonbValueToJsonb(), PG_GETARG_JSONB_P, PG_RETURN_POINTER, pushJsonbValue(), res, 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 3957 of file jsonfuncs.c.

3958 {
3959  return populate_recordset_worker(fcinfo, "jsonb_to_recordset",
3960  false, false);
3961 }

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 }
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59

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

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

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, SOFT_ERROR_OCCURRED, 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 537 of file jsonfuncs.c.

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

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

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

◆ okeys_array_start()

static JsonParseErrorType okeys_array_start ( void *  state)
static

Definition at line 806 of file jsonfuncs.c.

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

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

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

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

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

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

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

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

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

◆ pg_parse_json_or_errsave()

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

Definition at line 516 of file jsonfuncs.c.

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

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

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

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, makeMdArrayResult(), PopulateArrayContext::mcxt, PopulateArrayContext::ndims, palloc(), pfree(), populate_array_dim_jsonb(), populate_array_json(), PopulateArrayContext::sizes, and JsValue::val.

Referenced by populate_record_field().

◆ populate_array_array_end()

static JsonParseErrorType populate_array_array_end ( void *  _state)
static

Definition at line 2664 of file jsonfuncs.c.

2665 {
2667  PopulateArrayContext *ctx = state->ctx;
2668  int ndim = state->lex->lex_level;
2669 
2670  if (ctx->ndims <= 0)
2671  {
2672  if (!populate_array_assign_ndims(ctx, ndim + 1))
2673  return JSON_SEM_ACTION_FAILED;
2674  }
2675 
2676  if (ndim < ctx->ndims)
2677  {
2678  /* Report if an error occurred. */
2679  if (!populate_array_check_dimension(ctx, ndim))
2680  return JSON_SEM_ACTION_FAILED;
2681  }
2682 
2683  return JSON_SUCCESS;
2684 }
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:276

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

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

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

◆ 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  /* Nothing to do on an error. */
2627  if (SOFT_ERROR_OCCURRED(ctx->escontext))
2628  return false;
2629 
2630  accumArrayResult(ctx->astate, element, element_isnull,
2631  ctx->aio->element_type, ctx->acxt);
2632 
2633  Assert(ndim > 0);
2634  ctx->sizes[ndim - 1]++; /* increment current dimension counter */
2635 
2636  return true;
2637 }
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5331
int32 element_typmod
Definition: jsonfuncs.c:169
ColumnIOData * element_info
Definition: jsonfuncs.c:167

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

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

References Assert, JsValue::is_json, JsValue::json, JSON_SEM_ACTION_FAILED, JSON_SUCCESS, JSON_TOKEN_NULL, PopulateArrayContext::ndims, populate_array_element(), 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 2688 of file jsonfuncs.c.

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

References JSON_SUCCESS.

Referenced by populate_array_json().

◆ populate_array_json()

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

Definition at line 2785 of file jsonfuncs.c.

2786 {
2789 
2790  state.lex = makeJsonLexContextCstringLen(NULL, json, len,
2791  GetDatabaseEncoding(), true);
2792  state.ctx = ctx;
2793 
2794  memset(&sem, 0, sizeof(sem));
2795  sem.semstate = (void *) &state;
2801 
2802  if (pg_parse_json_or_errsave(state.lex, &sem, ctx->escontext))
2803  {
2804  /* number of dimensions should be already known */
2805  Assert(ctx->ndims > 0 && ctx->dims);
2806  }
2807 
2809 
2810  return !SOFT_ERROR_OCCURRED(ctx->escontext);
2811 }
static JsonParseErrorType populate_array_scalar(void *_state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:2749
static JsonParseErrorType populate_array_object_start(void *_state)
Definition: jsonfuncs.c:2641
static JsonParseErrorType populate_array_element_end(void *_state, bool isnull)
Definition: jsonfuncs.c:2706
static JsonParseErrorType populate_array_element_start(void *_state, bool isnull)
Definition: jsonfuncs.c:2688
static JsonParseErrorType populate_array_array_end(void *_state)
Definition: jsonfuncs.c:2664

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

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

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

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

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

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

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

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

Definition at line 3208 of file jsonfuncs.c.

3215 {
3216  Datum res;
3217 
3218  if (*isnull)
3219  res = (Datum) 0;
3220  else
3221  {
3223  io->base_typid, io->base_typmod,
3224  colname, mcxt, PointerGetDatum(NULL),
3225  jsv, isnull, escontext);
3226  Assert(!*isnull || SOFT_ERROR_OCCURRED(escontext));
3227  }
3228 
3229  if (!domain_check_safe(res, *isnull, typid, &io->domain_info, mcxt,
3230  escontext))
3231  {
3232  *isnull = true;
3233  return (Datum) 0;
3234  }
3235 
3236  return res;
3237 }
void * domain_info
Definition: jsonfuncs.c:194
int32 base_typmod
Definition: jsonfuncs.c:193
Oid base_typid
Definition: jsonfuncs.c:192
ColumnIOData * base_io
Definition: jsonfuncs.c:191

References Assert, DomainIOData::base_io, DomainIOData::base_typid, DomainIOData::base_typmod, domain_check_safe(), DomainIOData::domain_info, PointerGetDatum(), populate_record_field(), res, 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 3497 of file jsonfuncs.c.

3503 {
3504  RecordIOData *record = *record_p;
3505  Datum *values;
3506  bool *nulls;
3507  HeapTuple res;
3508  int ncolumns = tupdesc->natts;
3509  int i;
3510 
3511  /*
3512  * if the input json is empty, we can only skip the rest if we were passed
3513  * in a non-null record, since otherwise there may be issues with domain
3514  * nulls.
3515  */
3516  if (defaultval && JsObjectIsEmpty(obj))
3517  return defaultval;
3518 
3519  /* (re)allocate metadata cache */
3520  if (record == NULL ||
3521  record->ncolumns != ncolumns)
3522  *record_p = record = allocate_record_info(mcxt, ncolumns);
3523 
3524  /* invalidate metadata cache if the record type has changed */
3525  if (record->record_type != tupdesc->tdtypeid ||
3526  record->record_typmod != tupdesc->tdtypmod)
3527  {
3528  MemSet(record, 0, offsetof(RecordIOData, columns) +
3529  ncolumns * sizeof(ColumnIOData));
3530  record->record_type = tupdesc->tdtypeid;
3531  record->record_typmod = tupdesc->tdtypmod;
3532  record->ncolumns = ncolumns;
3533  }
3534 
3535  values = (Datum *) palloc(ncolumns * sizeof(Datum));
3536  nulls = (bool *) palloc(ncolumns * sizeof(bool));
3537 
3538  if (defaultval)
3539  {
3540  HeapTupleData tuple;
3541 
3542  /* Build a temporary HeapTuple control structure */
3543  tuple.t_len = HeapTupleHeaderGetDatumLength(defaultval);
3544  ItemPointerSetInvalid(&(tuple.t_self));
3545  tuple.t_tableOid = InvalidOid;
3546  tuple.t_data = defaultval;
3547 
3548  /* Break down the tuple into fields */
3549  heap_deform_tuple(&tuple, tupdesc, values, nulls);
3550  }
3551  else
3552  {
3553  for (i = 0; i < ncolumns; ++i)
3554  {
3555  values[i] = (Datum) 0;
3556  nulls[i] = true;
3557  }
3558  }
3559 
3560  for (i = 0; i < ncolumns; ++i)
3561  {
3562  Form_pg_attribute att = TupleDescAttr(tupdesc, i);
3563  char *colname = NameStr(att->attname);
3564  JsValue field = {0};
3565  bool found;
3566 
3567  /* Ignore dropped columns in datatype */
3568  if (att->attisdropped)
3569  {
3570  nulls[i] = true;
3571  continue;
3572  }
3573 
3574  found = JsObjectGetField(obj, colname, &field);
3575 
3576  /*
3577  * we can't just skip here if the key wasn't found since we might have
3578  * a domain to deal with. If we were passed in a non-null record
3579  * datum, we assume that the existing values are valid (if they're
3580  * not, then it's not our fault), but if we were passed in a null,
3581  * then every field which we don't populate needs to be run through
3582  * the input function just in case it's a domain type.
3583  */
3584  if (defaultval && !found)
3585  continue;
3586 
3587  values[i] = populate_record_field(&record->columns[i],
3588  att->atttypid,
3589  att->atttypmod,
3590  colname,
3591  mcxt,
3592  nulls[i] ? (Datum) 0 : values[i],
3593  &field,
3594  &nulls[i],
3595  escontext);
3596  }
3597 
3598  res = heap_form_tuple(tupdesc, values, nulls);
3599 
3600  pfree(values);
3601  pfree(nulls);
3602 
3603  return res->t_data;
3604 }
#define NameStr(name)
Definition: c.h:746
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1345
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:450
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition: itemptr.h:184
static RecordIOData * allocate_record_info(MemoryContext mcxt, int ncolumns)
Definition: jsonfuncs.c:3453
#define JsObjectIsEmpty(jso)
Definition: jsonfuncs.c:327
static bool JsObjectGetField(JsObject *obj, char *field, JsValue *jsv)
Definition: jsonfuncs.c:3469
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
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:826
Oid record_type
Definition: hstore_io.c:821
int32 record_typmod
Definition: hstore_io.c:822
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

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, res, 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 
)
static

Definition at line 3384 of file jsonfuncs.c.

3393 {
3394  TypeCat typcat;
3395 
3397 
3398  /*
3399  * Prepare column metadata cache for the given type. Force lookup of the
3400  * scalar_io data so that the json string hack below will work.
3401  */
3402  if (col->typid != typid || col->typmod != typmod)
3403  prepare_column_cache(col, typid, typmod, mcxt, true);
3404 
3405  *isnull = JsValueIsNull(jsv);
3406 
3407  typcat = col->typcat;
3408 
3409  /* try to convert json string to a non-scalar type through input function */
3410  if (JsValueIsString(jsv) &&
3411  (typcat == TYPECAT_ARRAY ||
3412  typcat == TYPECAT_COMPOSITE ||
3413  typcat == TYPECAT_COMPOSITE_DOMAIN))
3414  typcat = TYPECAT_SCALAR;
3415 
3416  /* we must perform domain checks for NULLs, otherwise exit immediately */
3417  if (*isnull &&
3418  typcat != TYPECAT_DOMAIN &&
3419  typcat != TYPECAT_COMPOSITE_DOMAIN)
3420  return (Datum) 0;
3421 
3422  switch (typcat)
3423  {
3424  case TYPECAT_SCALAR:
3425  return populate_scalar(&col->scalar_io, typid, typmod, jsv,
3426  isnull, escontext);
3427 
3428  case TYPECAT_ARRAY:
3429  return populate_array(&col->io.array, colname, mcxt, jsv,
3430  isnull, escontext);
3431 
3432  case TYPECAT_COMPOSITE:
3434  return populate_composite(&col->io.composite, typid,
3435  colname, mcxt,
3436  DatumGetPointer(defaultval)
3437  ? DatumGetHeapTupleHeader(defaultval)
3438  : NULL,
3439  jsv, isnull,
3440  escontext);
3441 
3442  case TYPECAT_DOMAIN:
3443  return populate_domain(&col->io.domain, typid, colname, mcxt,
3444  jsv, isnull, escontext);
3445 
3446  default:
3447  elog(ERROR, "unrecognized type category '%c'", typcat);
3448  return (Datum) 0;
3449  }
3450 }
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:295
#define JsValueIsString(jsv)
Definition: jsonfuncs.c:323
static Datum populate_scalar(ScalarIOData *io, Oid typid, int32 typmod, JsValue *jsv, bool *isnull, Node *escontext)
Definition: jsonfuncs.c:3121
#define JsValueIsNull(jsv)
Definition: jsonfuncs.c:318
static Datum populate_array(ArrayIOData *aio, const char *colname, MemoryContext mcxt, JsValue *jsv, bool *isnull, Node *escontext)
Definition: jsonfuncs.c:2911
static Datum populate_domain(DomainIOData *io, Oid typid, const char *colname, MemoryContext mcxt, JsValue *jsv, bool *isnull, Node *escontext)
Definition: jsonfuncs.c:3208
static Datum populate_composite(CompositeIOData *io, Oid typid, const char *colname, MemoryContext mcxt, HeapTupleHeader defaultval, JsValue *jsv, bool *isnull, Node *escontext)
Definition: jsonfuncs.c:3054
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
int32 typmod
Definition: jsonfuncs.c:213
ScalarIOData scalar_io
Definition: jsonfuncs.c:215
ArrayIOData array
Definition: jsonfuncs.c:219
DomainIOData domain
Definition: jsonfuncs.c:221

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

3678 {
3679  int json_arg_num = have_record_arg ? 1 : 0;
3680  JsValue jsv = {0};
3681  HeapTupleHeader rec;
3682  Datum rettuple;
3683  bool isnull;
3684  JsonbValue jbv;
3685  MemoryContext fnmcxt = fcinfo->flinfo->fn_mcxt;
3686  PopulateRecordCache *cache = fcinfo->flinfo->fn_extra;
3687 
3688  /*
3689  * If first time through, identify input/result record type. Note that
3690  * this stanza looks only at fcinfo context, which can't change during the
3691  * query; so we may not be able to fully resolve a RECORD input type yet.
3692  */
3693  if (!cache)
3694  {
3695  fcinfo->flinfo->fn_extra = cache =
3696  MemoryContextAllocZero(fnmcxt, sizeof(*cache));
3697  cache->fn_mcxt = fnmcxt;
3698 
3699  if (have_record_arg)
3700  get_record_type_from_argument(fcinfo, funcname, cache);
3701  else
3702  get_record_type_from_query(fcinfo, funcname, cache);
3703  }
3704 
3705  /* Collect record arg if we have one */
3706  if (!have_record_arg)
3707  rec = NULL; /* it's json{b}_to_record() */
3708  else if (!PG_ARGISNULL(0))
3709  {
3710  rec = PG_GETARG_HEAPTUPLEHEADER(0);
3711 
3712  /*
3713  * When declared arg type is RECORD, identify actual record type from
3714  * the tuple itself.
3715  */
3716  if (cache->argtype == RECORDOID)
3717  {
3720  }
3721  }
3722  else
3723  {
3724  rec = NULL;
3725 
3726  /*
3727  * When declared arg type is RECORD, identify actual record type from
3728  * calling query, or fail if we can't.
3729  */
3730  if (cache->argtype == RECORDOID)
3731  {
3732  get_record_type_from_query(fcinfo, funcname, cache);
3733  /* This can't change argtype, which is important for next time */
3734  Assert(cache->argtype == RECORDOID);
3735  }
3736  }
3737 
3738  /* If no JSON argument, just return the record (if any) unchanged */
3739  if (PG_ARGISNULL(json_arg_num))
3740  {
3741  if (rec)
3742  PG_RETURN_POINTER(rec);
3743  else
3744  PG_RETURN_NULL();
3745  }
3746 
3747  jsv.is_json = is_json;
3748 
3749  if (is_json)
3750  {
3751  text *json = PG_GETARG_TEXT_PP(json_arg_num);
3752 
3753  jsv.val.json.str = VARDATA_ANY(json);
3754  jsv.val.json.len = VARSIZE_ANY_EXHDR(json);
3755  jsv.val.json.type = JSON_TOKEN_INVALID; /* not used in
3756  * populate_composite() */
3757  }
3758  else
3759  {
3760  Jsonb *jb = PG_GETARG_JSONB_P(json_arg_num);
3761 
3762  jsv.val.jsonb = &jbv;
3763 
3764  /* fill binary jsonb value pointing to jb */
3765  jbv.type = jbvBinary;
3766  jbv.val.binary.data = &jb->root;
3767  jbv.val.binary.len = VARSIZE(jb) - VARHDRSZ;
3768  }
3769 
3770  isnull = false;
3771  rettuple = populate_composite(&cache->c.io.composite, cache->argtype,
3772  NULL, fnmcxt, rec, &jsv, &isnull,
3773  escontext);
3774  Assert(!isnull || SOFT_ERROR_OCCURRED(escontext));
3775 
3776  PG_RETURN_DATUM(rettuple);
3777 }
#define PG_GETARG_HEAPTUPLEHEADER(n)
Definition: fmgr.h:312
#define HeapTupleHeaderGetTypMod(tup)
Definition: htup_details.h:466
#define HeapTupleHeaderGetTypeId(tup)
Definition: htup_details.h:456
static void get_record_type_from_argument(FunctionCallInfo fcinfo, const char *funcname, PopulateRecordCache *cache)
Definition: jsonfuncs.c:3612
static void get_record_type_from_query(FunctionCallInfo fcinfo, const char *funcname, PopulateRecordCache *cache)
Definition: jsonfuncs.c:3638
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, 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, 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 4244 of file jsonfuncs.c.

4245 {
4247 
4248  if (_state->lex->lex_level == 1 &&
4250  ereport(ERROR,
4251  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4252  errmsg("argument of %s must be an array of objects",
4253  _state->function_name)));
4254 
4255  return JSON_SUCCESS;
4256 }
JsonLexContext * lex
Definition: jsonfuncs.c:246
const char * function_name
Definition: jsonfuncs.c:247

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

4260 {
4261  /* nothing to do */
4262  return JSON_SUCCESS;
4263 }

References JSON_SUCCESS.

Referenced by populate_recordset_worker().

◆ populate_recordset_object_end()

static JsonParseErrorType populate_recordset_object_end ( void *  state)
static

Definition at line 4221 of file jsonfuncs.c.

4222 {
4224  JsObject obj;
4225 
4226  /* Nested objects require no special processing */
4227  if (_state->lex->lex_level > 1)
4228  return JSON_SUCCESS;
4229 
4230  obj.is_json = true;
4231  obj.val.json_hash = _state->json_hash;
4232 
4233  /* Otherwise, construct and return a tuple based on this level-1 object */
4234  populate_recordset_record(_state, &obj);
4235 
4236  /* Done with hash for this object */
4237  hash_destroy(_state->json_hash);
4238  _state->json_hash = NULL;
4239 
4240  return JSON_SUCCESS;
4241 }
static void populate_recordset_record(PopulateRecordsetState *state, JsObject *obj)
Definition: jsonfuncs.c:3978

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

4307 {
4309  JsonHashEntry *hashentry;
4310  bool found;
4311 
4312  /*
4313  * Ignore nested fields.
4314  */
4315  if (_state->lex->lex_level > 2)
4316  return JSON_SUCCESS;
4317 
4318  /*
4319  * Ignore field names >= NAMEDATALEN - they can't match a record field.
4320  * (Note: without this test, the hash code would truncate the string at
4321  * NAMEDATALEN-1, and could then match against a similarly-truncated
4322  * record field name. That would be a reasonable behavior, but this code
4323  * has previously insisted on exact equality, so we keep this behavior.)
4324  */
4325  if (strlen(fname) >= NAMEDATALEN)
4326  return JSON_SUCCESS;
4327 
4328  hashentry = hash_search(_state->json_hash, fname, HASH_ENTER, &found);
4329 
4330  /*
4331  * found being true indicates a duplicate. We don't do anything about
4332  * that, a later field with the same name overrides the earlier field.
4333  */
4334 
4335  hashentry->type = _state->saved_token_type;
4336  Assert(isnull == (hashentry->type == JSON_TOKEN_NULL));
4337 
4338  if (_state->save_json_start != NULL)
4339  {
4340  int len = _state->lex->prev_token_terminator - _state->save_json_start;
4341  char *val = palloc((len + 1) * sizeof(char));
4342 
4343  memcpy(val, _state->save_json_start, len);
4344  val[len] = '\0';
4345  hashentry->val = val;
4346  }
4347  else
4348  {
4349  /* must have had a scalar instead */
4350  hashentry->val = _state->saved_scalar;
4351  }
4352 
4353  return JSON_SUCCESS;
4354 }
JsonTokenType saved_token_type
Definition: jsonfuncs.c:251

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

4284 {
4286 
4287  if (_state->lex->lex_level > 2)
4288  return JSON_SUCCESS;
4289 
4290  _state->saved_token_type = _state->lex->token_type;
4291 
4292  if (_state->lex->token_type == JSON_TOKEN_ARRAY_START ||
4294  {
4295  _state->save_json_start = _state->lex->token_start;
4296  }
4297  else
4298  {
4299  _state->save_json_start = NULL;
4300  }
4301 
4302  return JSON_SUCCESS;
4303 }

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

4192 {
4194  int lex_level = _state->lex->lex_level;
4195  HASHCTL ctl;
4196 
4197  /* Reject object at top level: we must have an array at level 0 */
4198  if (lex_level == 0)
4199  ereport(ERROR,
4200  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4201  errmsg("cannot call %s on an object",
4202  _state->function_name)));
4203 
4204  /* Nested objects require no special processing */
4205  if (lex_level > 1)
4206  return JSON_SUCCESS;
4207 
4208  /* Object at level 1: set up a new hash table for this object */
4209  ctl.keysize = NAMEDATALEN;
4210  ctl.entrysize = sizeof(JsonHashEntry);
4211  ctl.hcxt = CurrentMemoryContext;
4212  _state->json_hash = hash_create("json object hashtable",
4213  100,
4214  &ctl,
4216 
4217  return JSON_SUCCESS;
4218 }

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

3979 {
3980  PopulateRecordCache *cache = state->cache;
3981  HeapTupleHeader tuphead;
3982  HeapTupleData tuple;
3983 
3984  /* acquire/update cached tuple descriptor */
3985  update_cached_tupdesc(&cache->c.io.composite, cache->fn_mcxt);
3986 
3987  /* replace record fields from json */
3988  tuphead = populate_record(cache->c.io.composite.tupdesc,
3989  &cache->c.io.composite.record_io,
3990  state->rec,
3991  cache->fn_mcxt,
3992  obj,
3993  NULL);
3994 
3995  /* if it's domain over composite, check domain constraints */
3996  if (cache->c.typcat == TYPECAT_COMPOSITE_DOMAIN)
3997  (void) domain_check_safe(HeapTupleHeaderGetDatum(tuphead), false,
3998  cache->argtype,
3999  &cache->c.io.composite.domain_info,
4000  cache->fn_mcxt,
4001  NULL);
4002 
4003  /* ok, save into tuplestore */
4004  tuple.t_len = HeapTupleHeaderGetDatumLength(tuphead);
4005  ItemPointerSetInvalid(&(tuple.t_self));
4006  tuple.t_tableOid = InvalidOid;
4007  tuple.t_data = tuphead;
4008 
4009  tuplestore_puttuple(state->tuple_store, &tuple);
4010 }

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

4267 {
4269 
4270  if (_state->lex->lex_level == 0)
4271  ereport(ERROR,
4272  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4273  errmsg("cannot call %s on a scalar",
4274  _state->function_name)));
4275 
4276  if (_state->lex->lex_level == 2)
4277  _state->saved_scalar = token;
4278 
4279  return JSON_SUCCESS;
4280 }

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

4019 {
4020  int json_arg_num = have_record_arg ? 1 : 0;
4021  ReturnSetInfo *rsi;
4022  MemoryContext old_cxt;
4023  HeapTupleHeader rec;
4024  PopulateRecordCache *cache = fcinfo->flinfo->fn_extra;
4026 
4027  rsi = (ReturnSetInfo *) fcinfo->resultinfo;
4028 
4029  if (!rsi || !IsA(rsi, ReturnSetInfo))
4030  ereport(ERROR,
4031  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4032  errmsg("set-valued function called in context that cannot accept a set")));
4033 
4034  if (!(rsi->allowedModes & SFRM_Materialize))
4035  ereport(ERROR,
4036  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4037  errmsg("materialize mode required, but it is not allowed in this context")));
4038 
4040 
4041  /*
4042  * If first time through, identify input/result record type. Note that
4043  * this stanza looks only at fcinfo context, which can't change during the
4044  * query; so we may not be able to fully resolve a RECORD input type yet.
4045  */
4046  if (!cache)
4047  {
4048  fcinfo->flinfo->fn_extra = cache =
4049  MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt, sizeof(*cache));
4050  cache->fn_mcxt = fcinfo->flinfo->fn_mcxt;
4051 
4052  if (have_record_arg)
4053  get_record_type_from_argument(fcinfo, funcname, cache);
4054  else
4055  get_record_type_from_query(fcinfo, funcname, cache);
4056  }
4057 
4058  /* Collect record arg if we have one */
4059  if (!have_record_arg)
4060  rec = NULL; /* it's json{b}_to_recordset() */
4061  else if (!PG_ARGISNULL(0))
4062  {
4063  rec = PG_GETARG_HEAPTUPLEHEADER(0);
4064 
4065  /*
4066  * When declared arg type is RECORD, identify actual record type from
4067  * the tuple itself.
4068  */
4069  if (cache->argtype == RECORDOID)
4070  {
4073  }
4074  }
4075  else
4076  {
4077  rec = NULL;
4078 
4079  /*
4080  * When declared arg type is RECORD, identify actual record type from
4081  * calling query, or fail if we can't.
4082  */
4083  if (cache->argtype == RECORDOID)
4084  {
4085  get_record_type_from_query(fcinfo, funcname, cache);
4086  /* This can't change argtype, which is important for next time */
4087  Assert(cache->argtype == RECORDOID);
4088  }
4089  }
4090 
4091  /* if the json is null send back an empty set */
4092  if (PG_ARGISNULL(json_arg_num))
4093  PG_RETURN_NULL();
4094 
4095  /*
4096  * Forcibly update the cached tupdesc, to ensure we have the right tupdesc
4097  * to return even if the JSON contains no rows.
4098  */
4099  update_cached_tupdesc(&cache->c.io.composite, cache->fn_mcxt);
4100 
4102 
4103  /* make tuplestore in a sufficiently long-lived memory context */
4105  state->tuple_store = tuplestore_begin_heap(rsi->allowedModes &
4107  false, work_mem);
4108  MemoryContextSwitchTo(old_cxt);
4109 
4110  state->function_name = funcname;
4111  state->cache = cache;
4112  state->rec = rec;
4113 
4114  if (is_json)
4115  {
4116  text *json = PG_GETARG_TEXT_PP(json_arg_num);
4117  JsonLexContext lex;
4118  JsonSemAction *sem;
4119 
4120  sem = palloc0(sizeof(JsonSemAction));
4121 
4122  makeJsonLexContext(&lex, json, true);
4123 
4124  sem->semstate = (void *) state;
4132 
4133  state->lex = &lex;
4134 
4136 
4137  freeJsonLexContext(&lex);
4138  state->lex = NULL;
4139  }
4140  else
4141  {
4142  Jsonb *jb = PG_GETARG_JSONB_P(json_arg_num);
4143  JsonbIterator *it;
4144  JsonbValue v;
4145  bool skipNested = false;
4147 
4148  if (JB_ROOT_IS_SCALAR(jb) || !JB_ROOT_IS_ARRAY(jb))
4149  ereport(ERROR,
4150  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4151  errmsg("cannot call %s on a non-array",
4152  funcname)));
4153 
4154  it = JsonbIteratorInit(&jb->root);
4155 
4156  while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4157  {
4158  skipNested = true;
4159 
4160  if (r == WJB_ELEM)
4161  {
4162  JsObject obj;
4163 
4164  if (v.type != jbvBinary ||
4165  !JsonContainerIsObject(v.val.binary.data))
4166  ereport(ERROR,
4167  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4168  errmsg("argument of %s must be an array of objects",
4169  funcname)));
4170 
4171  obj.is_json = false;
4172  obj.val.jsonb_cont = v.val.binary.data;
4173 
4175  }
4176  }
4177  }
4178 
4179  /*
4180  * Note: we must copy the cached tupdesc because the executor will free
4181  * the passed-back setDesc, but we want to hang onto the cache in case
4182  * we're called again in the same query.
4183  */
4184  rsi->setResult = state->tuple_store;
4186 
4187  PG_RETURN_NULL();
4188 }
@ SFRM_Materialize_Random
Definition: execnodes.h:318
@ SFRM_Materialize
Definition: execnodes.h:317
int work_mem
Definition: globals.c:128
static JsonParseErrorType populate_recordset_array_start(void *state)
Definition: jsonfuncs.c:4259
static JsonParseErrorType populate_recordset_object_start(void *state)
Definition: jsonfuncs.c:4191
static JsonParseErrorType populate_recordset_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:4283
static JsonParseErrorType populate_recordset_object_field_end(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:4306
static JsonParseErrorType populate_recordset_object_end(void *state)
Definition: jsonfuncs.c:4221
static JsonParseErrorType populate_recordset_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:4244
static JsonParseErrorType populate_recordset_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:4266
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:262
SetFunctionReturnMode returnMode
Definition: execnodes.h:336
ExprContext * econtext
Definition: execnodes.h:332
int allowedModes
Definition: execnodes.h:334
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318

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

Definition at line 3121 of file jsonfuncs.c.

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

References Assert, buf, DatumGetCString(), DirectFunctionCall1, elog, ERROR, escape_json(), initStringInfo(), InputFunctionCallSafe(), JsValue::is_json, jbvBinary, jbvBool, jbvNumeric, jbvString, JsValue::json, JSON_TOKEN_STRING, JsValue::jsonb, JsonbPGetDatum(), JsonbToCString(), JsonbValueToJsonb(), len, numeric_out(), palloc(), pfree(), pnstrdup(), PointerGetDatum(), pstrdup(), res, Jsonb::root, str, JsonbValue::type, ScalarIOData::typiofunc, ScalarIOData::typioparam, 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 3241 of file jsonfuncs.c.

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

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

Referenced by get_record_type_from_argument(), and populate_record_field().

◆ push_null_elements()

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

Definition at line 1699 of file jsonfuncs.c.

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

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

Referenced by push_path(), and setPathArray().

◆ push_path()

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

Definition at line 1718 of file jsonfuncs.c.

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

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

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

Referenced by json_errsave_error().

◆ setPath()

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

Definition at line 5158 of file jsonfuncs.c.

5161 {
5162  JsonbValue v;
5164  JsonbValue *res;
5165 
5167 
5168  if (path_nulls[level])
5169  ereport(ERROR,
5170  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5171  errmsg("path element at position %d is null",
5172  level + 1)));
5173 
5174  r = JsonbIteratorNext(it, &v, false);
5175 
5176  switch (r)
5177  {
5178  case WJB_BEGIN_ARRAY:
5179 
5180  /*
5181  * If instructed complain about attempts to replace within a raw
5182  * scalar value. This happens even when current level is equal to
5183  * path_len, because the last path key should also correspond to
5184  * an object or an array, not raw scalar.
5185  */
5186  if ((op_type & JB_PATH_FILL_GAPS) && (level <= path_len - 1) &&
5187  v.val.array.rawScalar)
5188  ereport(ERROR,
5189  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5190  errmsg("cannot replace existing key"),
5191  errdetail("The path assumes key is a composite object, "
5192  "but it is a scalar value.")));
5193 
5194  (void) pushJsonbValue(st, r, NULL);
5195  setPathArray(it, path_elems, path_nulls, path_len, st, level,
5196  newval, v.val.array.nElems, op_type);
5197  r = JsonbIteratorNext(it, &v, false);
5198  Assert(r == WJB_END_ARRAY);
5199  res = pushJsonbValue(st, r, NULL);
5200  break;
5201  case WJB_BEGIN_OBJECT:
5202  (void) pushJsonbValue(st, r, NULL);
5203  setPathObject(it, path_elems, path_nulls, path_len, st, level,
5204  newval, v.val.object.nPairs, op_type);
5205  r = JsonbIteratorNext(it, &v, true);
5206  Assert(r == WJB_END_OBJECT);
5207  res = pushJsonbValue(st, r, NULL);
5208  break;
5209  case WJB_ELEM:
5210  case WJB_VALUE:
5211 
5212  /*
5213  * If instructed complain about attempts to replace within a
5214  * scalar value. This happens even when current level is equal to
5215  * path_len, because the last path key should also correspond to
5216  * an object or an array, not an element or value.
5217  */
5218  if ((op_type & JB_PATH_FILL_GAPS) && (level <= path_len - 1))
5219  ereport(ERROR,
5220  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5221  errmsg("cannot replace existing key"),
5222  errdetail("The path assumes key is a composite object, "
5223  "but it is a scalar value.")));
5224 
5225  res = pushJsonbValue(st, r, &v);
5226  break;
5227  default:
5228  elog(ERROR, "unrecognized iterator result: %d", (int) r);
5229  res = NULL; /* keep compiler quiet */
5230  break;
5231  }
5232 
5233  return res;
5234 }
static void setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, JsonbParseState **st, int level, JsonbValue *newval, uint32 nelems, int op_type)
Definition: jsonfuncs.c:5379
static void setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, JsonbParseState **st, int level, JsonbValue *newval, uint32 npairs, int op_type)
Definition: jsonfuncs.c:5240

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

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

◆ setPathArray()

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

Definition at line 5379 of file jsonfuncs.c.

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

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, push_null_elements(), push_path(), pushJsonbValue(), setPath(), strtoint(), TextDatumGetCString, WJB_BEGIN_ARRAY, WJB_BEGIN_OBJECT, WJB_ELEM, WJB_END_ARRAY, and WJB_END_OBJECT.

Referenced by setPath().

◆ setPathObject()

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

Definition at line 5240 of file jsonfuncs.c.

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

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

4437 {
4438  StripnullState *_state = (StripnullState *) state;
4439 
4440  if (_state->strval->data[_state->strval->len - 1] != '[')
4441  appendStringInfoCharMacro(_state->strval, ',');
4442 
4443  return JSON_SUCCESS;
4444 }
#define appendStringInfoCharMacro(str, ch)
Definition: stringinfo.h:204
StringInfo strval
Definition: jsonfuncs.c:286

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

Referenced by json_strip_nulls().

◆ sn_array_end()

static JsonParseErrorType sn_array_end ( void *  state)
static

Definition at line 4396 of file jsonfuncs.c.

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

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

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

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

4377 {
4378  StripnullState *_state = (StripnullState *) state;
4379 
4380  appendStringInfoCharMacro(_state->strval, '}');
4381 
4382  return JSON_SUCCESS;
4383 }

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

4407 {
4408  StripnullState *_state = (StripnullState *) state;
4409 
4410  if (isnull)
4411  {
4412  /*
4413  * The next thing must be a scalar or isnull couldn't be true, so
4414  * there is no danger of this state being carried down into a nested
4415  * object or array. The flag will be reset in the scalar action.
4416  */
4417  _state->skip_next_null = true;
4418  return JSON_SUCCESS;
4419  }
4420 
4421  if (_state->strval->data[_state->strval->len - 1] != '{')
4422  appendStringInfoCharMacro(_state->strval, ',');
4423 
4424  /*
4425  * Unfortunately we don't have the quoted and escaped string any more, so
4426  * we have to re-escape it.
4427  */
4428  escape_json(_state->strval, fname);
4429 
4430  appendStringInfoCharMacro(_state->strval, ':');
4431 
4432  return JSON_SUCCESS;
4433 }
bool skip_next_null
Definition: jsonfuncs.c:287

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

4367 {
4368  StripnullState *_state = (StripnullState *) state;
4369 
4370  appendStringInfoCharMacro(_state->strval, '{');
4371 
4372  return JSON_SUCCESS;
4373 }

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

4448 {
4449  StripnullState *_state = (StripnullState *) state;
4450 
4451  if (_state->skip_next_null)
4452  {
4453  Assert(tokentype == JSON_TOKEN_NULL);
4454  _state->skip_next_null = false;
4455  return JSON_SUCCESS;
4456  }
4457 
4458  if (tokentype == JSON_TOKEN_STRING)
4459  escape_json(_state->strval, token);
4460  else
4462 
4463  return JSON_SUCCESS;
4464 }
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:182

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

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

5809 {
5810  JsonLexContext lex;
5811  JsonSemAction *sem = palloc0(sizeof(JsonSemAction));
5813 
5814  state->lex = makeJsonLexContext(&lex, json, true);
5815  state->strval = makeStringInfo();
5816  state->action = transform_action;
5817  state->action_state = action_state;
5818 
5819  sem->semstate = (void *) state;
5827 
5829  freeJsonLexContext(&lex);
5830 
5831  return cstring_to_text_with_len(state->strval->data, state->strval->len);
5832 }
static JsonParseErrorType transform_string_values_array_start(void *state)
Definition: jsonfuncs.c:5860
static JsonParseErrorType transform_string_values_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:5880
static JsonParseErrorType transform_string_values_array_end(void *state)
Definition: jsonfuncs.c:5870
static JsonParseErrorType transform_string_values_object_end(void *state)
Definition: jsonfuncs.c:5850
static JsonParseErrorType transform_string_values_object_start(void *state)
Definition: jsonfuncs.c:5840
static JsonParseErrorType transform_string_values_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:5898
static JsonParseErrorType transform_string_values_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:5909

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

Referenced by ts_headline_json_byid_opt().

◆ transform_jsonb_string_values()

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

Definition at line 5760 of file jsonfuncs.c.

5762 {
5763  JsonbIterator *it;
5764  JsonbValue v,
5765  *res = NULL;
5767  JsonbParseState *st = NULL;
5768  text *out;
5769  bool is_scalar = false;
5770 
5771  it = JsonbIteratorInit(&jsonb->root);
5772  is_scalar = it->isScalar;
5773 
5774  while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
5775  {
5776  if ((type == WJB_VALUE || type == WJB_ELEM) && v.type == jbvString)
5777  {
5778  out = transform_action(action_state, v.val.string.val, v.val.string.len);
5779  /* out is probably not toasted, but let's be sure */
5780  out = pg_detoast_datum_packed(out);
5781  v.val.string.val = VARDATA_ANY(out);
5782  v.val.string.len = VARSIZE_ANY_EXHDR(out);
5783  res = pushJsonbValue(&st, type, type < WJB_BEGIN_ARRAY ? &v : NULL);
5784  }
5785  else
5786  {
5787  res = pushJsonbValue(&st, type, (type == WJB_KEY ||
5788  type == WJB_VALUE ||
5789  type == WJB_ELEM) ? &v : NULL);
5790  }
5791  }
5792 
5793  if (res->type == jbvArray)
5794  res->val.array.rawScalar = is_scalar;
5795 
5796  return JsonbValueToJsonb(res);
5797 }
bool isScalar
Definition: jsonb.h:347

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

5899 {
5901 
5902  if (_state->strval->data[_state->strval->len - 1] != '[')
5903  appendStringInfoCharMacro(_state->strval, ',');
5904 
5905  return JSON_SUCCESS;
5906 }

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

Definition at line 5870 of file jsonfuncs.c.

5871 {
5873 
5874  appendStringInfoCharMacro(_state->strval, ']');
5875 
5876  return JSON_SUCCESS;
5877 }

References appendStringInfoCharMacro, JSON_SUCCESS, and TransformJsonStringValuesState::strval.

Referenced by transform_json_string_values().

◆ transform_string_values_array_start()

static JsonParseErrorType transform_string_values_array_start ( void *  state)
static

Definition at line 5860 of file jsonfuncs.c.

5861 {
5863 
5864  appendStringInfoCharMacro(_state->strval, '[');
5865 
5866  return JSON_SUCCESS;
5867 }

References appendStringInfoCharMacro, JSON_SUCCESS, and TransformJsonStringValuesState::strval.

Referenced by transform_json_string_values().

◆ transform_string_values_object_end()

static JsonParseErrorType transform_string_values_object_end ( void *  state)
static

Definition at line 5850 of file jsonfuncs.c.

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

References appendStringInfoCharMacro, JSON_SUCCESS, and TransformJsonStringValuesState::strval.

Referenced by transform_json_string_values().

◆ transform_string_values_object_field_start()

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

Definition at line 5880 of file jsonfuncs.c.

5881 {
5883 
5884  if (_state->strval->data[_state->strval->len - 1] != '{')
5885  appendStringInfoCharMacro(_state->strval, ',');
5886 
5887  /*
5888  * Unfortunately we don't have the quoted and escaped string any more, so
5889  * we have to re-escape it.
5890  */
5891  escape_json(_state->strval, fname);
5892  appendStringInfoCharMacro(_state->strval, ':');
5893 
5894  return JSON_SUCCESS;
5895 }

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

Definition at line 5840 of file jsonfuncs.c.

5841 {
5843 
5844  appendStringInfoCharMacro(_state->strval, '{');
5845 
5846  return JSON_SUCCESS;
5847 }

References appendStringInfoCharMacro, JSON_SUCCESS, and TransformJsonStringValuesState::strval.

Referenced by transform_json_string_values().

◆ transform_string_values_scalar()

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

Definition at line 5909 of file jsonfuncs.c.

5910 {
5912 
5913  if (tokentype == JSON_TOKEN_STRING)
5914  {
5915  text *out = _state->action(_state->action_state, token, strlen(token));
5916 
5917  escape_json(_state->strval, text_to_cstring(out));
5918  }
5919  else
5921 
5922  return JSON_SUCCESS;
5923 }
JsonTransformStringValuesAction action
Definition: jsonfuncs.c:79

References TransformJsonStringValuesState::action, TransformJsonStringValuesState::action_state, appendStringInfoString(), escape_json(), JSON_SUCCESS, JSON_TOKEN_STRING, TransformJsonStringValuesState::strval, text_to_cstring(), and token.

Referenced by transform_json_string_values().

◆ update_cached_tupdesc()

static void update_cached_tupdesc ( CompositeIOData io,
MemoryContext  mcxt 
)
static

Definition at line 3025 of file jsonfuncs.c.

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

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