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

Go to the source code of this file.

Data Structures

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

Macros

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

Typedefs

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

Enumerations

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

Functions

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

Macro Definition Documentation

◆ JB_PATH_CONSISTENT_POSITION

#define JB_PATH_CONSISTENT_POSITION   0x0040

Definition at line 52 of file jsonfuncs.c.

◆ JB_PATH_CREATE

#define JB_PATH_CREATE   0x0001

Definition at line 44 of file jsonfuncs.c.

◆ JB_PATH_CREATE_OR_INSERT

#define JB_PATH_CREATE_OR_INSERT    (JB_PATH_INSERT_BEFORE | JB_PATH_INSERT_AFTER | JB_PATH_CREATE)

Definition at line 49 of file jsonfuncs.c.

◆ JB_PATH_DELETE

#define JB_PATH_DELETE   0x0002

Definition at line 45 of file jsonfuncs.c.

◆ JB_PATH_FILL_GAPS

#define JB_PATH_FILL_GAPS   0x0020

Definition at line 51 of file jsonfuncs.c.

◆ JB_PATH_INSERT_AFTER

#define JB_PATH_INSERT_AFTER   0x0010

Definition at line 48 of file jsonfuncs.c.

◆ JB_PATH_INSERT_BEFORE

#define JB_PATH_INSERT_BEFORE   0x0008

Definition at line 47 of file jsonfuncs.c.

◆ JB_PATH_REPLACE

#define JB_PATH_REPLACE   0x0004

Definition at line 46 of file jsonfuncs.c.

◆ JsObjectFree

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

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

◆ JsValueIsNull

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

Definition at line 319 of file jsonfuncs.c.

◆ JsValueIsString

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

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

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

Function Documentation

◆ alen_array_element_start()

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

Definition at line 1927 of file jsonfuncs.c.

1928 {
1929  AlenState *_state = (AlenState *) state;
1930 
1931  /* just count up all the level 1 elements */
1932  if (_state->lex->lex_level == 1)
1933  _state->count++;
1934 
1935  return JSON_SUCCESS;
1936 }
@ JSON_SUCCESS
Definition: jsonapi.h:36
int count
Definition: jsonfuncs.c:105
JsonLexContext * lex
Definition: jsonfuncs.c:104
Definition: regguts.h:323

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

Referenced by json_array_length().

◆ alen_object_start()

static JsonParseErrorType alen_object_start ( void *  state)
static

Definition at line 1899 of file jsonfuncs.c.

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

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

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

3476 {
3478  MemoryContextAlloc(mcxt,
3479  offsetof(RecordIOData, columns) +
3480  ncolumns * sizeof(ColumnIOData));
3481 
3482  data->record_type = InvalidOid;
3483  data->record_typmod = 0;
3484  data->ncolumns = ncolumns;
3485  MemSet(data->columns, 0, sizeof(ColumnIOData) * ncolumns);
3486 
3487  return data;
3488 }
#define MemSet(start, val, len)
Definition: c.h:1025
struct ColumnIOData ColumnIOData
Definition: jsonfuncs.c:162
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1181
const void * data
#define InvalidOid
Definition: postgres_ext.h: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 2167 of file jsonfuncs.c.

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

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

Referenced by each_worker().

◆ each_object_field_end()

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

Definition at line 2119 of file jsonfuncs.c.

2120 {
2121  EachState *_state = (EachState *) state;
2122  MemoryContext old_cxt;
2123  int len;
2124  text *val;
2125  HeapTuple tuple;
2126  Datum values[2];
2127  bool nulls[2] = {false, false};
2128 
2129  /* skip over nested objects */
2130  if (_state->lex->lex_level != 1)
2131  return JSON_SUCCESS;
2132 
2133  /* use the tmp context so we can clean up after each tuple is done */
2134  old_cxt = MemoryContextSwitchTo(_state->tmp_cxt);
2135 
2136  values[0] = CStringGetTextDatum(fname);
2137 
2138  if (isnull && _state->normalize_results)
2139  {
2140  nulls[1] = true;
2141  values[1] = (Datum) 0;
2142  }
2143  else if (_state->next_scalar)
2144  {
2146  _state->next_scalar = false;
2147  }
2148  else
2149  {
2150  len = _state->lex->prev_token_terminator - _state->result_start;
2152  values[1] = PointerGetDatum(val);
2153  }
2154 
2155  tuple = heap_form_tuple(_state->ret_tdesc, values, nulls);
2156 
2157  tuplestore_puttuple(_state->tuple_store, tuple);
2158 
2159  /* clean up and switch back */
2160  MemoryContextSwitchTo(old_cxt);
2161  MemoryContextReset(_state->tmp_cxt);
2162 
2163  return JSON_SUCCESS;
2164 }
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define CStringGetTextDatum(s)
Definition: builtins.h:97
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c: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:116
TupleDesc ret_tdesc
Definition: jsonfuncs.c:113
char * normalized_scalar
Definition: jsonfuncs.c:118
const char * result_start
Definition: jsonfuncs.c:115
Tuplestorestate * tuple_store
Definition: jsonfuncs.c:112
MemoryContext tmp_cxt
Definition: jsonfuncs.c:114
bool next_scalar
Definition: jsonfuncs.c:117
const char * prev_token_terminator
Definition: jsonapi.h:105
Definition: c.h:692
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
Definition: tuplestore.c:764
text * cstring_to_text_with_len(const char *s, int len)
Definition: varlena.c: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 2097 of file jsonfuncs.c.

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

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

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

2058 {
2059  text *json = PG_GETARG_TEXT_PP(0);
2060  JsonLexContext lex;
2061  JsonSemAction *sem;
2062  ReturnSetInfo *rsi;
2063  EachState *state;
2064 
2065  state = palloc0(sizeof(EachState));
2066  sem = palloc0(sizeof(JsonSemAction));
2067 
2068  rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2069 
2071  state->tuple_store = rsi->setResult;
2072  state->ret_tdesc = rsi->setDesc;
2073 
2074  sem->semstate = (void *) state;
2076  sem->scalar = each_scalar;
2079 
2080  state->normalize_results = as_text;
2081  state->next_scalar = false;
2082  state->lex = makeJsonLexContext(&lex, json, true);
2084  "json_each temporary cxt",
2086 
2088 
2089  MemoryContextDelete(state->tmp_cxt);
2090  freeJsonLexContext(&lex);
2091 
2092  PG_RETURN_NULL();
2093 }
#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:639
JsonLexContext * makeJsonLexContext(JsonLexContext *lex, text *json, bool need_escapes)
Definition: jsonfuncs.c:539
static JsonParseErrorType each_object_field_end(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:2119
static JsonParseErrorType each_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:2181
static JsonParseErrorType each_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:2097
static JsonParseErrorType each_array_start(void *state)
Definition: jsonfuncs.c:2167
#define pg_parse_json_or_ereport(lex, sem)
Definition: jsonfuncs.h:47
void * palloc0(Size size)
Definition: mcxt.c:1347
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
fmNodePtr resultinfo
Definition: fmgr.h:89
json_ofield_action object_field_start
Definition: jsonapi.h:149
json_scalar_action scalar
Definition: jsonapi.h:153
void * semstate
Definition: jsonapi.h:144
json_struct_action array_start
Definition: jsonapi.h:147
json_ofield_action object_field_end
Definition: jsonapi.h:150
TupleDesc setDesc
Definition: execnodes.h:343
Tuplestorestate * setResult
Definition: execnodes.h:342
static JsonSemAction sem

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

Referenced by json_each(), and json_each_text().

◆ each_worker_jsonb()

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

Definition at line 1973 of file jsonfuncs.c.

1974 {
1975  Jsonb *jb = PG_GETARG_JSONB_P(0);
1976  ReturnSetInfo *rsi;
1977  MemoryContext old_cxt,
1978  tmp_cxt;
1979  bool skipNested = false;
1980  JsonbIterator *it;
1981  JsonbValue v;
1983 
1984  if (!JB_ROOT_IS_OBJECT(jb))
1985  ereport(ERROR,
1986  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1987  errmsg("cannot call %s on a non-object",
1988  funcname)));
1989 
1990  rsi = (ReturnSetInfo *) fcinfo->resultinfo;
1992 
1994  "jsonb_each temporary cxt",
1996 
1997  it = JsonbIteratorInit(&jb->root);
1998 
1999  while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
2000  {
2001  skipNested = true;
2002 
2003  if (r == WJB_KEY)
2004  {
2005  text *key;
2006  Datum values[2];
2007  bool nulls[2] = {false, false};
2008 
2009  /* Use the tmp context so we can clean up after each tuple is done */
2010  old_cxt = MemoryContextSwitchTo(tmp_cxt);
2011 
2012  key = cstring_to_text_with_len(v.val.string.val, v.val.string.len);
2013 
2014  /*
2015  * The next thing the iterator fetches should be the value, no
2016  * matter what shape it is.
2017  */
2018  r = JsonbIteratorNext(&it, &v, skipNested);
2019  Assert(r != WJB_DONE);
2020 
2021  values[0] = PointerGetDatum(key);
2022 
2023  if (as_text)
2024  {
2025  if (v.type == jbvNull)
2026  {
2027  /* a json null is an sql null in text mode */
2028  nulls[1] = true;
2029  values[1] = (Datum) NULL;
2030  }
2031  else
2033  }
2034  else
2035  {
2036  /* Not in text mode, just return the Jsonb */
2037  Jsonb *val = JsonbValueToJsonb(&v);
2038 
2039  values[1] = PointerGetDatum(val);
2040  }
2041 
2042  tuplestore_putvalues(rsi->setResult, rsi->setDesc, values, nulls);
2043 
2044  /* clean up and switch back */
2045  MemoryContextSwitchTo(old_cxt);
2046  MemoryContextReset(tmp_cxt);
2047  }
2048  }
2049 
2050  MemoryContextDelete(tmp_cxt);
2051 
2052  PG_RETURN_NULL();
2053 }
#define Assert(condition)
Definition: c.h:863
#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:1804
enum jbvType type
Definition: jsonb.h:255
char * val
Definition: jsonb.h:264
Definition: jsonb.h:213
JsonbContainer root
Definition: jsonb.h:215
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:784

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

Referenced by jsonb_each(), and jsonb_each_text().

◆ elements_array_element_end()

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

Definition at line 2371 of file jsonfuncs.c.

2372 {
2373  ElementsState *_state = (ElementsState *) state;
2374  MemoryContext old_cxt;
2375  int len;
2376  text *val;
2377  HeapTuple tuple;
2378  Datum values[1];
2379  bool nulls[1] = {false};
2380 
2381  /* skip over nested objects */
2382  if (_state->lex->lex_level != 1)
2383  return JSON_SUCCESS;
2384 
2385  /* use the tmp context so we can clean up after each tuple is done */
2386  old_cxt = MemoryContextSwitchTo(_state->tmp_cxt);
2387 
2388  if (isnull && _state->normalize_results)
2389  {
2390  nulls[0] = true;
2391  values[0] = (Datum) NULL;
2392  }
2393  else if (_state->next_scalar)
2394  {
2396  _state->next_scalar = false;
2397  }
2398  else
2399  {
2400  len = _state->lex->prev_token_terminator - _state->result_start;
2402  values[0] = PointerGetDatum(val);
2403  }
2404 
2405  tuple = heap_form_tuple(_state->ret_tdesc, values, nulls);
2406 
2407  tuplestore_puttuple(_state->tuple_store, tuple);
2408 
2409  /* clean up and switch back */
2410  MemoryContextSwitchTo(old_cxt);
2411  MemoryContextReset(_state->tmp_cxt);
2412 
2413  return JSON_SUCCESS;
2414 }
bool next_scalar
Definition: jsonfuncs.c:131
TupleDesc ret_tdesc
Definition: jsonfuncs.c:127
Tuplestorestate * tuple_store
Definition: jsonfuncs.c:126
bool normalize_results
Definition: jsonfuncs.c:130
MemoryContext tmp_cxt
Definition: jsonfuncs.c:128
JsonLexContext * lex
Definition: jsonfuncs.c:124
const char * result_start
Definition: jsonfuncs.c:129
char * normalized_scalar
Definition: jsonfuncs.c:132

References cstring_to_text_with_len(), CStringGetTextDatum, heap_form_tuple(), JSON_SUCCESS, len, ElementsState::lex, JsonLexContext::lex_level, MemoryContextReset(), MemoryContextSwitchTo(), ElementsState::next_scalar, ElementsState::normalize_results, ElementsState::normalized_scalar, PointerGetDatum(), JsonLexContext::prev_token_terminator, ElementsState::result_start, ElementsState::ret_tdesc, ElementsState::tmp_cxt, ElementsState::tuple_store, tuplestore_puttuple(), val, and values.

Referenced by elements_worker().

◆ elements_array_element_start()

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

Definition at line 2349 of file jsonfuncs.c.

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

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

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

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

Referenced by elements_worker().

◆ elements_scalar()

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

Definition at line 2432 of file jsonfuncs.c.

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

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

2308 {
2309  text *json = PG_GETARG_TEXT_PP(0);
2310  JsonLexContext lex;
2311  JsonSemAction *sem;
2312  ReturnSetInfo *rsi;
2314 
2315  /* elements only needs escaped strings when as_text */
2316  makeJsonLexContext(&lex, json, as_text);
2317 
2318  state = palloc0(sizeof(ElementsState));
2319  sem = palloc0(sizeof(JsonSemAction));
2320 
2322  rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2323  state->tuple_store = rsi->setResult;
2324  state->ret_tdesc = rsi->setDesc;
2325 
2326  sem->semstate = (void *) state;
2331 
2332  state->function_name = funcname;
2333  state->normalize_results = as_text;
2334  state->next_scalar = false;
2335  state->lex = &lex;
2337  "json_array_elements temporary cxt",
2339 
2341 
2342  MemoryContextDelete(state->tmp_cxt);
2343  freeJsonLexContext(&lex);
2344 
2345  PG_RETURN_NULL();
2346 }
#define MAT_SRF_USE_EXPECTED_DESC
Definition: funcapi.h:296
static JsonParseErrorType elements_object_start(void *state)
Definition: jsonfuncs.c:2417
static JsonParseErrorType elements_array_element_end(void *state, bool isnull)
Definition: jsonfuncs.c:2371
static JsonParseErrorType elements_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:2432
static JsonParseErrorType elements_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:2349
json_struct_action object_start
Definition: jsonapi.h:145
json_aelem_action array_element_start
Definition: jsonapi.h:151
json_aelem_action array_element_end
Definition: jsonapi.h:152

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

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

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

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

Referenced by get_worker().

◆ get_array_element_start()

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

Definition at line 1352 of file jsonfuncs.c.

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

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

Referenced by get_worker().

◆ get_array_end()

static JsonParseErrorType get_array_end ( void *  state)
static

Definition at line 1334 of file jsonfuncs.c.

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

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

Referenced by get_worker().

◆ get_array_start()

static JsonParseErrorType get_array_start ( void *  state)
static

Definition at line 1294 of file jsonfuncs.c.

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

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

Referenced by get_worker().

◆ get_json_object_as_hash()

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

Definition at line 3810 of file jsonfuncs.c.

3812 {
3813  HASHCTL ctl;
3814  HTAB *tab;
3815  JHashState *state;
3816  JsonSemAction *sem;
3817 
3818  ctl.keysize = NAMEDATALEN;
3819  ctl.entrysize = sizeof(JsonHashEntry);
3820  ctl.hcxt = CurrentMemoryContext;
3821  tab = hash_create("json object hashtable",
3822  100,
3823  &ctl,
3825 
3826  state = palloc0(sizeof(JHashState));
3827  sem = palloc0(sizeof(JsonSemAction));
3828 
3829  state->function_name = funcname;
3830  state->hash = tab;
3831  state->lex = makeJsonLexContextCstringLen(NULL, json, len,
3832  GetDatabaseEncoding(), true);
3833 
3834  sem->semstate = (void *) state;
3836  sem->scalar = hash_scalar;
3839 
3840  if (!pg_parse_json_or_errsave(state->lex, sem, escontext))
3841  {
3842  hash_destroy(state->hash);
3843  tab = NULL;
3844  }
3845 
3846  freeJsonLexContext(state->lex);
3847 
3848  return tab;
3849 }
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:865
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
#define HASH_STRINGS
Definition: hsearch.h:96
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
JsonLexContext * makeJsonLexContextCstringLen(JsonLexContext *lex, const char *json, size_t len, int encoding, bool need_escapes)
Definition: jsonapi.c:390
static JsonParseErrorType hash_array_start(void *state)
Definition: jsonfuncs.c:3929
static JsonParseErrorType hash_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:3942
struct JsonHashEntry JsonHashEntry
bool pg_parse_json_or_errsave(JsonLexContext *lex, const JsonSemAction *sem, Node *escontext)
Definition: jsonfuncs.c:518
static JsonParseErrorType hash_object_field_end(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:3878
static JsonParseErrorType hash_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:3852
int GetDatabaseEncoding(void)
Definition: mbutils.c:1261
#define NAMEDATALEN
tree ctl
Definition: radixtree.h:1853
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 1499 of file jsonfuncs.c.

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

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

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

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

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

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

Referenced by get_worker().

◆ get_object_field_start()

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

Definition at line 1196 of file jsonfuncs.c.

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

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

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

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

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

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

Referenced by json_extract_path(), and json_extract_path_text().

◆ get_record_type_from_argument()

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

Definition at line 3635 of file jsonfuncs.c.

3638 {
3639  cache->argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
3640  prepare_column_cache(&cache->c,
3641  cache->argtype, -1,
3642  cache->fn_mcxt, false);
3643  if (cache->c.typcat != TYPECAT_COMPOSITE &&
3644  cache->c.typcat != TYPECAT_COMPOSITE_DOMAIN)
3645  ereport(ERROR,
3646  (errcode(ERRCODE_DATATYPE_MISMATCH),
3647  /* translator: %s is a function name, eg json_to_record */
3648  errmsg("first argument of %s must be a row type",
3649  funcname)));
3650 }
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:3250
TypeCat typcat
Definition: jsonfuncs.c:215
FmgrInfo * flinfo
Definition: fmgr.h:87
ColumnIOData c
Definition: jsonfuncs.c:240
MemoryContext fn_mcxt
Definition: jsonfuncs.c:241

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

Referenced by populate_record_worker(), and populate_recordset_worker().

◆ get_record_type_from_query()

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

Definition at line 3661 of file jsonfuncs.c.

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

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

1107 {
1108  JsonSemAction *sem = palloc0(sizeof(JsonSemAction));
1109  GetState *state = palloc0(sizeof(GetState));
1110 
1111  Assert(npath >= 0);
1112 
1113  state->lex = makeJsonLexContext(NULL, json, true);
1114 
1115  /* is it "_as_text" variant? */
1116  state->normalize_results = normalize_results;
1117  state->npath = npath;
1118  state->path_names = tpath;
1119  state->path_indexes = ipath;
1120  state->pathok = palloc0(sizeof(bool) * npath);
1121  state->array_cur_index = palloc(sizeof(int) * npath);
1122 
1123  if (npath > 0)
1124  state->pathok[0] = true;
1125 
1126  sem->semstate = (void *) state;
1127 
1128  /*
1129  * Not all variants need all the semantic routines. Only set the ones that
1130  * are actually needed for maximum efficiency.
1131  */
1132  sem->scalar = get_scalar;
1133  if (npath == 0)
1134  {
1139  }
1140  if (tpath != NULL)
1141  {
1144  }
1145  if (ipath != NULL)
1146  {
1150  }
1151 
1153  freeJsonLexContext(state->lex);
1154 
1155  return state->tresult;
1156 }
static JsonParseErrorType get_array_element_end(void *state, bool isnull)
Definition: jsonfuncs.c:1400
static JsonParseErrorType get_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:1196
static JsonParseErrorType get_object_start(void *state)
Definition: jsonfuncs.c:1159
static JsonParseErrorType get_array_start(void *state)
Definition: jsonfuncs.c:1294
static JsonParseErrorType get_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:1444
static JsonParseErrorType get_object_end(void *state)
Definition: jsonfuncs.c:1178
static JsonParseErrorType get_object_field_end(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:1243
static JsonParseErrorType get_array_end(void *state)
Definition: jsonfuncs.c:1334
static JsonParseErrorType get_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:1352
json_struct_action array_end
Definition: jsonapi.h:148
json_struct_action object_end
Definition: jsonapi.h:146

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

3930 {
3931  JHashState *_state = (JHashState *) state;
3932 
3933  if (_state->lex->lex_level == 0)
3934  ereport(ERROR,
3935  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3936  errmsg("cannot call %s on an array", _state->function_name)));
3937 
3938  return JSON_SUCCESS;
3939 }
const char * function_name
Definition: jsonfuncs.c:139
JsonLexContext * lex
Definition: jsonfuncs.c:138

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

Referenced by get_json_object_as_hash().

◆ hash_object_field_end()

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

Definition at line 3878 of file jsonfuncs.c.

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

References Assert, JHashState::hash, HASH_ENTER, hash_search(), JSON_SUCCESS, JSON_TOKEN_NULL, len, JHashState::lex, JsonLexContext::lex_level, NAMEDATALEN, palloc(), JsonLexContext::prev_token_terminator, JHashState::save_json_start, JHashState::saved_scalar, JHashState::saved_token_type, JsonHashEntry::type, JsonHashEntry::val, and val.

Referenced by get_json_object_as_hash().

◆ hash_object_field_start()

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

Definition at line 3852 of file jsonfuncs.c.

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

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

Referenced by get_json_object_as_hash().

◆ hash_scalar()

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

Definition at line 3942 of file jsonfuncs.c.

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

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

5711 {
5712  JsonLexContext lex;
5713  JsonSemAction *sem = palloc0(sizeof(JsonSemAction));
5715 
5716  state->lex = makeJsonLexContext(&lex, json, true);
5717  state->action = action;
5718  state->action_state = action_state;
5719  state->flags = flags;
5720 
5721  sem->semstate = (void *) state;
5724 
5726  freeJsonLexContext(&lex);
5727 }
static JsonParseErrorType iterate_values_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:5762
static JsonParseErrorType iterate_values_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:5734

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

5643 {
5644  JsonbIterator *it;
5645  JsonbValue v;
5647 
5648  it = JsonbIteratorInit(&jb->root);
5649 
5650  /*
5651  * Just recursively iterating over jsonb and call callback on all
5652  * corresponding elements
5653  */
5654  while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
5655  {
5656  if (type == WJB_KEY)
5657  {
5658  if (flags & jtiKey)
5659  action(state, v.val.string.val, v.val.string.len);
5660 
5661  continue;
5662  }
5663  else if (!(type == WJB_VALUE || type == WJB_ELEM))
5664  {
5665  /* do not call callback for composite JsonbValue */
5666  continue;
5667  }
5668 
5669  /* JsonbValue is a value of object or element of array */
5670  switch (v.type)
5671  {
5672  case jbvString:
5673  if (flags & jtiString)
5674  action(state, v.val.string.val, v.val.string.len);
5675  break;
5676  case jbvNumeric:
5677  if (flags & jtiNumeric)
5678  {
5679  char *val;
5680 
5682  NumericGetDatum(v.val.numeric)));
5683 
5684  action(state, val, strlen(val));
5685  pfree(val);
5686  }
5687  break;
5688  case jbvBool:
5689  if (flags & jtiBool)
5690  {
5691  if (v.val.boolean)
5692  action(state, "true", 4);
5693  else
5694  action(state, "false", 5);
5695  }
5696  break;
5697  default:
5698  /* do not call callback for composite JsonbValue */
5699  break;
5700  }
5701  }
5702 }
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:815
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:641
@ 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:1521
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 5762 of file jsonfuncs.c.

5763 {
5765 
5766  if (_state->flags & jtiKey)
5767  {
5768  char *val = pstrdup(fname);
5769 
5770  _state->action(_state->action_state, val, strlen(val));
5771  }
5772 
5773  return JSON_SUCCESS;
5774 }
char * pstrdup(const char *in)
Definition: mcxt.c:1696
JsonIterateStringValuesAction action
Definition: jsonfuncs.c:68

References IterateJsonStringValuesState::action, IterateJsonStringValuesState::action_state, IterateJsonStringValuesState::flags, JSON_SUCCESS, jtiKey, pstrdup(), and val.

Referenced by iterate_json_values().

◆ iterate_values_scalar()

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

Definition at line 5734 of file jsonfuncs.c.

5735 {
5737 
5738  switch (tokentype)
5739  {
5740  case JSON_TOKEN_STRING:
5741  if (_state->flags & jtiString)
5742  _state->action(_state->action_state, token, strlen(token));
5743  break;
5744  case JSON_TOKEN_NUMBER:
5745  if (_state->flags & jtiNumeric)
5746  _state->action(_state->action_state, token, strlen(token));
5747  break;
5748  case JSON_TOKEN_TRUE:
5749  case JSON_TOKEN_FALSE:
5750  if (_state->flags & jtiBool)
5751  _state->action(_state->action_state, token, strlen(token));
5752  break;
5753  default:
5754  /* do not call callback for any other token */
5755  break;
5756  }
5757 
5758  return JSON_SUCCESS;
5759 }
@ JSON_TOKEN_FALSE
Definition: jsonapi.h:29
@ JSON_TOKEN_TRUE
Definition: jsonapi.h:28
@ JSON_TOKEN_NUMBER
Definition: jsonapi.h:21

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

Referenced by iterate_json_values().

◆ IteratorConcat()

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

Definition at line 5053 of file jsonfuncs.c.

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

3492 {
3493  jsv->is_json = obj->is_json;
3494 
3495  if (jsv->is_json)
3496  {
3497  JsonHashEntry *hashentry = hash_search(obj->val.json_hash, field,
3498  HASH_FIND, NULL);
3499 
3500  jsv->val.json.type = hashentry ? hashentry->type : JSON_TOKEN_NULL;
3501  jsv->val.json.str = jsv->val.json.type == JSON_TOKEN_NULL ? NULL :
3502  hashentry->val;
3503  jsv->val.json.len = jsv->val.json.str ? -1 : 0; /* null-terminated */
3504 
3505  return hashentry != NULL;
3506  }
3507  else
3508  {
3509  jsv->val.jsonb = !obj->val.jsonb_cont ? NULL :
3510  getKeyJsonValueFromContainer(obj->val.jsonb_cont, field, strlen(field),
3511  NULL);
3512 
3513  return jsv->val.jsonb != NULL;
3514  }
3515 }
@ 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:310
JsonbContainer * jsonb_cont
Definition: jsonfuncs.c:314
HTAB * json_hash
Definition: jsonfuncs.c:313
union JsObject::@27 val
JsonbValue * jsonb
Definition: jsonfuncs.c:304
struct JsValue::@25::@26 json
union JsValue::@25 val
bool is_json
Definition: jsonfuncs.c:294

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

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

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

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

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

References elements_worker().

◆ json_array_elements_text()

Datum json_array_elements_text ( PG_FUNCTION_ARGS  )

Definition at line 2301 of file jsonfuncs.c.

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

References elements_worker().

◆ json_array_length()

Datum json_array_length ( PG_FUNCTION_ARGS  )

Definition at line 1851 of file jsonfuncs.c.

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

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

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

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

References each_worker().

◆ json_each_text()

Datum json_each_text ( PG_FUNCTION_ARGS  )

Definition at line 1961 of file jsonfuncs.c.

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

References each_worker().

◆ json_errsave_error()

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

Definition at line 640 of file jsonfuncs.c.

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

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

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

◆ json_extract_path()

Datum json_extract_path ( PG_FUNCTION_ARGS  )

Definition at line 1008 of file jsonfuncs.c.

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

References get_path_all().

◆ json_extract_path_text()

Datum json_extract_path_text ( PG_FUNCTION_ARGS  )

Definition at line 1014 of file jsonfuncs.c.

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

References get_path_all().

◆ json_get_first_token()

JsonTokenType json_get_first_token ( text json,
bool  throw_error 
)

Definition at line 5949 of file jsonfuncs.c.

5950 {
5951  JsonLexContext lex;
5952  JsonParseErrorType result;
5953 
5954  makeJsonLexContext(&lex, json, false);
5955 
5956  /* Lex exactly one token from the input and check its type. */
5957  result = json_lex(&lex);
5958 
5959  if (result == JSON_SUCCESS)
5960  return lex.token_type;
5961 
5962  if (throw_error)
5963  json_errsave_error(result, &lex, NULL);
5964 
5965  return JSON_TOKEN_INVALID; /* invalid json */
5966 }
JsonParseErrorType json_lex(JsonLexContext *lex)
Definition: jsonapi.c:1498
@ JSON_TOKEN_INVALID
Definition: jsonapi.h:19

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

Referenced by ExecEvalJsonIsPredicate().

◆ json_object_field()

Datum json_object_field ( PG_FUNCTION_ARGS  )

Definition at line 845 of file jsonfuncs.c.

846 {
847  text *json = PG_GETARG_TEXT_PP(0);
848  text *fname = PG_GETARG_TEXT_PP(1);
849  char *fnamestr = text_to_cstring(fname);
850  text *result;
851 
852  result = get_worker(json, &fnamestr, NULL, 1, false);
853 
854  if (result != NULL)
855  PG_RETURN_TEXT_P(result);
856  else
857  PG_RETURN_NULL();
858 }
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 883 of file jsonfuncs.c.

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

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

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

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

References populate_record_worker().

◆ json_populate_recordset()

Datum json_populate_recordset ( PG_FUNCTION_ARGS  )

Definition at line 3987 of file jsonfuncs.c.

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

References populate_recordset_worker().

◆ json_populate_type()

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

Definition at line 3344 of file jsonfuncs.c.

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

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

4494 {
4495  text *json = PG_GETARG_TEXT_PP(0);
4497  JsonLexContext lex;
4498  JsonSemAction *sem;
4499 
4500  state = palloc0(sizeof(StripnullState));
4501  sem = palloc0(sizeof(JsonSemAction));
4502 
4503  state->lex = makeJsonLexContext(&lex, json, true);
4504  state->strval = makeStringInfo();
4505  state->skip_next_null = false;
4506 
4507  sem->semstate = (void *) state;
4512  sem->scalar = sn_scalar;
4515 
4517 
4519  state->strval->len));
4520 }
static JsonParseErrorType sn_object_end(void *state)
Definition: jsonfuncs.c:4399
static JsonParseErrorType sn_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:4459
static JsonParseErrorType sn_object_start(void *state)
Definition: jsonfuncs.c:4389
static JsonParseErrorType sn_array_start(void *state)
Definition: jsonfuncs.c:4409
static JsonParseErrorType sn_array_end(void *state)
Definition: jsonfuncs.c:4419
static JsonParseErrorType sn_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:4429
static JsonParseErrorType sn_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:4470
StringInfo makeStringInfo(void)
Definition: stringinfo.c:38

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

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

References populate_record_worker().

◆ json_to_recordset()

Datum json_to_recordset ( PG_FUNCTION_ARGS  )

Definition at line 3994 of file jsonfuncs.c.

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

References populate_recordset_worker().

◆ jsonb_array_element()

Datum jsonb_array_element ( PG_FUNCTION_ARGS  )

Definition at line 936 of file jsonfuncs.c.

937 {
938  Jsonb *jb = PG_GETARG_JSONB_P(0);
939  int element = PG_GETARG_INT32(1);
940  JsonbValue *v;
941 
942  if (!JB_ROOT_IS_ARRAY(jb))
943  PG_RETURN_NULL();
944 
945  /* Handle negative subscript */
946  if (element < 0)
947  {
948  uint32 nelements = JB_ROOT_COUNT(jb);
949 
950  if (pg_abs_s32(element) > nelements)
951  PG_RETURN_NULL();
952  else
953  element += nelements;
954  }
955 
957  if (v != NULL)
959 
960  PG_RETURN_NULL();
961 }
unsigned int uint32
Definition: c.h:518
static uint32 pg_abs_s32(int32 a)
Definition: int.h:189
#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_abs_s32(), PG_GETARG_INT32, PG_GETARG_JSONB_P, PG_RETURN_JSONB_P, PG_RETURN_NULL, and Jsonb::root.

◆ jsonb_array_element_text()

Datum jsonb_array_element_text ( PG_FUNCTION_ARGS  )

Definition at line 979 of file jsonfuncs.c.

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

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

◆ jsonb_array_elements()

Datum jsonb_array_elements ( PG_FUNCTION_ARGS  )

Definition at line 2207 of file jsonfuncs.c.

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

References elements_worker_jsonb().

◆ jsonb_array_elements_text()

Datum jsonb_array_elements_text ( PG_FUNCTION_ARGS  )

Definition at line 2213 of file jsonfuncs.c.

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

References elements_worker_jsonb().

◆ jsonb_array_length()

Datum jsonb_array_length ( PG_FUNCTION_ARGS  )

Definition at line 1877 of file jsonfuncs.c.

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

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

4601 {
4602  Jsonb *jb1 = PG_GETARG_JSONB_P(0);
4603  Jsonb *jb2 = PG_GETARG_JSONB_P(1);
4604  JsonbParseState *state = NULL;
4605  JsonbValue *res;
4606  JsonbIterator *it1,
4607  *it2;
4608 
4609  /*
4610  * If one of the jsonb is empty, just return the other if it's not scalar
4611  * and both are of the same kind. If it's a scalar or they are of
4612  * different kinds we need to perform the concatenation even if one is
4613  * empty.
4614  */
4615  if (JB_ROOT_IS_OBJECT(jb1) == JB_ROOT_IS_OBJECT(jb2))
4616  {
4617  if (JB_ROOT_COUNT(jb1) == 0 && !JB_ROOT_IS_SCALAR(jb2))
4618  PG_RETURN_JSONB_P(jb2);
4619  else if (JB_ROOT_COUNT(jb2) == 0 && !JB_ROOT_IS_SCALAR(jb1))
4620  PG_RETURN_JSONB_P(jb1);
4621  }
4622 
4623  it1 = JsonbIteratorInit(&jb1->root);
4624  it2 = JsonbIteratorInit(&jb2->root);
4625 
4626  res = IteratorConcat(&it1, &it2, &state);
4627 
4628  Assert(res != NULL);
4629 
4631 }
static JsonbValue * IteratorConcat(JsonbIterator **it1, JsonbIterator **it2, JsonbParseState **state)
Definition: jsonfuncs.c:5053

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

4642 {
4643  Jsonb *in = PG_GETARG_JSONB_P(0);
4644  text *key = PG_GETARG_TEXT_PP(1);
4645  char *keyptr = VARDATA_ANY(key);
4646  int keylen = VARSIZE_ANY_EXHDR(key);
4647  JsonbParseState *state = NULL;
4648  JsonbIterator *it;
4649  JsonbValue v,
4650  *res = NULL;
4651  bool skipNested = false;
4653 
4654  if (JB_ROOT_IS_SCALAR(in))
4655  ereport(ERROR,
4656  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4657  errmsg("cannot delete from scalar")));
4658 
4659  if (JB_ROOT_COUNT(in) == 0)
4660  PG_RETURN_JSONB_P(in);
4661 
4662  it = JsonbIteratorInit(&in->root);
4663 
4664  while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4665  {
4666  skipNested = true;
4667 
4668  if ((r == WJB_ELEM || r == WJB_KEY) &&
4669  (v.type == jbvString && keylen == v.val.string.len &&
4670  memcmp(keyptr, v.val.string.val, keylen) == 0))
4671  {
4672  /* skip corresponding value as well */
4673  if (r == WJB_KEY)
4674  (void) JsonbIteratorNext(&it, &v, true);
4675 
4676  continue;
4677  }
4678 
4679  res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4680  }
4681 
4682  Assert(res != NULL);
4683 
4685 }

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

4695 {
4696  Jsonb *in = PG_GETARG_JSONB_P(0);
4697  ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1);
4698  Datum *keys_elems;
4699  bool *keys_nulls;
4700  int keys_len;
4701  JsonbParseState *state = NULL;
4702  JsonbIterator *it;
4703  JsonbValue v,
4704  *res = NULL;
4705  bool skipNested = false;
4707 
4708  if (ARR_NDIM(keys) > 1)
4709  ereport(ERROR,
4710  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4711  errmsg("wrong number of array subscripts")));
4712 
4713  if (JB_ROOT_IS_SCALAR(in))
4714  ereport(ERROR,
4715  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4716  errmsg("cannot delete from scalar")));
4717 
4718  if (JB_ROOT_COUNT(in) == 0)
4719  PG_RETURN_JSONB_P(in);
4720 
4721  deconstruct_array_builtin(keys, TEXTOID, &keys_elems, &keys_nulls, &keys_len);
4722 
4723  if (keys_len == 0)
4724  PG_RETURN_JSONB_P(in);
4725 
4726  it = JsonbIteratorInit(&in->root);
4727 
4728  while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4729  {
4730  skipNested = true;
4731 
4732  if ((r == WJB_ELEM || r == WJB_KEY) && v.type == jbvString)
4733  {
4734  int i;
4735  bool found = false;
4736 
4737  for (i = 0; i < keys_len; i++)
4738  {
4739  char *keyptr;
4740  int keylen;
4741 
4742  if (keys_nulls[i])
4743  continue;
4744 
4745  /* We rely on the array elements not being toasted */
4746  keyptr = VARDATA_ANY(keys_elems[i]);
4747  keylen = VARSIZE_ANY_EXHDR(keys_elems[i]);
4748  if (keylen == v.val.string.len &&
4749  memcmp(keyptr, v.val.string.val, keylen) == 0)
4750  {
4751  found = true;
4752  break;
4753  }
4754  }
4755  if (found)
4756  {
4757  /* skip corresponding value as well */
4758  if (r == WJB_KEY)
4759  (void) JsonbIteratorNext(&it, &v, true);
4760 
4761  continue;
4762  }
4763  }
4764 
4765  res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4766  }
4767 
4768  Assert(res != NULL);
4769 
4771 }
#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 4781 of file jsonfuncs.c.

4782 {
4783  Jsonb *in = PG_GETARG_JSONB_P(0);
4784  int idx = PG_GETARG_INT32(1);
4785  JsonbParseState *state = NULL;
4786  JsonbIterator *it;
4787  uint32 i = 0,
4788  n;
4789  JsonbValue v,
4790  *res = NULL;
4792 
4793  if (JB_ROOT_IS_SCALAR(in))
4794  ereport(ERROR,
4795  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4796  errmsg("cannot delete from scalar")));
4797 
4798  if (JB_ROOT_IS_OBJECT(in))
4799  ereport(ERROR,
4800  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4801  errmsg("cannot delete from object using integer index")));
4802 
4803  if (JB_ROOT_COUNT(in) == 0)
4804  PG_RETURN_JSONB_P(in);
4805 
4806  it = JsonbIteratorInit(&in->root);
4807 
4808  r = JsonbIteratorNext(&it, &v, false);
4809  Assert(r == WJB_BEGIN_ARRAY);
4810  n = v.val.array.nElems;
4811 
4812  if (idx < 0)
4813  {
4814  if (pg_abs_s32(idx) > n)
4815  idx = n;
4816  else
4817  idx = n + idx;
4818  }
4819 
4820  if (idx >= n)
4821  PG_RETURN_JSONB_P(in);
4822 
4823  pushJsonbValue(&state, r, NULL);
4824 
4825  while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
4826  {
4827  if (r == WJB_ELEM)
4828  {
4829  if (i++ == idx)
4830  continue;
4831  }
4832 
4833  res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4834  }
4835 
4836  Assert(res != NULL);
4837 
4839 }
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_abs_s32(), 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 4961 of file jsonfuncs.c.

4962 {
4963  Jsonb *in = PG_GETARG_JSONB_P(0);
4964  ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
4965  JsonbValue *res = NULL;
4966  Datum *path_elems;
4967  bool *path_nulls;
4968  int path_len;
4969  JsonbIterator *it;
4970  JsonbParseState *st = NULL;
4971 
4972  if (ARR_NDIM(path) > 1)
4973  ereport(ERROR,
4974  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4975  errmsg("wrong number of array subscripts")));
4976 
4977  if (JB_ROOT_IS_SCALAR(in))
4978  ereport(ERROR,
4979  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4980  errmsg("cannot delete path in scalar")));
4981 
4982  if (JB_ROOT_COUNT(in) == 0)
4983  PG_RETURN_JSONB_P(in);
4984 
4985  deconstruct_array_builtin(path, TEXTOID, &path_elems, &path_nulls, &path_len);
4986 
4987  if (path_len == 0)
4988  PG_RETURN_JSONB_P(in);
4989 
4990  it = JsonbIteratorInit(&in->root);
4991 
4992  res = setPath(&it, path_elems, path_nulls, path_len, &st,
4993  0, NULL, JB_PATH_DELETE);
4994 
4995  Assert(res != NULL);
4996 
4998 }
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:5181
#define JB_PATH_DELETE
Definition: jsonfuncs.c:45

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

Referenced by jsonb_set_lax().

◆ jsonb_each()

Datum jsonb_each ( PG_FUNCTION_ARGS  )

Definition at line 1955 of file jsonfuncs.c.

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

References each_worker_jsonb().

◆ jsonb_each_text()

Datum jsonb_each_text ( PG_FUNCTION_ARGS  )

Definition at line 1967 of file jsonfuncs.c.

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

References each_worker_jsonb().

◆ jsonb_extract_path()

Datum jsonb_extract_path ( PG_FUNCTION_ARGS  )

Definition at line 1487 of file jsonfuncs.c.

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

References get_jsonb_path_all().

◆ jsonb_extract_path_text()

Datum jsonb_extract_path_text ( PG_FUNCTION_ARGS  )

Definition at line 1493 of file jsonfuncs.c.

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

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

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

5005 {
5006  Jsonb *in = PG_GETARG_JSONB_P(0);
5007  ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
5008  Jsonb *newjsonb = PG_GETARG_JSONB_P(2);
5010  bool after = PG_GETARG_BOOL(3);
5011  JsonbValue *res = NULL;
5012  Datum *path_elems;
5013  bool *path_nulls;
5014  int path_len;
5015  JsonbIterator *it;
5016  JsonbParseState *st = NULL;
5017 
5018  JsonbToJsonbValue(newjsonb, &newval);
5019 
5020  if (ARR_NDIM(path) > 1)
5021  ereport(ERROR,
5022  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
5023  errmsg("wrong number of array subscripts")));
5024 
5025  if (JB_ROOT_IS_SCALAR(in))
5026  ereport(ERROR,
5027  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5028  errmsg("cannot set path in scalar")));
5029 
5030  deconstruct_array_builtin(path, TEXTOID, &path_elems, &path_nulls, &path_len);
5031 
5032  if (path_len == 0)
5033  PG_RETURN_JSONB_P(in);
5034 
5035  it = JsonbIteratorInit(&in->root);
5036 
5037  res = setPath(&it, path_elems, path_nulls, path_len, &st, 0, &newval,
5039 
5040  Assert(res != NULL);
5041 
5043 }
#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:47
#define JB_PATH_INSERT_AFTER
Definition: jsonfuncs.c:48

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

◆ jsonb_object_field()

Datum jsonb_object_field ( PG_FUNCTION_ARGS  )

Definition at line 861 of file jsonfuncs.c.

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

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

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

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

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

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

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

References populate_record_worker().

◆ jsonb_populate_record_valid()

Datum jsonb_populate_record_valid ( PG_FUNCTION_ARGS  )

Definition at line 2476 of file jsonfuncs.c.

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

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

References populate_recordset_worker().

◆ jsonb_pretty()

Datum jsonb_pretty ( PG_FUNCTION_ARGS  )

Definition at line 4584 of file jsonfuncs.c.

4585 {
4586  Jsonb *jb = PG_GETARG_JSONB_P(0);
4588 
4589  JsonbToCStringIndent(str, &jb->root, VARSIZE(jb));
4590 
4592 }
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 4845 of file jsonfuncs.c.

4846 {
4847  Jsonb *in = PG_GETARG_JSONB_P(0);
4848  ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
4849  Jsonb *newjsonb = PG_GETARG_JSONB_P(2);
4851  bool create = PG_GETARG_BOOL(3);
4852  JsonbValue *res = NULL;
4853  Datum *path_elems;
4854  bool *path_nulls;
4855  int path_len;
4856  JsonbIterator *it;
4857  JsonbParseState *st = NULL;
4858 
4859  JsonbToJsonbValue(newjsonb, &newval);
4860 
4861  if (ARR_NDIM(path) > 1)
4862  ereport(ERROR,
4863  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4864  errmsg("wrong number of array subscripts")));
4865 
4866  if (JB_ROOT_IS_SCALAR(in))
4867  ereport(ERROR,
4868  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4869  errmsg("cannot set path in scalar")));
4870 
4871  if (JB_ROOT_COUNT(in) == 0 && !create)
4872  PG_RETURN_JSONB_P(in);
4873 
4874  deconstruct_array_builtin(path, TEXTOID, &path_elems, &path_nulls, &path_len);
4875 
4876  if (path_len == 0)
4877  PG_RETURN_JSONB_P(in);
4878 
4879  it = JsonbIteratorInit(&in->root);
4880 
4881  res = setPath(&it, path_elems, path_nulls, path_len, &st,
4882  0, &newval, create ? JB_PATH_CREATE : JB_PATH_REPLACE);
4883 
4884  Assert(res != NULL);
4885 
4887 }
#define JB_PATH_CREATE
Definition: jsonfuncs.c:44
#define JB_PATH_REPLACE
Definition: jsonfuncs.c:46

References ARR_NDIM, Assert, deconstruct_array_builtin(), ereport, errcode(), errmsg(), ERROR, JB_PATH_CREATE, JB_PATH_REPLACE, JB_ROOT_COUNT, JB_ROOT_IS_SCALAR, JsonbIteratorInit(), JsonbToJsonbValue(), JsonbValueToJsonb(), newval, PG_GETARG_ARRAYTYPE_P, PG_GETARG_BOOL, PG_GETARG_JSONB_P, PG_RETURN_JSONB_P, 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 1678 of file jsonfuncs.c.

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

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

Referenced by jsonb_subscript_assign().

◆ jsonb_set_lax()

Datum jsonb_set_lax ( PG_FUNCTION_ARGS  )

Definition at line 4894 of file jsonfuncs.c.

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

4527 {
4528  Jsonb *jb = PG_GETARG_JSONB_P(0);
4529  JsonbIterator *it;
4530  JsonbParseState *parseState = NULL;
4531  JsonbValue *res = NULL;
4532  JsonbValue v,
4533  k;
4535  bool last_was_key = false;
4536 
4537  if (JB_ROOT_IS_SCALAR(jb))
4538  PG_RETURN_POINTER(jb);
4539 
4540  it = JsonbIteratorInit(&jb->root);
4541 
4542  while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
4543  {
4544  Assert(!(type == WJB_KEY && last_was_key));
4545 
4546  if (type == WJB_KEY)
4547  {
4548  /* stash the key until we know if it has a null value */
4549  k = v;
4550  last_was_key = true;
4551  continue;
4552  }
4553 
4554  if (last_was_key)
4555  {
4556  /* if the last element was a key this one can't be */
4557  last_was_key = false;
4558 
4559  /* skip this field if value is null */
4560  if (type == WJB_VALUE && v.type == jbvNull)
4561  continue;
4562 
4563  /* otherwise, do a delayed push of the key */
4564  (void) pushJsonbValue(&parseState, WJB_KEY, &k);
4565  }
4566 
4567  if (type == WJB_VALUE || type == WJB_ELEM)
4568  res = pushJsonbValue(&parseState, type, &v);
4569  else
4570  res = pushJsonbValue(&parseState, type, NULL);
4571  }
4572 
4573  Assert(res != NULL);
4574 
4576 }
#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 2487 of file jsonfuncs.c.

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

References populate_record_worker().

◆ jsonb_to_recordset()

Datum jsonb_to_recordset ( PG_FUNCTION_ARGS  )

Definition at line 3980 of file jsonfuncs.c.

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

References populate_recordset_worker().

◆ JsonbValueAsText()

static text * JsonbValueAsText ( JsonbValue v)
static

Definition at line 1804 of file jsonfuncs.c.

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

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

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

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

540 {
541  /*
542  * Most callers pass a detoasted datum, but it's not clear that they all
543  * do. pg_detoast_datum_packed() is cheap insurance.
544  */
545  json = pg_detoast_datum_packed(json);
546 
547  return makeJsonLexContextCstringLen(lex,
548  VARDATA_ANY(json),
549  VARSIZE_ANY_EXHDR(json),
551  need_escapes);
552 }
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 808 of file jsonfuncs.c.

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

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

Referenced by json_object_keys().

◆ okeys_object_field_start()

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

Definition at line 785 of file jsonfuncs.c.

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

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

Referenced by json_object_keys().

◆ okeys_scalar()

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

Definition at line 823 of file jsonfuncs.c.

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

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

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

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

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

◆ pg_parse_json_or_errsave()

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

Definition at line 518 of file jsonfuncs.c.

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

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

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

References PopulateArrayContext::acxt, PopulateArrayContext::aio, Assert, PopulateArrayContext::astate, PopulateArrayContext::colname, CurrentMemoryContext, PopulateArrayContext::dims, ArrayIOData::element_type, PopulateArrayContext::escontext, i, initArrayResult(), JsValue::is_json, JsValue::json, JsValue::jsonb, 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 2667 of file jsonfuncs.c.

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

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

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

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

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

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

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

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

2618 {
2619  Datum element;
2620  bool element_isnull;
2621 
2622  /* populate the array element */
2624  ctx->aio->element_type,
2625  ctx->aio->element_typmod,
2626  NULL, ctx->mcxt, PointerGetDatum(NULL),
2627  jsv, &element_isnull, ctx->escontext,
2628  false);
2629  /* Nothing to do on an error. */
2630  if (SOFT_ERROR_OCCURRED(ctx->escontext))
2631  return false;
2632 
2633  accumArrayResult(ctx->astate, element, element_isnull,
2634  ctx->aio->element_type, ctx->acxt);
2635 
2636  Assert(ndim > 0);
2637  ctx->sizes[ndim - 1]++; /* increment current dimension counter */
2638 
2639  return true;
2640 }
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5350
int32 element_typmod
Definition: jsonfuncs.c:170
ColumnIOData * element_info
Definition: jsonfuncs.c:168

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

Referenced by populate_array_dim_jsonb(), and populate_array_element_end().

◆ populate_array_element_end()

static JsonParseErrorType populate_array_element_end ( void *  _state,
bool  isnull 
)
static

Definition at line 2709 of file jsonfuncs.c.

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

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

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

References JSON_SUCCESS.

Referenced by populate_array_json().

◆ populate_array_json()

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

Definition at line 2788 of file jsonfuncs.c.

2789 {
2792 
2793  state.lex = makeJsonLexContextCstringLen(NULL, json, len,
2794  GetDatabaseEncoding(), true);
2795  state.ctx = ctx;
2796 
2797  memset(&sem, 0, sizeof(sem));
2798  sem.semstate = (void *) &state;
2804 
2805  if (pg_parse_json_or_errsave(state.lex, &sem, ctx->escontext))
2806  {
2807  /* number of dimensions should be already known */
2808  Assert(ctx->ndims > 0 && ctx->dims);
2809  }
2810 
2812 
2813  return !SOFT_ERROR_OCCURRED(ctx->escontext);
2814 }
static JsonParseErrorType populate_array_scalar(void *_state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:2752
static JsonParseErrorType populate_array_object_start(void *_state)
Definition: jsonfuncs.c:2644
static JsonParseErrorType populate_array_element_end(void *_state, bool isnull)
Definition: jsonfuncs.c:2709
static JsonParseErrorType populate_array_element_start(void *_state, bool isnull)
Definition: jsonfuncs.c:2691
static JsonParseErrorType populate_array_array_end(void *_state)
Definition: jsonfuncs.c:2667

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

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

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

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

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

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

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

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

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

Referenced by populate_record_field(), and populate_record_worker().

◆ populate_domain()

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

Definition at line 3216 of file jsonfuncs.c.

3224 {
3225  Datum res;
3226 
3227  if (*isnull)
3228  res = (Datum) 0;
3229  else
3230  {
3232  io->base_typid, io->base_typmod,
3233  colname, mcxt, PointerGetDatum(NULL),
3234  jsv, isnull, escontext, omit_quotes);
3235  Assert(!*isnull || SOFT_ERROR_OCCURRED(escontext));
3236  }
3237 
3238  if (!domain_check_safe(res, *isnull, typid, &io->domain_info, mcxt,
3239  escontext))
3240  {
3241  *isnull = true;
3242  return (Datum) 0;
3243  }
3244 
3245  return res;
3246 }
void * domain_info
Definition: jsonfuncs.c:195
int32 base_typmod
Definition: jsonfuncs.c:194
Oid base_typid
Definition: jsonfuncs.c:193
ColumnIOData * base_io
Definition: jsonfuncs.c:192

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

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

Definition at line 3405 of file jsonfuncs.c.

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

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

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

◆ populate_record_worker()

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

Definition at line 3698 of file jsonfuncs.c.

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

4268 {
4270 
4271  if (_state->lex->lex_level == 1 &&
4273  ereport(ERROR,
4274  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4275  errmsg("argument of %s must be an array of objects",
4276  _state->function_name)));
4277 
4278  return JSON_SUCCESS;
4279 }
JsonLexContext * lex
Definition: jsonfuncs.c:247
const char * function_name
Definition: jsonfuncs.c:248

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

Referenced by populate_recordset_worker().

◆ populate_recordset_array_start()

static JsonParseErrorType populate_recordset_array_start ( void *  state)
static

Definition at line 4282 of file jsonfuncs.c.

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

References JSON_SUCCESS.

Referenced by populate_recordset_worker().

◆ populate_recordset_object_end()

static JsonParseErrorType populate_recordset_object_end ( void *  state)
static

Definition at line 4244 of file jsonfuncs.c.

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

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

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

References Assert, HASH_ENTER, hash_search(), PopulateRecordsetState::json_hash, JSON_SUCCESS, JSON_TOKEN_NULL, len, PopulateRecordsetState::lex, JsonLexContext::lex_level, NAMEDATALEN, palloc(), JsonLexContext::prev_token_terminator, PopulateRecordsetState::save_json_start, PopulateRecordsetState::saved_scalar, PopulateRecordsetState::saved_token_type, JsonHashEntry::type, JsonHashEntry::val, and val.

Referenced by populate_recordset_worker().

◆ populate_recordset_object_field_start()

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

Definition at line 4306 of file jsonfuncs.c.

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

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

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

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

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

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

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

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

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

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

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

◆ populate_scalar()

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

Definition at line 3124 of file jsonfuncs.c.

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

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

Referenced by populate_record_field().

◆ prepare_column_cache()

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

Definition at line 3250 of file jsonfuncs.c.

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

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

Referenced by get_record_type_from_argument(), and populate_record_field().

◆ push_null_elements()

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

Definition at line 1701 of file jsonfuncs.c.

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

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

Referenced by push_path(), and setPathArray().

◆ push_path()

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

Definition at line 1720 of file jsonfuncs.c.

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

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

Referenced by setPathArray(), and setPathObject().

◆ report_json_context()

static int report_json_context ( JsonLexContext lex)
static

Definition at line 676 of file jsonfuncs.c.

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

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

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

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

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

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

Referenced by setPath().

◆ setPathObject()

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

Definition at line 5263 of file jsonfuncs.c.

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

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

4460 {
4461  StripnullState *_state = (StripnullState *) state;
4462 
4463  if (_state->strval->data[_state->strval->len - 1] != '[')
4464  appendStringInfoCharMacro(_state->strval, ',');
4465 
4466  return JSON_SUCCESS;
4467 }
#define appendStringInfoCharMacro(str, ch)
Definition: stringinfo.h:204
StringInfo strval
Definition: jsonfuncs.c:287

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

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

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

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

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

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

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

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

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

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

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

4471 {
4472  StripnullState *_state = (StripnullState *) state;
4473 
4474  if (_state->skip_next_null)
4475  {
4476  Assert(tokentype == JSON_TOKEN_NULL);
4477  _state->skip_next_null = false;
4478  return JSON_SUCCESS;
4479  }
4480 
4481  if (tokentype == JSON_TOKEN_STRING)
4482  escape_json(_state->strval, token);
4483  else
4485 
4486  return JSON_SUCCESS;
4487 }
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:179

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

5832 {
5833  JsonLexContext lex;
5834  JsonSemAction *sem = palloc0(sizeof(JsonSemAction));
5836 
5837  state->lex = makeJsonLexContext(&lex, json, true);
5838  state->strval = makeStringInfo();
5839  state->action = transform_action;
5840  state->action_state = action_state;
5841 
5842  sem->semstate = (void *) state;
5850 
5852  freeJsonLexContext(&lex);
5853 
5854  return cstring_to_text_with_len(state->strval->data, state->strval->len);
5855 }
static JsonParseErrorType transform_string_values_array_start(void *state)
Definition: jsonfuncs.c:5883
static JsonParseErrorType transform_string_values_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:5903
static JsonParseErrorType transform_string_values_array_end(void *state)
Definition: jsonfuncs.c:5893
static JsonParseErrorType transform_string_values_object_end(void *state)
Definition: jsonfuncs.c:5873
static JsonParseErrorType transform_string_values_object_start(void *state)
Definition: jsonfuncs.c:5863
static JsonParseErrorType transform_string_values_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:5921
static JsonParseErrorType transform_string_values_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:5932

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

5785 {
5786  JsonbIterator *it;
5787  JsonbValue v,
5788  *res = NULL;
5790  JsonbParseState *st = NULL;
5791  text *out;
5792  bool is_scalar = false;
5793 
5794  it = JsonbIteratorInit(&jsonb->root);
5795  is_scalar = it->isScalar;
5796 
5797  while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
5798  {
5799  if ((type == WJB_VALUE || type == WJB_ELEM) && v.type == jbvString)
5800  {
5801  out = transform_action(action_state, v.val.string.val, v.val.string.len);
5802  /* out is probably not toasted, but let's be sure */
5803  out = pg_detoast_datum_packed(out);
5804  v.val.string.val = VARDATA_ANY(out);
5805  v.val.string.len = VARSIZE_ANY_EXHDR(out);
5806  res = pushJsonbValue(&st, type, type < WJB_BEGIN_ARRAY ? &v : NULL);
5807  }
5808  else
5809  {
5810  res = pushJsonbValue(&st, type, (type == WJB_KEY ||
5811  type == WJB_VALUE ||
5812  type == WJB_ELEM) ? &v : NULL);
5813  }
5814  }
5815 
5816  if (res->type == jbvArray)
5817  res->val.array.rawScalar = is_scalar;
5818 
5819  return JsonbValueToJsonb(res);
5820 }
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 5921 of file jsonfuncs.c.

5922 {
5924 
5925  if (_state->strval->data[_state->strval->len - 1] != '[')
5926  appendStringInfoCharMacro(_state->strval, ',');
5927 
5928  return JSON_SUCCESS;
5929 }

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

5894 {
5896 
5897  appendStringInfoCharMacro(_state->strval, ']');
5898 
5899  return JSON_SUCCESS;
5900 }

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

5884 {
5886 
5887  appendStringInfoCharMacro(_state->strval, '[');
5888 
5889  return JSON_SUCCESS;
5890 }

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

5874 {
5876 
5877  appendStringInfoCharMacro(_state->strval, '}');
5878 
5879  return JSON_SUCCESS;
5880 }

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

5904 {
5906 
5907  if (_state->strval->data[_state->strval->len - 1] != '{')
5908  appendStringInfoCharMacro(_state->strval, ',');
5909 
5910  /*
5911  * Unfortunately we don't have the quoted and escaped string any more, so
5912  * we have to re-escape it.
5913  */
5914  escape_json(_state->strval, fname);
5915  appendStringInfoCharMacro(_state->strval, ':');
5916 
5917  return JSON_SUCCESS;
5918 }

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

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

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

5933 {
5935 
5936  if (tokentype == JSON_TOKEN_STRING)
5937  {
5938  text *out = _state->action(_state->action_state, token, strlen(token));
5939 
5940  escape_json_text(_state->strval, out);
5941  }
5942  else
5944 
5945  return JSON_SUCCESS;
5946 }
void escape_json_text(StringInfo buf, const text *txt)
Definition: json.c:1736
JsonTransformStringValuesAction action
Definition: jsonfuncs.c:80

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

Referenced by transform_json_string_values().

◆ update_cached_tupdesc()

static void update_cached_tupdesc ( CompositeIOData io,
MemoryContext  mcxt 
)
static

Definition at line 3028 of file jsonfuncs.c.

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

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