2013-03-29 19:12:13 +01:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* jsonfuncs.c
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
* Functions to process JSON data types.
|
2013-03-29 19:12:13 +01:00
|
|
|
*
|
2016-01-02 19:33:40 +01:00
|
|
|
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
|
2013-03-29 19:12:13 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
|
|
|
* src/backend/utils/adt/jsonfuncs.c
|
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "postgres.h"
|
|
|
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
|
|
|
#include "access/htup_details.h"
|
|
|
|
#include "catalog/pg_type.h"
|
2014-06-25 20:22:18 +02:00
|
|
|
#include "fmgr.h"
|
|
|
|
#include "funcapi.h"
|
2013-03-29 19:12:13 +01:00
|
|
|
#include "lib/stringinfo.h"
|
|
|
|
#include "mb/pg_wchar.h"
|
2014-06-25 20:22:18 +02:00
|
|
|
#include "miscadmin.h"
|
2013-03-29 19:12:13 +01:00
|
|
|
#include "utils/array.h"
|
|
|
|
#include "utils/builtins.h"
|
|
|
|
#include "utils/hsearch.h"
|
|
|
|
#include "utils/json.h"
|
|
|
|
#include "utils/jsonapi.h"
|
2014-06-25 20:22:18 +02:00
|
|
|
#include "utils/jsonb.h"
|
2013-03-29 19:12:13 +01:00
|
|
|
#include "utils/lsyscache.h"
|
|
|
|
#include "utils/memutils.h"
|
|
|
|
#include "utils/typcache.h"
|
|
|
|
|
2016-04-06 18:20:17 +02:00
|
|
|
/* Operations available for setPath */
|
|
|
|
#define JB_PATH_CREATE 0x0001
|
|
|
|
#define JB_PATH_DELETE 0x0002
|
2016-10-13 06:25:28 +02:00
|
|
|
#define JB_PATH_REPLACE 0x0004
|
|
|
|
#define JB_PATH_INSERT_BEFORE 0x0008
|
|
|
|
#define JB_PATH_INSERT_AFTER 0x0010
|
2016-04-06 18:20:17 +02:00
|
|
|
#define JB_PATH_CREATE_OR_INSERT \
|
|
|
|
(JB_PATH_INSERT_BEFORE | JB_PATH_INSERT_AFTER | JB_PATH_CREATE)
|
|
|
|
|
2013-03-29 19:12:13 +01:00
|
|
|
/* semantic action functions for json_object_keys */
|
|
|
|
static void okeys_object_field_start(void *state, char *fname, bool isnull);
|
|
|
|
static void okeys_array_start(void *state);
|
|
|
|
static void okeys_scalar(void *state, char *token, JsonTokenType tokentype);
|
|
|
|
|
|
|
|
/* semantic action functions for json_get* functions */
|
|
|
|
static void get_object_start(void *state);
|
2014-08-22 19:17:58 +02:00
|
|
|
static void get_object_end(void *state);
|
2013-03-29 19:12:13 +01:00
|
|
|
static void get_object_field_start(void *state, char *fname, bool isnull);
|
|
|
|
static void get_object_field_end(void *state, char *fname, bool isnull);
|
|
|
|
static void get_array_start(void *state);
|
2014-08-22 19:17:58 +02:00
|
|
|
static void get_array_end(void *state);
|
2013-03-29 19:12:13 +01:00
|
|
|
static void get_array_element_start(void *state, bool isnull);
|
|
|
|
static void get_array_element_end(void *state, bool isnull);
|
|
|
|
static void get_scalar(void *state, char *token, JsonTokenType tokentype);
|
|
|
|
|
|
|
|
/* common worker function for json getter functions */
|
2014-08-22 19:17:58 +02:00
|
|
|
static Datum get_path_all(FunctionCallInfo fcinfo, bool as_text);
|
|
|
|
static text *get_worker(text *json, char **tpath, int *ipath, int npath,
|
2013-03-29 19:12:13 +01:00
|
|
|
bool normalize_results);
|
2014-08-22 19:17:58 +02:00
|
|
|
static Datum get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* semantic action functions for json_array_length */
|
|
|
|
static void alen_object_start(void *state);
|
|
|
|
static void alen_scalar(void *state, char *token, JsonTokenType tokentype);
|
|
|
|
static void alen_array_element_start(void *state, bool isnull);
|
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
/* common workers for json{b}_each* functions */
|
2014-06-25 20:22:18 +02:00
|
|
|
static Datum each_worker(FunctionCallInfo fcinfo, bool as_text);
|
2014-06-26 00:25:22 +02:00
|
|
|
static Datum each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname,
|
|
|
|
bool as_text);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* semantic action functions for json_each */
|
|
|
|
static void each_object_field_start(void *state, char *fname, bool isnull);
|
|
|
|
static void each_object_field_end(void *state, char *fname, bool isnull);
|
|
|
|
static void each_array_start(void *state);
|
|
|
|
static void each_scalar(void *state, char *token, JsonTokenType tokentype);
|
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
/* common workers for json{b}_array_elements_* functions */
|
2014-06-26 00:25:22 +02:00
|
|
|
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);
|
2014-01-29 21:39:01 +01:00
|
|
|
|
2013-03-29 19:12:13 +01:00
|
|
|
/* semantic action functions for json_array_elements */
|
|
|
|
static void elements_object_start(void *state);
|
|
|
|
static void elements_array_element_start(void *state, bool isnull);
|
|
|
|
static void elements_array_element_end(void *state, bool isnull);
|
|
|
|
static void elements_scalar(void *state, char *token, JsonTokenType tokentype);
|
|
|
|
|
|
|
|
/* turn a json object into a hash table */
|
2014-06-29 19:50:58 +02:00
|
|
|
static HTAB *get_json_object_as_hash(text *json, const char *funcname);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
2014-01-28 23:48:21 +01:00
|
|
|
/* common worker for populate_record and to_record */
|
2014-06-26 00:25:22 +02:00
|
|
|
static Datum populate_record_worker(FunctionCallInfo fcinfo, const char *funcname,
|
2014-01-28 23:48:21 +01:00
|
|
|
bool have_record_arg);
|
|
|
|
|
2013-03-29 19:12:13 +01:00
|
|
|
/* semantic action functions for get_json_object_as_hash */
|
|
|
|
static void hash_object_field_start(void *state, char *fname, bool isnull);
|
|
|
|
static void hash_object_field_end(void *state, char *fname, bool isnull);
|
|
|
|
static void hash_array_start(void *state);
|
|
|
|
static void hash_scalar(void *state, char *token, JsonTokenType tokentype);
|
|
|
|
|
|
|
|
/* semantic action functions for populate_recordset */
|
|
|
|
static void populate_recordset_object_field_start(void *state, char *fname, bool isnull);
|
|
|
|
static void populate_recordset_object_field_end(void *state, char *fname, bool isnull);
|
|
|
|
static void populate_recordset_scalar(void *state, char *token, JsonTokenType tokentype);
|
|
|
|
static void populate_recordset_object_start(void *state);
|
|
|
|
static void populate_recordset_object_end(void *state);
|
|
|
|
static void populate_recordset_array_start(void *state);
|
|
|
|
static void populate_recordset_array_element_start(void *state, bool isnull);
|
|
|
|
|
2014-12-12 15:00:43 +01:00
|
|
|
/* semantic action functions for json_strip_nulls */
|
|
|
|
static void sn_object_start(void *state);
|
|
|
|
static void sn_object_end(void *state);
|
|
|
|
static void sn_array_start(void *state);
|
|
|
|
static void sn_array_end(void *state);
|
2015-05-24 03:35:49 +02:00
|
|
|
static void sn_object_field_start(void *state, char *fname, bool isnull);
|
|
|
|
static void sn_array_element_start(void *state, bool isnull);
|
2014-12-12 15:00:43 +01:00
|
|
|
static void sn_scalar(void *state, char *token, JsonTokenType tokentype);
|
|
|
|
|
2014-01-28 23:48:21 +01:00
|
|
|
/* worker function for populate_recordset and to_recordset */
|
2014-06-26 00:25:22 +02:00
|
|
|
static Datum populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname,
|
2014-01-28 23:48:21 +01:00
|
|
|
bool have_record_arg);
|
2014-05-06 18:12:18 +02:00
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
/* Worker that takes care of common setup for us */
|
2014-05-07 22:16:19 +02:00
|
|
|
static JsonbValue *findJsonbValueFromContainerLen(JsonbContainer *container,
|
2014-06-25 20:22:18 +02:00
|
|
|
uint32 flags,
|
|
|
|
char *key,
|
|
|
|
uint32 keylen);
|
2014-01-28 23:48:21 +01:00
|
|
|
|
2015-06-01 02:34:10 +02:00
|
|
|
/* functions supporting jsonb_delete, jsonb_set and jsonb_concat */
|
2015-05-12 21:52:45 +02:00
|
|
|
static JsonbValue *IteratorConcat(JsonbIterator **it1, JsonbIterator **it2,
|
2015-05-24 03:35:49 +02:00
|
|
|
JsonbParseState **state);
|
2015-06-01 02:34:10 +02:00
|
|
|
static JsonbValue *setPath(JsonbIterator **it, Datum *path_elems,
|
|
|
|
bool *path_nulls, int path_len,
|
|
|
|
JsonbParseState **st, int level, Jsonb *newval,
|
2016-04-06 18:20:17 +02:00
|
|
|
int op_type);
|
2015-06-01 02:34:10 +02:00
|
|
|
static void setPathObject(JsonbIterator **it, Datum *path_elems,
|
|
|
|
bool *path_nulls, int path_len, JsonbParseState **st,
|
|
|
|
int level,
|
2016-04-06 18:20:17 +02:00
|
|
|
Jsonb *newval, uint32 npairs, int op_type);
|
2015-06-01 02:34:10 +02:00
|
|
|
static void setPathArray(JsonbIterator **it, Datum *path_elems,
|
|
|
|
bool *path_nulls, int path_len, JsonbParseState **st,
|
2016-04-06 18:20:17 +02:00
|
|
|
int level, Jsonb *newval, uint32 nelems, int op_type);
|
2015-05-24 03:35:49 +02:00
|
|
|
static void addJsonbToParseState(JsonbParseState **jbps, Jsonb *jb);
|
2015-05-12 21:52:45 +02:00
|
|
|
|
2013-03-29 19:12:13 +01:00
|
|
|
/* state for json_object_keys */
|
2013-07-20 12:38:31 +02:00
|
|
|
typedef struct OkeysState
|
2013-03-29 19:12:13 +01:00
|
|
|
{
|
|
|
|
JsonLexContext *lex;
|
|
|
|
char **result;
|
|
|
|
int result_size;
|
|
|
|
int result_count;
|
|
|
|
int sent_count;
|
2014-01-22 14:46:51 +01:00
|
|
|
} OkeysState;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* state for json_get* functions */
|
2013-07-20 12:38:31 +02:00
|
|
|
typedef struct GetState
|
2013-03-29 19:12:13 +01:00
|
|
|
{
|
|
|
|
JsonLexContext *lex;
|
|
|
|
text *tresult;
|
2014-08-22 19:17:58 +02:00
|
|
|
char *result_start;
|
2013-03-29 19:12:13 +01:00
|
|
|
bool normalize_results;
|
|
|
|
bool next_scalar;
|
2014-08-22 19:17:58 +02:00
|
|
|
int npath; /* length of each path-related array */
|
|
|
|
char **path_names; /* field name(s) being sought */
|
|
|
|
int *path_indexes; /* array index(es) being sought */
|
|
|
|
bool *pathok; /* is path matched to current depth? */
|
|
|
|
int *array_cur_index; /* current element index at each path level */
|
2014-01-22 14:46:51 +01:00
|
|
|
} GetState;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* state for json_array_length */
|
2013-07-20 12:38:31 +02:00
|
|
|
typedef struct AlenState
|
2013-03-29 19:12:13 +01:00
|
|
|
{
|
|
|
|
JsonLexContext *lex;
|
|
|
|
int count;
|
2014-01-22 14:46:51 +01:00
|
|
|
} AlenState;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* state for json_each */
|
2013-07-20 12:38:31 +02:00
|
|
|
typedef struct EachState
|
2013-03-29 19:12:13 +01:00
|
|
|
{
|
|
|
|
JsonLexContext *lex;
|
|
|
|
Tuplestorestate *tuple_store;
|
|
|
|
TupleDesc ret_tdesc;
|
|
|
|
MemoryContext tmp_cxt;
|
|
|
|
char *result_start;
|
|
|
|
bool normalize_results;
|
|
|
|
bool next_scalar;
|
|
|
|
char *normalized_scalar;
|
2014-01-22 14:46:51 +01:00
|
|
|
} EachState;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* state for json_array_elements */
|
2013-07-20 12:38:31 +02:00
|
|
|
typedef struct ElementsState
|
2013-03-29 19:12:13 +01:00
|
|
|
{
|
|
|
|
JsonLexContext *lex;
|
2014-06-26 00:25:22 +02:00
|
|
|
const char *function_name;
|
2013-03-29 19:12:13 +01:00
|
|
|
Tuplestorestate *tuple_store;
|
|
|
|
TupleDesc ret_tdesc;
|
|
|
|
MemoryContext tmp_cxt;
|
|
|
|
char *result_start;
|
2014-01-29 21:39:01 +01:00
|
|
|
bool normalize_results;
|
|
|
|
bool next_scalar;
|
|
|
|
char *normalized_scalar;
|
2014-01-22 14:46:51 +01:00
|
|
|
} ElementsState;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* state for get_json_object_as_hash */
|
2013-07-20 12:38:31 +02:00
|
|
|
typedef struct JhashState
|
2013-03-29 19:12:13 +01:00
|
|
|
{
|
|
|
|
JsonLexContext *lex;
|
2014-06-26 00:25:22 +02:00
|
|
|
const char *function_name;
|
2013-03-29 19:12:13 +01:00
|
|
|
HTAB *hash;
|
|
|
|
char *saved_scalar;
|
|
|
|
char *save_json_start;
|
2014-01-22 14:46:51 +01:00
|
|
|
} JHashState;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
2014-06-25 20:22:18 +02:00
|
|
|
/* hashtable element */
|
2013-07-20 12:38:31 +02:00
|
|
|
typedef struct JsonHashEntry
|
2013-03-29 19:12:13 +01:00
|
|
|
{
|
2014-06-25 20:22:18 +02:00
|
|
|
char fname[NAMEDATALEN]; /* hash key (MUST BE FIRST) */
|
2013-03-29 19:12:13 +01:00
|
|
|
char *val;
|
|
|
|
char *json;
|
|
|
|
bool isnull;
|
2014-01-22 14:46:51 +01:00
|
|
|
} JsonHashEntry;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* these two are stolen from hstore / record_out, used in populate_record* */
|
|
|
|
typedef struct ColumnIOData
|
|
|
|
{
|
|
|
|
Oid column_type;
|
|
|
|
Oid typiofunc;
|
|
|
|
Oid typioparam;
|
|
|
|
FmgrInfo proc;
|
|
|
|
} ColumnIOData;
|
|
|
|
|
|
|
|
typedef struct RecordIOData
|
|
|
|
{
|
|
|
|
Oid record_type;
|
|
|
|
int32 record_typmod;
|
|
|
|
int ncolumns;
|
2015-02-20 23:03:12 +01:00
|
|
|
ColumnIOData columns[FLEXIBLE_ARRAY_MEMBER];
|
2013-03-29 19:12:13 +01:00
|
|
|
} RecordIOData;
|
|
|
|
|
|
|
|
/* state for populate_recordset */
|
2013-07-20 12:38:31 +02:00
|
|
|
typedef struct PopulateRecordsetState
|
2013-03-29 19:12:13 +01:00
|
|
|
{
|
|
|
|
JsonLexContext *lex;
|
2014-06-26 00:25:22 +02:00
|
|
|
const char *function_name;
|
2013-03-29 19:12:13 +01:00
|
|
|
HTAB *json_hash;
|
|
|
|
char *saved_scalar;
|
|
|
|
char *save_json_start;
|
|
|
|
Tuplestorestate *tuple_store;
|
|
|
|
TupleDesc ret_tdesc;
|
|
|
|
HeapTupleHeader rec;
|
|
|
|
RecordIOData *my_extra;
|
|
|
|
MemoryContext fn_mcxt; /* used to stash IO funcs */
|
2014-01-22 14:46:51 +01:00
|
|
|
} PopulateRecordsetState;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
2014-12-12 15:00:43 +01:00
|
|
|
/* state for json_strip_nulls */
|
2015-05-24 03:35:49 +02:00
|
|
|
typedef struct StripnullState
|
|
|
|
{
|
2014-12-12 15:00:43 +01:00
|
|
|
JsonLexContext *lex;
|
2015-05-24 03:35:49 +02:00
|
|
|
StringInfo strval;
|
|
|
|
bool skip_next_null;
|
2014-12-12 15:00:43 +01:00
|
|
|
} StripnullState;
|
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
/* Turn a jsonb object into a record */
|
2014-05-06 18:12:18 +02:00
|
|
|
static void make_row_from_rec_and_jsonb(Jsonb *element,
|
|
|
|
PopulateRecordsetState *state);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
2013-03-29 19:12:13 +01:00
|
|
|
/*
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
* SQL function json_object_keys
|
2013-03-29 19:12:13 +01:00
|
|
|
*
|
|
|
|
* Returns the set of keys for the object argument.
|
|
|
|
*
|
|
|
|
* This SRF operates in value-per-call mode. It processes the
|
|
|
|
* object during the first call, and the keys are simply stashed
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
* in an array, whose size is expanded as necessary. This is probably
|
2013-03-29 19:12:13 +01:00
|
|
|
* safe enough for a list of keys of a single object, since they are
|
|
|
|
* limited in size to NAMEDATALEN and the number of keys is unlikely to
|
|
|
|
* be so huge that it has major memory implications.
|
|
|
|
*/
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
Datum
|
|
|
|
jsonb_object_keys(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
FuncCallContext *funcctx;
|
|
|
|
OkeysState *state;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (SRF_IS_FIRSTCALL())
|
|
|
|
{
|
|
|
|
MemoryContext oldcontext;
|
|
|
|
Jsonb *jb = PG_GETARG_JSONB(0);
|
|
|
|
bool skipNested = false;
|
|
|
|
JsonbIterator *it;
|
|
|
|
JsonbValue v;
|
2015-10-12 05:53:35 +02:00
|
|
|
JsonbIteratorToken r;
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
|
|
|
if (JB_ROOT_IS_SCALAR(jb))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
2014-06-26 00:25:22 +02:00
|
|
|
errmsg("cannot call %s on a scalar",
|
|
|
|
"jsonb_object_keys")));
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
else if (JB_ROOT_IS_ARRAY(jb))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
2014-06-26 00:25:22 +02:00
|
|
|
errmsg("cannot call %s on an array",
|
|
|
|
"jsonb_object_keys")));
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
|
|
|
funcctx = SRF_FIRSTCALL_INIT();
|
|
|
|
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
|
|
|
|
|
|
|
state = palloc(sizeof(OkeysState));
|
|
|
|
|
|
|
|
state->result_size = JB_ROOT_COUNT(jb);
|
|
|
|
state->result_count = 0;
|
|
|
|
state->sent_count = 0;
|
|
|
|
state->result = palloc(state->result_size * sizeof(char *));
|
|
|
|
|
2014-05-07 22:16:19 +02:00
|
|
|
it = JsonbIteratorInit(&jb->root);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
|
|
|
while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
|
|
|
|
{
|
|
|
|
skipNested = true;
|
|
|
|
|
|
|
|
if (r == WJB_KEY)
|
|
|
|
{
|
|
|
|
char *cstr;
|
|
|
|
|
2014-04-02 20:30:08 +02:00
|
|
|
cstr = palloc(v.val.string.len + 1 * sizeof(char));
|
|
|
|
memcpy(cstr, v.val.string.val, v.val.string.len);
|
|
|
|
cstr[v.val.string.len] = '\0';
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
state->result[state->result_count++] = cstr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
funcctx->user_fctx = (void *) state;
|
|
|
|
}
|
|
|
|
|
|
|
|
funcctx = SRF_PERCALL_SETUP();
|
|
|
|
state = (OkeysState *) funcctx->user_fctx;
|
|
|
|
|
|
|
|
if (state->sent_count < state->result_count)
|
|
|
|
{
|
|
|
|
char *nxt = state->result[state->sent_count++];
|
|
|
|
|
|
|
|
SRF_RETURN_NEXT(funcctx, CStringGetTextDatum(nxt));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* cleanup to reduce or eliminate memory leaks */
|
|
|
|
for (i = 0; i < state->result_count; i++)
|
|
|
|
pfree(state->result[i]);
|
|
|
|
pfree(state->result);
|
|
|
|
pfree(state);
|
|
|
|
|
|
|
|
SRF_RETURN_DONE(funcctx);
|
|
|
|
}
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
json_object_keys(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
FuncCallContext *funcctx;
|
2013-07-20 12:38:31 +02:00
|
|
|
OkeysState *state;
|
2013-03-29 19:12:13 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (SRF_IS_FIRSTCALL())
|
|
|
|
{
|
|
|
|
text *json = PG_GETARG_TEXT_P(0);
|
|
|
|
JsonLexContext *lex = makeJsonLexContext(json, true);
|
2013-07-20 12:38:31 +02:00
|
|
|
JsonSemAction *sem;
|
2013-03-29 19:12:13 +01:00
|
|
|
MemoryContext oldcontext;
|
|
|
|
|
|
|
|
funcctx = SRF_FIRSTCALL_INIT();
|
|
|
|
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
|
|
|
|
2013-07-20 12:38:31 +02:00
|
|
|
state = palloc(sizeof(OkeysState));
|
|
|
|
sem = palloc0(sizeof(JsonSemAction));
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
state->lex = lex;
|
|
|
|
state->result_size = 256;
|
|
|
|
state->result_count = 0;
|
|
|
|
state->sent_count = 0;
|
|
|
|
state->result = palloc(256 * sizeof(char *));
|
|
|
|
|
|
|
|
sem->semstate = (void *) state;
|
|
|
|
sem->array_start = okeys_array_start;
|
|
|
|
sem->scalar = okeys_scalar;
|
|
|
|
sem->object_field_start = okeys_object_field_start;
|
|
|
|
/* remainder are all NULL, courtesy of palloc0 above */
|
|
|
|
|
|
|
|
pg_parse_json(lex, sem);
|
|
|
|
/* keys are now in state->result */
|
|
|
|
|
|
|
|
pfree(lex->strval->data);
|
|
|
|
pfree(lex->strval);
|
|
|
|
pfree(lex);
|
|
|
|
pfree(sem);
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
funcctx->user_fctx = (void *) state;
|
|
|
|
}
|
|
|
|
|
|
|
|
funcctx = SRF_PERCALL_SETUP();
|
2013-07-20 12:38:31 +02:00
|
|
|
state = (OkeysState *) funcctx->user_fctx;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
if (state->sent_count < state->result_count)
|
|
|
|
{
|
|
|
|
char *nxt = state->result[state->sent_count++];
|
|
|
|
|
|
|
|
SRF_RETURN_NEXT(funcctx, CStringGetTextDatum(nxt));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* cleanup to reduce or eliminate memory leaks */
|
|
|
|
for (i = 0; i < state->result_count; i++)
|
|
|
|
pfree(state->result[i]);
|
|
|
|
pfree(state->result);
|
|
|
|
pfree(state);
|
|
|
|
|
|
|
|
SRF_RETURN_DONE(funcctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
okeys_object_field_start(void *state, char *fname, bool isnull)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
OkeysState *_state = (OkeysState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* only collecting keys for the top level object */
|
|
|
|
if (_state->lex->lex_level != 1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* enlarge result array if necessary */
|
|
|
|
if (_state->result_count >= _state->result_size)
|
|
|
|
{
|
|
|
|
_state->result_size *= 2;
|
2014-06-25 20:22:18 +02:00
|
|
|
_state->result = (char **)
|
2013-03-29 19:12:13 +01:00
|
|
|
repalloc(_state->result, sizeof(char *) * _state->result_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* save a copy of the field name */
|
|
|
|
_state->result[_state->result_count++] = pstrdup(fname);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
okeys_array_start(void *state)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
OkeysState *_state = (OkeysState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* top level must be a json object */
|
|
|
|
if (_state->lex->lex_level == 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
2014-06-26 00:25:22 +02:00
|
|
|
errmsg("cannot call %s on an array",
|
|
|
|
"json_object_keys")));
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
okeys_scalar(void *state, char *token, JsonTokenType tokentype)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
OkeysState *_state = (OkeysState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* top level must be a json object */
|
|
|
|
if (_state->lex->lex_level == 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
2014-06-26 00:25:22 +02:00
|
|
|
errmsg("cannot call %s on a scalar",
|
|
|
|
"json_object_keys")));
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
* json and jsonb getter functions
|
2013-03-29 19:12:13 +01:00
|
|
|
* these implement the -> ->> #> and #>> operators
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
* and the json{b?}_extract_path*(json, text, ...) functions
|
2013-03-29 19:12:13 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
json_object_field(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
text *json = PG_GETARG_TEXT_P(0);
|
2014-08-22 19:17:58 +02:00
|
|
|
text *fname = PG_GETARG_TEXT_PP(1);
|
2013-03-29 19:12:13 +01:00
|
|
|
char *fnamestr = text_to_cstring(fname);
|
2014-06-25 20:22:18 +02:00
|
|
|
text *result;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
result = get_worker(json, &fnamestr, NULL, 1, false);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
if (result != NULL)
|
|
|
|
PG_RETURN_TEXT_P(result);
|
|
|
|
else
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
Datum
|
|
|
|
jsonb_object_field(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Jsonb *jb = PG_GETARG_JSONB(0);
|
2014-06-02 01:04:02 +02:00
|
|
|
text *key = PG_GETARG_TEXT_PP(1);
|
|
|
|
JsonbValue *v;
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
if (!JB_ROOT_IS_OBJECT(jb))
|
|
|
|
PG_RETURN_NULL();
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
2014-06-02 01:04:02 +02:00
|
|
|
v = findJsonbValueFromContainerLen(&jb->root, JB_FOBJECT,
|
2014-08-22 19:17:58 +02:00
|
|
|
VARDATA_ANY(key),
|
|
|
|
VARSIZE_ANY_EXHDR(key));
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
2014-06-02 01:04:02 +02:00
|
|
|
if (v != NULL)
|
|
|
|
PG_RETURN_JSONB(JsonbValueToJsonb(v));
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
2013-03-29 19:12:13 +01:00
|
|
|
Datum
|
|
|
|
json_object_field_text(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
text *json = PG_GETARG_TEXT_P(0);
|
2014-08-22 19:17:58 +02:00
|
|
|
text *fname = PG_GETARG_TEXT_PP(1);
|
2013-03-29 19:12:13 +01:00
|
|
|
char *fnamestr = text_to_cstring(fname);
|
2014-06-25 20:22:18 +02:00
|
|
|
text *result;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
result = get_worker(json, &fnamestr, NULL, 1, true);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
if (result != NULL)
|
|
|
|
PG_RETURN_TEXT_P(result);
|
|
|
|
else
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
Datum
|
|
|
|
jsonb_object_field_text(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Jsonb *jb = PG_GETARG_JSONB(0);
|
2014-06-02 01:04:02 +02:00
|
|
|
text *key = PG_GETARG_TEXT_PP(1);
|
|
|
|
JsonbValue *v;
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
if (!JB_ROOT_IS_OBJECT(jb))
|
|
|
|
PG_RETURN_NULL();
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
2014-06-02 01:04:02 +02:00
|
|
|
v = findJsonbValueFromContainerLen(&jb->root, JB_FOBJECT,
|
2014-08-22 19:17:58 +02:00
|
|
|
VARDATA_ANY(key),
|
|
|
|
VARSIZE_ANY_EXHDR(key));
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
2014-06-02 01:04:02 +02:00
|
|
|
if (v != NULL)
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
{
|
2014-06-02 01:04:02 +02:00
|
|
|
text *result = NULL;
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
2014-06-25 20:22:18 +02:00
|
|
|
switch (v->type)
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
{
|
2014-06-02 01:04:02 +02:00
|
|
|
case jbvNull:
|
|
|
|
break;
|
|
|
|
case jbvBool:
|
|
|
|
result = cstring_to_text(v->val.boolean ? "true" : "false");
|
|
|
|
break;
|
|
|
|
case jbvString:
|
|
|
|
result = cstring_to_text_with_len(v->val.string.val, v->val.string.len);
|
|
|
|
break;
|
|
|
|
case jbvNumeric:
|
|
|
|
result = cstring_to_text(DatumGetCString(DirectFunctionCall1(numeric_out,
|
2014-06-25 20:22:18 +02:00
|
|
|
PointerGetDatum(v->val.numeric))));
|
2014-06-02 01:04:02 +02:00
|
|
|
break;
|
|
|
|
case jbvBinary:
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
{
|
2014-06-25 20:22:18 +02:00
|
|
|
StringInfo jtext = makeStringInfo();
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
2014-06-02 01:04:02 +02:00
|
|
|
(void) JsonbToCString(jtext, v->val.binary.data, -1);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
result = cstring_to_text_with_len(jtext->data, jtext->len);
|
|
|
|
}
|
2014-06-02 01:04:02 +02:00
|
|
|
break;
|
|
|
|
default:
|
2014-06-26 00:25:22 +02:00
|
|
|
elog(ERROR, "unrecognized jsonb type: %d", (int) v->type);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
}
|
2014-06-02 01:04:02 +02:00
|
|
|
|
|
|
|
if (result)
|
|
|
|
PG_RETURN_TEXT_P(result);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
2013-03-29 19:12:13 +01:00
|
|
|
Datum
|
|
|
|
json_array_element(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
text *json = PG_GETARG_TEXT_P(0);
|
|
|
|
int element = PG_GETARG_INT32(1);
|
2014-06-25 20:22:18 +02:00
|
|
|
text *result;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
result = get_worker(json, NULL, &element, 1, false);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
if (result != NULL)
|
|
|
|
PG_RETURN_TEXT_P(result);
|
|
|
|
else
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
Datum
|
|
|
|
jsonb_array_element(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Jsonb *jb = PG_GETARG_JSONB(0);
|
|
|
|
int element = PG_GETARG_INT32(1);
|
2014-06-02 01:04:02 +02:00
|
|
|
JsonbValue *v;
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
if (!JB_ROOT_IS_ARRAY(jb))
|
|
|
|
PG_RETURN_NULL();
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
Support JSON negative array subscripts everywhere
Previously, there was an inconsistency across json/jsonb operators that
operate on datums containing JSON arrays -- only some operators
supported negative array count-from-the-end subscripting. Specifically,
only a new-to-9.5 jsonb deletion operator had support (the new "jsonb -
integer" operator). This inconsistency seemed likely to be
counter-intuitive to users. To fix, allow all places where the user can
supply an integer subscript to accept a negative subscript value,
including path-orientated operators and functions, as well as other
extraction operators. This will need to be called out as an
incompatibility in the 9.5 release notes, since it's possible that users
are relying on certain established extraction operators changed here
yielding NULL in the event of a negative subscript.
For the json type, this requires adding a way of cheaply getting the
total JSON array element count ahead of time when parsing arrays with a
negative subscript involved, necessitating an ad-hoc lex and parse.
This is followed by a "conversion" from a negative subscript to its
equivalent positive-wise value using the count. From there on, it's as
if a positive-wise value was originally provided.
Note that there is still a minor inconsistency here across jsonb
deletion operators. Unlike the aforementioned new "-" deletion operator
that accepts an integer on its right hand side, the new "#-" path
orientated deletion variant does not throw an error when it appears like
an array subscript (input that could be recognized by as an integer
literal) is being used on an object, which is wrong-headed. The reason
for not being stricter is that it could be the case that an object pair
happens to have a key value that looks like an integer; in general,
these two possibilities are impossible to differentiate with rhs path
text[] argument elements. However, we still don't allow the "#-"
path-orientated deletion operator to perform array-style subscripting.
Rather, we just return the original left operand value in the event of a
negative subscript (which seems analogous to how the established
"jsonb/json #> text[]" path-orientated operator may yield NULL in the
event of an invalid subscript).
In passing, make SetArrayPath() stricter about not accepting cases where
there is trailing non-numeric garbage bytes rather than a clean NUL
byte. This means, for example, that strings like "10e10" are now not
accepted as an array subscript of 10 by some new-to-9.5 path-orientated
jsonb operators (e.g. the new #- operator). Finally, remove dead code
for jsonb subscript deletion; arguably, this should have been done in
commit b81c7b409.
Peter Geoghegan and Andrew Dunstan
2015-07-18 02:56:13 +02:00
|
|
|
/* Handle negative subscript */
|
|
|
|
if (element < 0)
|
|
|
|
{
|
2016-06-10 00:02:36 +02:00
|
|
|
uint32 nelements = JB_ROOT_COUNT(jb);
|
Support JSON negative array subscripts everywhere
Previously, there was an inconsistency across json/jsonb operators that
operate on datums containing JSON arrays -- only some operators
supported negative array count-from-the-end subscripting. Specifically,
only a new-to-9.5 jsonb deletion operator had support (the new "jsonb -
integer" operator). This inconsistency seemed likely to be
counter-intuitive to users. To fix, allow all places where the user can
supply an integer subscript to accept a negative subscript value,
including path-orientated operators and functions, as well as other
extraction operators. This will need to be called out as an
incompatibility in the 9.5 release notes, since it's possible that users
are relying on certain established extraction operators changed here
yielding NULL in the event of a negative subscript.
For the json type, this requires adding a way of cheaply getting the
total JSON array element count ahead of time when parsing arrays with a
negative subscript involved, necessitating an ad-hoc lex and parse.
This is followed by a "conversion" from a negative subscript to its
equivalent positive-wise value using the count. From there on, it's as
if a positive-wise value was originally provided.
Note that there is still a minor inconsistency here across jsonb
deletion operators. Unlike the aforementioned new "-" deletion operator
that accepts an integer on its right hand side, the new "#-" path
orientated deletion variant does not throw an error when it appears like
an array subscript (input that could be recognized by as an integer
literal) is being used on an object, which is wrong-headed. The reason
for not being stricter is that it could be the case that an object pair
happens to have a key value that looks like an integer; in general,
these two possibilities are impossible to differentiate with rhs path
text[] argument elements. However, we still don't allow the "#-"
path-orientated deletion operator to perform array-style subscripting.
Rather, we just return the original left operand value in the event of a
negative subscript (which seems analogous to how the established
"jsonb/json #> text[]" path-orientated operator may yield NULL in the
event of an invalid subscript).
In passing, make SetArrayPath() stricter about not accepting cases where
there is trailing non-numeric garbage bytes rather than a clean NUL
byte. This means, for example, that strings like "10e10" are now not
accepted as an array subscript of 10 by some new-to-9.5 path-orientated
jsonb operators (e.g. the new #- operator). Finally, remove dead code
for jsonb subscript deletion; arguably, this should have been done in
commit b81c7b409.
Peter Geoghegan and Andrew Dunstan
2015-07-18 02:56:13 +02:00
|
|
|
|
|
|
|
if (-element > nelements)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
else
|
|
|
|
element += nelements;
|
|
|
|
}
|
|
|
|
|
2014-06-02 01:04:02 +02:00
|
|
|
v = getIthJsonbValueFromContainer(&jb->root, element);
|
|
|
|
if (v != NULL)
|
|
|
|
PG_RETURN_JSONB(JsonbValueToJsonb(v));
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
2013-03-29 19:12:13 +01:00
|
|
|
Datum
|
|
|
|
json_array_element_text(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
text *json = PG_GETARG_TEXT_P(0);
|
|
|
|
int element = PG_GETARG_INT32(1);
|
2014-06-25 20:22:18 +02:00
|
|
|
text *result;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
result = get_worker(json, NULL, &element, 1, true);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
if (result != NULL)
|
|
|
|
PG_RETURN_TEXT_P(result);
|
|
|
|
else
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
Datum
|
|
|
|
jsonb_array_element_text(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Jsonb *jb = PG_GETARG_JSONB(0);
|
|
|
|
int element = PG_GETARG_INT32(1);
|
2014-06-02 01:04:02 +02:00
|
|
|
JsonbValue *v;
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
if (!JB_ROOT_IS_ARRAY(jb))
|
|
|
|
PG_RETURN_NULL();
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
Support JSON negative array subscripts everywhere
Previously, there was an inconsistency across json/jsonb operators that
operate on datums containing JSON arrays -- only some operators
supported negative array count-from-the-end subscripting. Specifically,
only a new-to-9.5 jsonb deletion operator had support (the new "jsonb -
integer" operator). This inconsistency seemed likely to be
counter-intuitive to users. To fix, allow all places where the user can
supply an integer subscript to accept a negative subscript value,
including path-orientated operators and functions, as well as other
extraction operators. This will need to be called out as an
incompatibility in the 9.5 release notes, since it's possible that users
are relying on certain established extraction operators changed here
yielding NULL in the event of a negative subscript.
For the json type, this requires adding a way of cheaply getting the
total JSON array element count ahead of time when parsing arrays with a
negative subscript involved, necessitating an ad-hoc lex and parse.
This is followed by a "conversion" from a negative subscript to its
equivalent positive-wise value using the count. From there on, it's as
if a positive-wise value was originally provided.
Note that there is still a minor inconsistency here across jsonb
deletion operators. Unlike the aforementioned new "-" deletion operator
that accepts an integer on its right hand side, the new "#-" path
orientated deletion variant does not throw an error when it appears like
an array subscript (input that could be recognized by as an integer
literal) is being used on an object, which is wrong-headed. The reason
for not being stricter is that it could be the case that an object pair
happens to have a key value that looks like an integer; in general,
these two possibilities are impossible to differentiate with rhs path
text[] argument elements. However, we still don't allow the "#-"
path-orientated deletion operator to perform array-style subscripting.
Rather, we just return the original left operand value in the event of a
negative subscript (which seems analogous to how the established
"jsonb/json #> text[]" path-orientated operator may yield NULL in the
event of an invalid subscript).
In passing, make SetArrayPath() stricter about not accepting cases where
there is trailing non-numeric garbage bytes rather than a clean NUL
byte. This means, for example, that strings like "10e10" are now not
accepted as an array subscript of 10 by some new-to-9.5 path-orientated
jsonb operators (e.g. the new #- operator). Finally, remove dead code
for jsonb subscript deletion; arguably, this should have been done in
commit b81c7b409.
Peter Geoghegan and Andrew Dunstan
2015-07-18 02:56:13 +02:00
|
|
|
/* Handle negative subscript */
|
|
|
|
if (element < 0)
|
|
|
|
{
|
2016-06-10 00:02:36 +02:00
|
|
|
uint32 nelements = JB_ROOT_COUNT(jb);
|
Support JSON negative array subscripts everywhere
Previously, there was an inconsistency across json/jsonb operators that
operate on datums containing JSON arrays -- only some operators
supported negative array count-from-the-end subscripting. Specifically,
only a new-to-9.5 jsonb deletion operator had support (the new "jsonb -
integer" operator). This inconsistency seemed likely to be
counter-intuitive to users. To fix, allow all places where the user can
supply an integer subscript to accept a negative subscript value,
including path-orientated operators and functions, as well as other
extraction operators. This will need to be called out as an
incompatibility in the 9.5 release notes, since it's possible that users
are relying on certain established extraction operators changed here
yielding NULL in the event of a negative subscript.
For the json type, this requires adding a way of cheaply getting the
total JSON array element count ahead of time when parsing arrays with a
negative subscript involved, necessitating an ad-hoc lex and parse.
This is followed by a "conversion" from a negative subscript to its
equivalent positive-wise value using the count. From there on, it's as
if a positive-wise value was originally provided.
Note that there is still a minor inconsistency here across jsonb
deletion operators. Unlike the aforementioned new "-" deletion operator
that accepts an integer on its right hand side, the new "#-" path
orientated deletion variant does not throw an error when it appears like
an array subscript (input that could be recognized by as an integer
literal) is being used on an object, which is wrong-headed. The reason
for not being stricter is that it could be the case that an object pair
happens to have a key value that looks like an integer; in general,
these two possibilities are impossible to differentiate with rhs path
text[] argument elements. However, we still don't allow the "#-"
path-orientated deletion operator to perform array-style subscripting.
Rather, we just return the original left operand value in the event of a
negative subscript (which seems analogous to how the established
"jsonb/json #> text[]" path-orientated operator may yield NULL in the
event of an invalid subscript).
In passing, make SetArrayPath() stricter about not accepting cases where
there is trailing non-numeric garbage bytes rather than a clean NUL
byte. This means, for example, that strings like "10e10" are now not
accepted as an array subscript of 10 by some new-to-9.5 path-orientated
jsonb operators (e.g. the new #- operator). Finally, remove dead code
for jsonb subscript deletion; arguably, this should have been done in
commit b81c7b409.
Peter Geoghegan and Andrew Dunstan
2015-07-18 02:56:13 +02:00
|
|
|
|
|
|
|
if (-element > nelements)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
else
|
|
|
|
element += nelements;
|
|
|
|
}
|
|
|
|
|
2014-06-02 01:04:02 +02:00
|
|
|
v = getIthJsonbValueFromContainer(&jb->root, element);
|
|
|
|
if (v != NULL)
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
{
|
2014-06-02 01:04:02 +02:00
|
|
|
text *result = NULL;
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
2014-06-25 20:22:18 +02:00
|
|
|
switch (v->type)
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
{
|
2014-06-02 01:04:02 +02:00
|
|
|
case jbvNull:
|
|
|
|
break;
|
|
|
|
case jbvBool:
|
|
|
|
result = cstring_to_text(v->val.boolean ? "true" : "false");
|
|
|
|
break;
|
|
|
|
case jbvString:
|
|
|
|
result = cstring_to_text_with_len(v->val.string.val, v->val.string.len);
|
|
|
|
break;
|
|
|
|
case jbvNumeric:
|
|
|
|
result = cstring_to_text(DatumGetCString(DirectFunctionCall1(numeric_out,
|
2014-06-25 20:22:18 +02:00
|
|
|
PointerGetDatum(v->val.numeric))));
|
2014-06-02 01:04:02 +02:00
|
|
|
break;
|
|
|
|
case jbvBinary:
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
{
|
2014-06-25 20:22:18 +02:00
|
|
|
StringInfo jtext = makeStringInfo();
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
2014-06-02 01:04:02 +02:00
|
|
|
(void) JsonbToCString(jtext, v->val.binary.data, -1);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
result = cstring_to_text_with_len(jtext->data, jtext->len);
|
|
|
|
}
|
2014-06-02 01:04:02 +02:00
|
|
|
break;
|
|
|
|
default:
|
2014-06-26 00:25:22 +02:00
|
|
|
elog(ERROR, "unrecognized jsonb type: %d", (int) v->type);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
}
|
2014-06-02 01:04:02 +02:00
|
|
|
|
|
|
|
if (result)
|
|
|
|
PG_RETURN_TEXT_P(result);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
2013-03-29 19:12:13 +01:00
|
|
|
Datum
|
|
|
|
json_extract_path(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-08-22 19:17:58 +02:00
|
|
|
return get_path_all(fcinfo, false);
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
json_extract_path_text(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-08-22 19:17:58 +02:00
|
|
|
return get_path_all(fcinfo, true);
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* common routine for extract_path functions
|
|
|
|
*/
|
2014-06-25 20:22:18 +02:00
|
|
|
static Datum
|
2014-08-22 19:17:58 +02:00
|
|
|
get_path_all(FunctionCallInfo fcinfo, bool as_text)
|
2013-03-29 19:12:13 +01:00
|
|
|
{
|
2014-06-25 20:22:18 +02:00
|
|
|
text *json = PG_GETARG_TEXT_P(0);
|
2013-03-29 19:12:13 +01:00
|
|
|
ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
|
|
|
|
text *result;
|
|
|
|
Datum *pathtext;
|
|
|
|
bool *pathnulls;
|
|
|
|
int npath;
|
|
|
|
char **tpath;
|
|
|
|
int *ipath;
|
|
|
|
int i;
|
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
/*
|
|
|
|
* If the array contains any null elements, return NULL, on the grounds
|
|
|
|
* that you'd have gotten NULL if any RHS value were NULL in a nested
|
|
|
|
* series of applications of the -> operator. (Note: because we also
|
|
|
|
* return NULL for error cases such as no-such-field, this is true
|
|
|
|
* regardless of the contents of the rest of the array.)
|
|
|
|
*/
|
2013-03-29 19:12:13 +01:00
|
|
|
if (array_contains_nulls(path))
|
2014-08-22 19:17:58 +02:00
|
|
|
PG_RETURN_NULL();
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
deconstruct_array(path, TEXTOID, -1, false, 'i',
|
|
|
|
&pathtext, &pathnulls, &npath);
|
|
|
|
|
|
|
|
tpath = palloc(npath * sizeof(char *));
|
|
|
|
ipath = palloc(npath * sizeof(int));
|
|
|
|
|
|
|
|
for (i = 0; i < npath; i++)
|
|
|
|
{
|
2014-08-22 19:17:58 +02:00
|
|
|
Assert(!pathnulls[i]);
|
2013-03-29 19:12:13 +01:00
|
|
|
tpath[i] = TextDatumGetCString(pathtext[i]);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* we have no idea at this stage what structure the document is so
|
|
|
|
* just convert anything in the path that we can to an integer and set
|
Support JSON negative array subscripts everywhere
Previously, there was an inconsistency across json/jsonb operators that
operate on datums containing JSON arrays -- only some operators
supported negative array count-from-the-end subscripting. Specifically,
only a new-to-9.5 jsonb deletion operator had support (the new "jsonb -
integer" operator). This inconsistency seemed likely to be
counter-intuitive to users. To fix, allow all places where the user can
supply an integer subscript to accept a negative subscript value,
including path-orientated operators and functions, as well as other
extraction operators. This will need to be called out as an
incompatibility in the 9.5 release notes, since it's possible that users
are relying on certain established extraction operators changed here
yielding NULL in the event of a negative subscript.
For the json type, this requires adding a way of cheaply getting the
total JSON array element count ahead of time when parsing arrays with a
negative subscript involved, necessitating an ad-hoc lex and parse.
This is followed by a "conversion" from a negative subscript to its
equivalent positive-wise value using the count. From there on, it's as
if a positive-wise value was originally provided.
Note that there is still a minor inconsistency here across jsonb
deletion operators. Unlike the aforementioned new "-" deletion operator
that accepts an integer on its right hand side, the new "#-" path
orientated deletion variant does not throw an error when it appears like
an array subscript (input that could be recognized by as an integer
literal) is being used on an object, which is wrong-headed. The reason
for not being stricter is that it could be the case that an object pair
happens to have a key value that looks like an integer; in general,
these two possibilities are impossible to differentiate with rhs path
text[] argument elements. However, we still don't allow the "#-"
path-orientated deletion operator to perform array-style subscripting.
Rather, we just return the original left operand value in the event of a
negative subscript (which seems analogous to how the established
"jsonb/json #> text[]" path-orientated operator may yield NULL in the
event of an invalid subscript).
In passing, make SetArrayPath() stricter about not accepting cases where
there is trailing non-numeric garbage bytes rather than a clean NUL
byte. This means, for example, that strings like "10e10" are now not
accepted as an array subscript of 10 by some new-to-9.5 path-orientated
jsonb operators (e.g. the new #- operator). Finally, remove dead code
for jsonb subscript deletion; arguably, this should have been done in
commit b81c7b409.
Peter Geoghegan and Andrew Dunstan
2015-07-18 02:56:13 +02:00
|
|
|
* all the other integers to INT_MIN which will never match.
|
2013-03-29 19:12:13 +01:00
|
|
|
*/
|
2014-08-22 19:17:58 +02:00
|
|
|
if (*tpath[i] != '\0')
|
|
|
|
{
|
|
|
|
long ind;
|
|
|
|
char *endptr;
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
ind = strtol(tpath[i], &endptr, 10);
|
Support JSON negative array subscripts everywhere
Previously, there was an inconsistency across json/jsonb operators that
operate on datums containing JSON arrays -- only some operators
supported negative array count-from-the-end subscripting. Specifically,
only a new-to-9.5 jsonb deletion operator had support (the new "jsonb -
integer" operator). This inconsistency seemed likely to be
counter-intuitive to users. To fix, allow all places where the user can
supply an integer subscript to accept a negative subscript value,
including path-orientated operators and functions, as well as other
extraction operators. This will need to be called out as an
incompatibility in the 9.5 release notes, since it's possible that users
are relying on certain established extraction operators changed here
yielding NULL in the event of a negative subscript.
For the json type, this requires adding a way of cheaply getting the
total JSON array element count ahead of time when parsing arrays with a
negative subscript involved, necessitating an ad-hoc lex and parse.
This is followed by a "conversion" from a negative subscript to its
equivalent positive-wise value using the count. From there on, it's as
if a positive-wise value was originally provided.
Note that there is still a minor inconsistency here across jsonb
deletion operators. Unlike the aforementioned new "-" deletion operator
that accepts an integer on its right hand side, the new "#-" path
orientated deletion variant does not throw an error when it appears like
an array subscript (input that could be recognized by as an integer
literal) is being used on an object, which is wrong-headed. The reason
for not being stricter is that it could be the case that an object pair
happens to have a key value that looks like an integer; in general,
these two possibilities are impossible to differentiate with rhs path
text[] argument elements. However, we still don't allow the "#-"
path-orientated deletion operator to perform array-style subscripting.
Rather, we just return the original left operand value in the event of a
negative subscript (which seems analogous to how the established
"jsonb/json #> text[]" path-orientated operator may yield NULL in the
event of an invalid subscript).
In passing, make SetArrayPath() stricter about not accepting cases where
there is trailing non-numeric garbage bytes rather than a clean NUL
byte. This means, for example, that strings like "10e10" are now not
accepted as an array subscript of 10 by some new-to-9.5 path-orientated
jsonb operators (e.g. the new #- operator). Finally, remove dead code
for jsonb subscript deletion; arguably, this should have been done in
commit b81c7b409.
Peter Geoghegan and Andrew Dunstan
2015-07-18 02:56:13 +02:00
|
|
|
if (*endptr == '\0' && errno == 0 && ind <= INT_MAX && ind >= INT_MIN)
|
2014-08-22 19:17:58 +02:00
|
|
|
ipath[i] = (int) ind;
|
|
|
|
else
|
Support JSON negative array subscripts everywhere
Previously, there was an inconsistency across json/jsonb operators that
operate on datums containing JSON arrays -- only some operators
supported negative array count-from-the-end subscripting. Specifically,
only a new-to-9.5 jsonb deletion operator had support (the new "jsonb -
integer" operator). This inconsistency seemed likely to be
counter-intuitive to users. To fix, allow all places where the user can
supply an integer subscript to accept a negative subscript value,
including path-orientated operators and functions, as well as other
extraction operators. This will need to be called out as an
incompatibility in the 9.5 release notes, since it's possible that users
are relying on certain established extraction operators changed here
yielding NULL in the event of a negative subscript.
For the json type, this requires adding a way of cheaply getting the
total JSON array element count ahead of time when parsing arrays with a
negative subscript involved, necessitating an ad-hoc lex and parse.
This is followed by a "conversion" from a negative subscript to its
equivalent positive-wise value using the count. From there on, it's as
if a positive-wise value was originally provided.
Note that there is still a minor inconsistency here across jsonb
deletion operators. Unlike the aforementioned new "-" deletion operator
that accepts an integer on its right hand side, the new "#-" path
orientated deletion variant does not throw an error when it appears like
an array subscript (input that could be recognized by as an integer
literal) is being used on an object, which is wrong-headed. The reason
for not being stricter is that it could be the case that an object pair
happens to have a key value that looks like an integer; in general,
these two possibilities are impossible to differentiate with rhs path
text[] argument elements. However, we still don't allow the "#-"
path-orientated deletion operator to perform array-style subscripting.
Rather, we just return the original left operand value in the event of a
negative subscript (which seems analogous to how the established
"jsonb/json #> text[]" path-orientated operator may yield NULL in the
event of an invalid subscript).
In passing, make SetArrayPath() stricter about not accepting cases where
there is trailing non-numeric garbage bytes rather than a clean NUL
byte. This means, for example, that strings like "10e10" are now not
accepted as an array subscript of 10 by some new-to-9.5 path-orientated
jsonb operators (e.g. the new #- operator). Finally, remove dead code
for jsonb subscript deletion; arguably, this should have been done in
commit b81c7b409.
Peter Geoghegan and Andrew Dunstan
2015-07-18 02:56:13 +02:00
|
|
|
ipath[i] = INT_MIN;
|
2014-08-22 19:17:58 +02:00
|
|
|
}
|
2013-03-29 19:12:13 +01:00
|
|
|
else
|
Support JSON negative array subscripts everywhere
Previously, there was an inconsistency across json/jsonb operators that
operate on datums containing JSON arrays -- only some operators
supported negative array count-from-the-end subscripting. Specifically,
only a new-to-9.5 jsonb deletion operator had support (the new "jsonb -
integer" operator). This inconsistency seemed likely to be
counter-intuitive to users. To fix, allow all places where the user can
supply an integer subscript to accept a negative subscript value,
including path-orientated operators and functions, as well as other
extraction operators. This will need to be called out as an
incompatibility in the 9.5 release notes, since it's possible that users
are relying on certain established extraction operators changed here
yielding NULL in the event of a negative subscript.
For the json type, this requires adding a way of cheaply getting the
total JSON array element count ahead of time when parsing arrays with a
negative subscript involved, necessitating an ad-hoc lex and parse.
This is followed by a "conversion" from a negative subscript to its
equivalent positive-wise value using the count. From there on, it's as
if a positive-wise value was originally provided.
Note that there is still a minor inconsistency here across jsonb
deletion operators. Unlike the aforementioned new "-" deletion operator
that accepts an integer on its right hand side, the new "#-" path
orientated deletion variant does not throw an error when it appears like
an array subscript (input that could be recognized by as an integer
literal) is being used on an object, which is wrong-headed. The reason
for not being stricter is that it could be the case that an object pair
happens to have a key value that looks like an integer; in general,
these two possibilities are impossible to differentiate with rhs path
text[] argument elements. However, we still don't allow the "#-"
path-orientated deletion operator to perform array-style subscripting.
Rather, we just return the original left operand value in the event of a
negative subscript (which seems analogous to how the established
"jsonb/json #> text[]" path-orientated operator may yield NULL in the
event of an invalid subscript).
In passing, make SetArrayPath() stricter about not accepting cases where
there is trailing non-numeric garbage bytes rather than a clean NUL
byte. This means, for example, that strings like "10e10" are now not
accepted as an array subscript of 10 by some new-to-9.5 path-orientated
jsonb operators (e.g. the new #- operator). Finally, remove dead code
for jsonb subscript deletion; arguably, this should have been done in
commit b81c7b409.
Peter Geoghegan and Andrew Dunstan
2015-07-18 02:56:13 +02:00
|
|
|
ipath[i] = INT_MIN;
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
result = get_worker(json, tpath, ipath, npath, as_text);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
if (result != NULL)
|
2014-05-06 18:12:18 +02:00
|
|
|
PG_RETURN_TEXT_P(result);
|
2013-03-29 19:12:13 +01:00
|
|
|
else
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get_worker
|
|
|
|
*
|
|
|
|
* common worker for all the json getter functions
|
2014-08-22 19:17:58 +02:00
|
|
|
*
|
|
|
|
* json: JSON object (in text form)
|
|
|
|
* tpath[]: field name(s) to extract
|
Support JSON negative array subscripts everywhere
Previously, there was an inconsistency across json/jsonb operators that
operate on datums containing JSON arrays -- only some operators
supported negative array count-from-the-end subscripting. Specifically,
only a new-to-9.5 jsonb deletion operator had support (the new "jsonb -
integer" operator). This inconsistency seemed likely to be
counter-intuitive to users. To fix, allow all places where the user can
supply an integer subscript to accept a negative subscript value,
including path-orientated operators and functions, as well as other
extraction operators. This will need to be called out as an
incompatibility in the 9.5 release notes, since it's possible that users
are relying on certain established extraction operators changed here
yielding NULL in the event of a negative subscript.
For the json type, this requires adding a way of cheaply getting the
total JSON array element count ahead of time when parsing arrays with a
negative subscript involved, necessitating an ad-hoc lex and parse.
This is followed by a "conversion" from a negative subscript to its
equivalent positive-wise value using the count. From there on, it's as
if a positive-wise value was originally provided.
Note that there is still a minor inconsistency here across jsonb
deletion operators. Unlike the aforementioned new "-" deletion operator
that accepts an integer on its right hand side, the new "#-" path
orientated deletion variant does not throw an error when it appears like
an array subscript (input that could be recognized by as an integer
literal) is being used on an object, which is wrong-headed. The reason
for not being stricter is that it could be the case that an object pair
happens to have a key value that looks like an integer; in general,
these two possibilities are impossible to differentiate with rhs path
text[] argument elements. However, we still don't allow the "#-"
path-orientated deletion operator to perform array-style subscripting.
Rather, we just return the original left operand value in the event of a
negative subscript (which seems analogous to how the established
"jsonb/json #> text[]" path-orientated operator may yield NULL in the
event of an invalid subscript).
In passing, make SetArrayPath() stricter about not accepting cases where
there is trailing non-numeric garbage bytes rather than a clean NUL
byte. This means, for example, that strings like "10e10" are now not
accepted as an array subscript of 10 by some new-to-9.5 path-orientated
jsonb operators (e.g. the new #- operator). Finally, remove dead code
for jsonb subscript deletion; arguably, this should have been done in
commit b81c7b409.
Peter Geoghegan and Andrew Dunstan
2015-07-18 02:56:13 +02:00
|
|
|
* ipath[]: array index(es) (zero-based) to extract, accepts negatives
|
2014-08-22 19:17:58 +02:00
|
|
|
* npath: length of tpath[] and/or ipath[]
|
|
|
|
* normalize_results: true to de-escape string and null scalars
|
|
|
|
*
|
|
|
|
* tpath can be NULL, or any one tpath[] entry can be NULL, if an object
|
|
|
|
* field is not to be matched at that nesting level. Similarly, ipath can
|
Support JSON negative array subscripts everywhere
Previously, there was an inconsistency across json/jsonb operators that
operate on datums containing JSON arrays -- only some operators
supported negative array count-from-the-end subscripting. Specifically,
only a new-to-9.5 jsonb deletion operator had support (the new "jsonb -
integer" operator). This inconsistency seemed likely to be
counter-intuitive to users. To fix, allow all places where the user can
supply an integer subscript to accept a negative subscript value,
including path-orientated operators and functions, as well as other
extraction operators. This will need to be called out as an
incompatibility in the 9.5 release notes, since it's possible that users
are relying on certain established extraction operators changed here
yielding NULL in the event of a negative subscript.
For the json type, this requires adding a way of cheaply getting the
total JSON array element count ahead of time when parsing arrays with a
negative subscript involved, necessitating an ad-hoc lex and parse.
This is followed by a "conversion" from a negative subscript to its
equivalent positive-wise value using the count. From there on, it's as
if a positive-wise value was originally provided.
Note that there is still a minor inconsistency here across jsonb
deletion operators. Unlike the aforementioned new "-" deletion operator
that accepts an integer on its right hand side, the new "#-" path
orientated deletion variant does not throw an error when it appears like
an array subscript (input that could be recognized by as an integer
literal) is being used on an object, which is wrong-headed. The reason
for not being stricter is that it could be the case that an object pair
happens to have a key value that looks like an integer; in general,
these two possibilities are impossible to differentiate with rhs path
text[] argument elements. However, we still don't allow the "#-"
path-orientated deletion operator to perform array-style subscripting.
Rather, we just return the original left operand value in the event of a
negative subscript (which seems analogous to how the established
"jsonb/json #> text[]" path-orientated operator may yield NULL in the
event of an invalid subscript).
In passing, make SetArrayPath() stricter about not accepting cases where
there is trailing non-numeric garbage bytes rather than a clean NUL
byte. This means, for example, that strings like "10e10" are now not
accepted as an array subscript of 10 by some new-to-9.5 path-orientated
jsonb operators (e.g. the new #- operator). Finally, remove dead code
for jsonb subscript deletion; arguably, this should have been done in
commit b81c7b409.
Peter Geoghegan and Andrew Dunstan
2015-07-18 02:56:13 +02:00
|
|
|
* be NULL, or any one ipath[] entry can be INT_MIN if an array element is
|
|
|
|
* not to be matched at that nesting level (a json datum should never be
|
|
|
|
* large enough to have -INT_MIN elements due to MaxAllocSize restriction).
|
2013-03-29 19:12:13 +01:00
|
|
|
*/
|
2014-06-25 20:22:18 +02:00
|
|
|
static text *
|
2013-03-29 19:12:13 +01:00
|
|
|
get_worker(text *json,
|
|
|
|
char **tpath,
|
|
|
|
int *ipath,
|
|
|
|
int npath,
|
|
|
|
bool normalize_results)
|
|
|
|
{
|
|
|
|
JsonLexContext *lex = makeJsonLexContext(json, true);
|
2014-08-22 19:17:58 +02:00
|
|
|
JsonSemAction *sem = palloc0(sizeof(JsonSemAction));
|
|
|
|
GetState *state = palloc0(sizeof(GetState));
|
2013-03-29 19:12:13 +01:00
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
Assert(npath >= 0);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
state->lex = lex;
|
|
|
|
/* is it "_as_text" variant? */
|
|
|
|
state->normalize_results = normalize_results;
|
2014-08-22 19:17:58 +02:00
|
|
|
state->npath = npath;
|
|
|
|
state->path_names = tpath;
|
|
|
|
state->path_indexes = ipath;
|
|
|
|
state->pathok = palloc0(sizeof(bool) * npath);
|
|
|
|
state->array_cur_index = palloc(sizeof(int) * npath);
|
|
|
|
|
|
|
|
if (npath > 0)
|
2013-03-29 19:12:13 +01:00
|
|
|
state->pathok[0] = true;
|
|
|
|
|
|
|
|
sem->semstate = (void *) state;
|
|
|
|
|
|
|
|
/*
|
2014-06-26 00:25:22 +02:00
|
|
|
* Not all variants need all the semantic routines. Only set the ones that
|
|
|
|
* are actually needed for maximum efficiency.
|
2013-03-29 19:12:13 +01:00
|
|
|
*/
|
|
|
|
sem->scalar = get_scalar;
|
2014-08-22 19:17:58 +02:00
|
|
|
if (npath == 0)
|
|
|
|
{
|
|
|
|
sem->object_start = get_object_start;
|
|
|
|
sem->object_end = get_object_end;
|
|
|
|
sem->array_start = get_array_start;
|
|
|
|
sem->array_end = get_array_end;
|
|
|
|
}
|
|
|
|
if (tpath != NULL)
|
2013-03-29 19:12:13 +01:00
|
|
|
{
|
|
|
|
sem->object_field_start = get_object_field_start;
|
|
|
|
sem->object_field_end = get_object_field_end;
|
|
|
|
}
|
2014-08-22 19:17:58 +02:00
|
|
|
if (ipath != NULL)
|
2013-03-29 19:12:13 +01:00
|
|
|
{
|
2014-08-22 19:17:58 +02:00
|
|
|
sem->array_start = get_array_start;
|
2013-03-29 19:12:13 +01:00
|
|
|
sem->array_element_start = get_array_element_start;
|
|
|
|
sem->array_element_end = get_array_element_end;
|
|
|
|
}
|
|
|
|
|
|
|
|
pg_parse_json(lex, sem);
|
|
|
|
|
|
|
|
return state->tresult;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
get_object_start(void *state)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
GetState *_state = (GetState *) state;
|
2014-08-22 19:17:58 +02:00
|
|
|
int lex_level = _state->lex->lex_level;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
if (lex_level == 0 && _state->npath == 0)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Special case: we should match the entire object. We only need this
|
|
|
|
* at outermost level because at nested levels the match will have
|
|
|
|
* been started by the outer field or array element callback.
|
|
|
|
*/
|
|
|
|
_state->result_start = _state->lex->token_start;
|
|
|
|
}
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-08-22 19:17:58 +02:00
|
|
|
get_object_end(void *state)
|
2013-03-29 19:12:13 +01:00
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
GetState *_state = (GetState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
int lex_level = _state->lex->lex_level;
|
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
if (lex_level == 0 && _state->npath == 0)
|
2013-03-29 19:12:13 +01:00
|
|
|
{
|
2014-08-22 19:17:58 +02:00
|
|
|
/* Special case: return the entire object */
|
|
|
|
char *start = _state->result_start;
|
|
|
|
int len = _state->lex->prev_token_terminator - start;
|
|
|
|
|
|
|
|
_state->tresult = cstring_to_text_with_len(start, len);
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
2014-08-22 19:17:58 +02:00
|
|
|
}
|
2013-03-29 19:12:13 +01:00
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
static void
|
|
|
|
get_object_field_start(void *state, char *fname, bool isnull)
|
|
|
|
{
|
|
|
|
GetState *_state = (GetState *) state;
|
|
|
|
bool get_next = false;
|
|
|
|
int lex_level = _state->lex->lex_level;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
if (lex_level <= _state->npath &&
|
|
|
|
_state->pathok[lex_level - 1] &&
|
|
|
|
_state->path_names != NULL &&
|
|
|
|
_state->path_names[lex_level - 1] != NULL &&
|
|
|
|
strcmp(fname, _state->path_names[lex_level - 1]) == 0)
|
|
|
|
{
|
2013-03-29 19:12:13 +01:00
|
|
|
if (lex_level < _state->npath)
|
2014-08-22 19:17:58 +02:00
|
|
|
{
|
|
|
|
/* if not at end of path just mark path ok */
|
2013-03-29 19:12:13 +01:00
|
|
|
_state->pathok[lex_level] = true;
|
2014-08-22 19:17:58 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* end of path, so we want this value */
|
2013-03-29 19:12:13 +01:00
|
|
|
get_next = true;
|
2014-08-22 19:17:58 +02:00
|
|
|
}
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (get_next)
|
|
|
|
{
|
2014-08-22 19:17:58 +02:00
|
|
|
/* this object overrides any previous matching object */
|
|
|
|
_state->tresult = NULL;
|
|
|
|
_state->result_start = NULL;
|
|
|
|
|
2013-03-29 19:12:13 +01:00
|
|
|
if (_state->normalize_results &&
|
|
|
|
_state->lex->token_type == JSON_TOKEN_STRING)
|
|
|
|
{
|
|
|
|
/* for as_text variants, tell get_scalar to set it for us */
|
|
|
|
_state->next_scalar = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* for non-as_text variants, just note the json starting point */
|
|
|
|
_state->result_start = _state->lex->token_start;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
get_object_field_end(void *state, char *fname, bool isnull)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
GetState *_state = (GetState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
bool get_last = false;
|
|
|
|
int lex_level = _state->lex->lex_level;
|
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
/* same tests as in get_object_field_start */
|
|
|
|
if (lex_level <= _state->npath &&
|
|
|
|
_state->pathok[lex_level - 1] &&
|
|
|
|
_state->path_names != NULL &&
|
|
|
|
_state->path_names[lex_level - 1] != NULL &&
|
|
|
|
strcmp(fname, _state->path_names[lex_level - 1]) == 0)
|
2013-03-29 19:12:13 +01:00
|
|
|
{
|
|
|
|
if (lex_level < _state->npath)
|
2014-08-22 19:17:58 +02:00
|
|
|
{
|
|
|
|
/* done with this field so reset pathok */
|
2013-03-29 19:12:13 +01:00
|
|
|
_state->pathok[lex_level] = false;
|
2014-08-22 19:17:58 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* end of path, so we want this value */
|
2013-03-29 19:12:13 +01:00
|
|
|
get_last = true;
|
2014-08-22 19:17:58 +02:00
|
|
|
}
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
/* for as_text scalar case, our work is already done */
|
2013-03-29 19:12:13 +01:00
|
|
|
if (get_last && _state->result_start != NULL)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* make a text object from the string from the prevously noted json
|
|
|
|
* start up to the end of the previous token (the lexer is by now
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
* ahead of us on whatever came after what we're interested in).
|
2013-03-29 19:12:13 +01:00
|
|
|
*/
|
|
|
|
if (isnull && _state->normalize_results)
|
|
|
|
_state->tresult = (text *) NULL;
|
|
|
|
else
|
2014-08-22 19:17:58 +02:00
|
|
|
{
|
|
|
|
char *start = _state->result_start;
|
|
|
|
int len = _state->lex->prev_token_terminator - start;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
_state->tresult = cstring_to_text_with_len(start, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* this should be unnecessary but let's do it for cleanliness: */
|
|
|
|
_state->result_start = NULL;
|
|
|
|
}
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
get_array_start(void *state)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
GetState *_state = (GetState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
int lex_level = _state->lex->lex_level;
|
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
if (lex_level < _state->npath)
|
|
|
|
{
|
|
|
|
/* Initialize counting of elements in this array */
|
|
|
|
_state->array_cur_index[lex_level] = -1;
|
2015-07-28 23:54:13 +02:00
|
|
|
|
|
|
|
/* INT_MIN value is reserved to represent invalid subscript */
|
|
|
|
if (_state->path_indexes[lex_level] < 0 &&
|
|
|
|
_state->path_indexes[lex_level] != INT_MIN)
|
|
|
|
{
|
|
|
|
/* Negative subscript -- convert to positive-wise subscript */
|
2016-06-10 00:02:36 +02:00
|
|
|
int nelements = json_count_array_elements(_state->lex);
|
2015-07-28 23:54:13 +02:00
|
|
|
|
|
|
|
if (-_state->path_indexes[lex_level] <= nelements)
|
|
|
|
_state->path_indexes[lex_level] += nelements;
|
|
|
|
}
|
2014-08-22 19:17:58 +02:00
|
|
|
}
|
|
|
|
else if (lex_level == 0 && _state->npath == 0)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Special case: we should match the entire array. We only need this
|
2016-06-10 00:02:36 +02:00
|
|
|
* at the outermost level because at nested levels the match will have
|
|
|
|
* been started by the outer field or array element callback.
|
2014-08-22 19:17:58 +02:00
|
|
|
*/
|
|
|
|
_state->result_start = _state->lex->token_start;
|
|
|
|
}
|
|
|
|
}
|
2013-05-29 22:58:43 +02:00
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
static void
|
|
|
|
get_array_end(void *state)
|
|
|
|
{
|
|
|
|
GetState *_state = (GetState *) state;
|
|
|
|
int lex_level = _state->lex->lex_level;
|
|
|
|
|
|
|
|
if (lex_level == 0 && _state->npath == 0)
|
|
|
|
{
|
|
|
|
/* Special case: return the entire array */
|
|
|
|
char *start = _state->result_start;
|
|
|
|
int len = _state->lex->prev_token_terminator - start;
|
|
|
|
|
|
|
|
_state->tresult = cstring_to_text_with_len(start, len);
|
|
|
|
}
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
get_array_element_start(void *state, bool isnull)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
GetState *_state = (GetState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
bool get_next = false;
|
|
|
|
int lex_level = _state->lex->lex_level;
|
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
/* Update array element counter */
|
|
|
|
if (lex_level <= _state->npath)
|
|
|
|
_state->array_cur_index[lex_level - 1]++;
|
|
|
|
|
|
|
|
if (lex_level <= _state->npath &&
|
|
|
|
_state->pathok[lex_level - 1] &&
|
|
|
|
_state->path_indexes != NULL &&
|
|
|
|
_state->array_cur_index[lex_level - 1] == _state->path_indexes[lex_level - 1])
|
2013-03-29 19:12:13 +01:00
|
|
|
{
|
2014-08-22 19:17:58 +02:00
|
|
|
if (lex_level < _state->npath)
|
2013-03-29 19:12:13 +01:00
|
|
|
{
|
2014-08-22 19:17:58 +02:00
|
|
|
/* if not at end of path just mark path ok */
|
|
|
|
_state->pathok[lex_level] = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* end of path, so we want this value */
|
|
|
|
get_next = true;
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* same logic as for objects */
|
|
|
|
if (get_next)
|
|
|
|
{
|
2014-08-22 19:17:58 +02:00
|
|
|
_state->tresult = NULL;
|
|
|
|
_state->result_start = NULL;
|
|
|
|
|
2013-03-29 19:12:13 +01:00
|
|
|
if (_state->normalize_results &&
|
|
|
|
_state->lex->token_type == JSON_TOKEN_STRING)
|
|
|
|
{
|
|
|
|
_state->next_scalar = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_state->result_start = _state->lex->token_start;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
get_array_element_end(void *state, bool isnull)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
GetState *_state = (GetState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
bool get_last = false;
|
|
|
|
int lex_level = _state->lex->lex_level;
|
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
/* same tests as in get_array_element_start */
|
|
|
|
if (lex_level <= _state->npath &&
|
|
|
|
_state->pathok[lex_level - 1] &&
|
|
|
|
_state->path_indexes != NULL &&
|
|
|
|
_state->array_cur_index[lex_level - 1] == _state->path_indexes[lex_level - 1])
|
2013-03-29 19:12:13 +01:00
|
|
|
{
|
|
|
|
if (lex_level < _state->npath)
|
2014-08-22 19:17:58 +02:00
|
|
|
{
|
|
|
|
/* done with this element so reset pathok */
|
2013-03-29 19:12:13 +01:00
|
|
|
_state->pathok[lex_level] = false;
|
2014-08-22 19:17:58 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* end of path, so we want this value */
|
2013-03-29 19:12:13 +01:00
|
|
|
get_last = true;
|
2014-08-22 19:17:58 +02:00
|
|
|
}
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
2014-08-22 19:17:58 +02:00
|
|
|
|
|
|
|
/* same logic as for objects */
|
2013-03-29 19:12:13 +01:00
|
|
|
if (get_last && _state->result_start != NULL)
|
|
|
|
{
|
|
|
|
if (isnull && _state->normalize_results)
|
|
|
|
_state->tresult = (text *) NULL;
|
|
|
|
else
|
2014-08-22 19:17:58 +02:00
|
|
|
{
|
|
|
|
char *start = _state->result_start;
|
|
|
|
int len = _state->lex->prev_token_terminator - start;
|
|
|
|
|
|
|
|
_state->tresult = cstring_to_text_with_len(start, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
_state->result_start = NULL;
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
get_scalar(void *state, char *token, JsonTokenType tokentype)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
GetState *_state = (GetState *) state;
|
2014-08-22 19:17:58 +02:00
|
|
|
int lex_level = _state->lex->lex_level;
|
|
|
|
|
|
|
|
/* Check for whole-object match */
|
|
|
|
if (lex_level == 0 && _state->npath == 0)
|
|
|
|
{
|
|
|
|
if (_state->normalize_results && tokentype == JSON_TOKEN_STRING)
|
|
|
|
{
|
|
|
|
/* we want the de-escaped string */
|
|
|
|
_state->next_scalar = true;
|
|
|
|
}
|
|
|
|
else if (_state->normalize_results && tokentype == JSON_TOKEN_NULL)
|
|
|
|
{
|
|
|
|
_state->tresult = (text *) NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* This is a bit hokey: we will suppress whitespace after the
|
|
|
|
* scalar token, but not whitespace before it. Probably not worth
|
|
|
|
* doing our own space-skipping to avoid that.
|
|
|
|
*/
|
|
|
|
char *start = _state->lex->input;
|
|
|
|
int len = _state->lex->prev_token_terminator - start;
|
|
|
|
|
|
|
|
_state->tresult = cstring_to_text_with_len(start, len);
|
|
|
|
}
|
|
|
|
}
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
if (_state->next_scalar)
|
|
|
|
{
|
|
|
|
/* a de-escaped text value is wanted, so supply it */
|
|
|
|
_state->tresult = cstring_to_text(token);
|
|
|
|
/* make sure the next call to get_scalar doesn't overwrite it */
|
|
|
|
_state->next_scalar = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
Datum
|
|
|
|
jsonb_extract_path(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-08-22 19:17:58 +02:00
|
|
|
return get_jsonb_path_all(fcinfo, false);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
jsonb_extract_path_text(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-08-22 19:17:58 +02:00
|
|
|
return get_jsonb_path_all(fcinfo, true);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
}
|
|
|
|
|
2014-06-25 20:22:18 +02:00
|
|
|
static Datum
|
2014-08-22 19:17:58 +02:00
|
|
|
get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
{
|
|
|
|
Jsonb *jb = PG_GETARG_JSONB(0);
|
|
|
|
ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
|
2014-08-20 22:48:35 +02:00
|
|
|
Jsonb *res;
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
Datum *pathtext;
|
|
|
|
bool *pathnulls;
|
|
|
|
int npath;
|
|
|
|
int i;
|
|
|
|
bool have_object = false,
|
|
|
|
have_array = false;
|
|
|
|
JsonbValue *jbvp = NULL;
|
|
|
|
JsonbValue tv;
|
2014-05-07 22:16:19 +02:00
|
|
|
JsonbContainer *container;
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
/*
|
|
|
|
* If the array contains any null elements, return NULL, on the grounds
|
|
|
|
* that you'd have gotten NULL if any RHS value were NULL in a nested
|
|
|
|
* series of applications of the -> operator. (Note: because we also
|
|
|
|
* return NULL for error cases such as no-such-field, this is true
|
|
|
|
* regardless of the contents of the rest of the array.)
|
|
|
|
*/
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
if (array_contains_nulls(path))
|
2014-08-22 19:17:58 +02:00
|
|
|
PG_RETURN_NULL();
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
|
|
|
deconstruct_array(path, TEXTOID, -1, false, 'i',
|
|
|
|
&pathtext, &pathnulls, &npath);
|
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
/* Identify whether we have object, array, or scalar at top-level */
|
|
|
|
container = &jb->root;
|
2014-08-20 22:48:35 +02:00
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
if (JB_ROOT_IS_OBJECT(jb))
|
|
|
|
have_object = true;
|
|
|
|
else if (JB_ROOT_IS_ARRAY(jb) && !JB_ROOT_IS_SCALAR(jb))
|
|
|
|
have_array = true;
|
2014-08-22 19:17:58 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
Assert(JB_ROOT_IS_ARRAY(jb) && JB_ROOT_IS_SCALAR(jb));
|
|
|
|
/* Extract the scalar value, if it is what we'll return */
|
|
|
|
if (npath <= 0)
|
|
|
|
jbvp = getIthJsonbValueFromContainer(container, 0);
|
|
|
|
}
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
/*
|
|
|
|
* If the array is empty, return the entire LHS object, on the grounds
|
|
|
|
* that we should do zero field or element extractions. For the
|
|
|
|
* non-scalar case we can just hand back the object without much work. For
|
|
|
|
* the scalar case, fall through and deal with the value below the loop.
|
|
|
|
* (This inconsistency arises because there's no easy way to generate a
|
|
|
|
* JsonbValue directly for root-level containers.)
|
|
|
|
*/
|
|
|
|
if (npath <= 0 && jbvp == NULL)
|
|
|
|
{
|
|
|
|
if (as_text)
|
|
|
|
{
|
|
|
|
PG_RETURN_TEXT_P(cstring_to_text(JsonbToCString(NULL,
|
|
|
|
container,
|
|
|
|
VARSIZE(jb))));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* not text mode - just hand back the jsonb */
|
|
|
|
PG_RETURN_JSONB(jb);
|
|
|
|
}
|
|
|
|
}
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
|
|
|
for (i = 0; i < npath; i++)
|
|
|
|
{
|
|
|
|
if (have_object)
|
|
|
|
{
|
2014-05-07 22:16:19 +02:00
|
|
|
jbvp = findJsonbValueFromContainerLen(container,
|
|
|
|
JB_FOBJECT,
|
|
|
|
VARDATA_ANY(pathtext[i]),
|
2014-05-06 18:12:18 +02:00
|
|
|
VARSIZE_ANY_EXHDR(pathtext[i]));
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
}
|
|
|
|
else if (have_array)
|
|
|
|
{
|
|
|
|
long lindex;
|
|
|
|
uint32 index;
|
|
|
|
char *indextext = TextDatumGetCString(pathtext[i]);
|
|
|
|
char *endptr;
|
|
|
|
|
2014-08-22 19:17:58 +02:00
|
|
|
errno = 0;
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
lindex = strtol(indextext, &endptr, 10);
|
2014-08-22 19:17:58 +02:00
|
|
|
if (endptr == indextext || *endptr != '\0' || errno != 0 ||
|
Support JSON negative array subscripts everywhere
Previously, there was an inconsistency across json/jsonb operators that
operate on datums containing JSON arrays -- only some operators
supported negative array count-from-the-end subscripting. Specifically,
only a new-to-9.5 jsonb deletion operator had support (the new "jsonb -
integer" operator). This inconsistency seemed likely to be
counter-intuitive to users. To fix, allow all places where the user can
supply an integer subscript to accept a negative subscript value,
including path-orientated operators and functions, as well as other
extraction operators. This will need to be called out as an
incompatibility in the 9.5 release notes, since it's possible that users
are relying on certain established extraction operators changed here
yielding NULL in the event of a negative subscript.
For the json type, this requires adding a way of cheaply getting the
total JSON array element count ahead of time when parsing arrays with a
negative subscript involved, necessitating an ad-hoc lex and parse.
This is followed by a "conversion" from a negative subscript to its
equivalent positive-wise value using the count. From there on, it's as
if a positive-wise value was originally provided.
Note that there is still a minor inconsistency here across jsonb
deletion operators. Unlike the aforementioned new "-" deletion operator
that accepts an integer on its right hand side, the new "#-" path
orientated deletion variant does not throw an error when it appears like
an array subscript (input that could be recognized by as an integer
literal) is being used on an object, which is wrong-headed. The reason
for not being stricter is that it could be the case that an object pair
happens to have a key value that looks like an integer; in general,
these two possibilities are impossible to differentiate with rhs path
text[] argument elements. However, we still don't allow the "#-"
path-orientated deletion operator to perform array-style subscripting.
Rather, we just return the original left operand value in the event of a
negative subscript (which seems analogous to how the established
"jsonb/json #> text[]" path-orientated operator may yield NULL in the
event of an invalid subscript).
In passing, make SetArrayPath() stricter about not accepting cases where
there is trailing non-numeric garbage bytes rather than a clean NUL
byte. This means, for example, that strings like "10e10" are now not
accepted as an array subscript of 10 by some new-to-9.5 path-orientated
jsonb operators (e.g. the new #- operator). Finally, remove dead code
for jsonb subscript deletion; arguably, this should have been done in
commit b81c7b409.
Peter Geoghegan and Andrew Dunstan
2015-07-18 02:56:13 +02:00
|
|
|
lindex > INT_MAX || lindex < INT_MIN)
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
PG_RETURN_NULL();
|
Support JSON negative array subscripts everywhere
Previously, there was an inconsistency across json/jsonb operators that
operate on datums containing JSON arrays -- only some operators
supported negative array count-from-the-end subscripting. Specifically,
only a new-to-9.5 jsonb deletion operator had support (the new "jsonb -
integer" operator). This inconsistency seemed likely to be
counter-intuitive to users. To fix, allow all places where the user can
supply an integer subscript to accept a negative subscript value,
including path-orientated operators and functions, as well as other
extraction operators. This will need to be called out as an
incompatibility in the 9.5 release notes, since it's possible that users
are relying on certain established extraction operators changed here
yielding NULL in the event of a negative subscript.
For the json type, this requires adding a way of cheaply getting the
total JSON array element count ahead of time when parsing arrays with a
negative subscript involved, necessitating an ad-hoc lex and parse.
This is followed by a "conversion" from a negative subscript to its
equivalent positive-wise value using the count. From there on, it's as
if a positive-wise value was originally provided.
Note that there is still a minor inconsistency here across jsonb
deletion operators. Unlike the aforementioned new "-" deletion operator
that accepts an integer on its right hand side, the new "#-" path
orientated deletion variant does not throw an error when it appears like
an array subscript (input that could be recognized by as an integer
literal) is being used on an object, which is wrong-headed. The reason
for not being stricter is that it could be the case that an object pair
happens to have a key value that looks like an integer; in general,
these two possibilities are impossible to differentiate with rhs path
text[] argument elements. However, we still don't allow the "#-"
path-orientated deletion operator to perform array-style subscripting.
Rather, we just return the original left operand value in the event of a
negative subscript (which seems analogous to how the established
"jsonb/json #> text[]" path-orientated operator may yield NULL in the
event of an invalid subscript).
In passing, make SetArrayPath() stricter about not accepting cases where
there is trailing non-numeric garbage bytes rather than a clean NUL
byte. This means, for example, that strings like "10e10" are now not
accepted as an array subscript of 10 by some new-to-9.5 path-orientated
jsonb operators (e.g. the new #- operator). Finally, remove dead code
for jsonb subscript deletion; arguably, this should have been done in
commit b81c7b409.
Peter Geoghegan and Andrew Dunstan
2015-07-18 02:56:13 +02:00
|
|
|
|
|
|
|
if (lindex >= 0)
|
|
|
|
{
|
|
|
|
index = (uint32) lindex;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Handle negative subscript */
|
|
|
|
uint32 nelements;
|
|
|
|
|
|
|
|
/* Container must be array, but make sure */
|
|
|
|
if ((container->header & JB_FARRAY) == 0)
|
|
|
|
elog(ERROR, "not a jsonb array");
|
|
|
|
|
|
|
|
nelements = container->header & JB_CMASK;
|
|
|
|
|
|
|
|
if (-lindex > nelements)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
else
|
|
|
|
index = nelements + lindex;
|
|
|
|
}
|
|
|
|
|
2014-05-07 22:16:19 +02:00
|
|
|
jbvp = getIthJsonbValueFromContainer(container, index);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-08-22 19:17:58 +02:00
|
|
|
/* scalar, extraction yields a null */
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (jbvp == NULL)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
else if (i == npath - 1)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (jbvp->type == jbvBinary)
|
|
|
|
{
|
2014-05-07 22:16:19 +02:00
|
|
|
JsonbIterator *it = JsonbIteratorInit((JsonbContainer *) jbvp->val.binary.data);
|
2015-10-12 05:53:35 +02:00
|
|
|
JsonbIteratorToken r;
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
|
|
|
r = JsonbIteratorNext(&it, &tv, true);
|
2014-05-07 22:16:19 +02:00
|
|
|
container = (JsonbContainer *) jbvp->val.binary.data;
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
have_object = r == WJB_BEGIN_OBJECT;
|
|
|
|
have_array = r == WJB_BEGIN_ARRAY;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
have_object = jbvp->type == jbvObject;
|
|
|
|
have_array = jbvp->type == jbvArray;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (as_text)
|
|
|
|
{
|
2014-08-22 19:17:58 +02:00
|
|
|
/* special-case outputs for string and null values */
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
if (jbvp->type == jbvString)
|
2014-08-22 19:17:58 +02:00
|
|
|
PG_RETURN_TEXT_P(cstring_to_text_with_len(jbvp->val.string.val,
|
|
|
|
jbvp->val.string.len));
|
|
|
|
if (jbvp->type == jbvNull)
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
|
|
|
res = JsonbValueToJsonb(jbvp);
|
|
|
|
|
|
|
|
if (as_text)
|
|
|
|
{
|
|
|
|
PG_RETURN_TEXT_P(cstring_to_text(JsonbToCString(NULL,
|
2014-05-07 22:16:19 +02:00
|
|
|
&res->root,
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
VARSIZE(res))));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* not text mode - just hand back the jsonb */
|
|
|
|
PG_RETURN_JSONB(res);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-29 19:12:13 +01:00
|
|
|
/*
|
|
|
|
* SQL function json_array_length(json) -> int
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
json_array_length(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-06-25 20:22:18 +02:00
|
|
|
text *json = PG_GETARG_TEXT_P(0);
|
2013-07-20 12:38:31 +02:00
|
|
|
AlenState *state;
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
JsonLexContext *lex;
|
2013-07-20 12:38:31 +02:00
|
|
|
JsonSemAction *sem;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
lex = makeJsonLexContext(json, false);
|
2013-07-20 12:38:31 +02:00
|
|
|
state = palloc0(sizeof(AlenState));
|
|
|
|
sem = palloc0(sizeof(JsonSemAction));
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* palloc0 does this for us */
|
|
|
|
#if 0
|
|
|
|
state->count = 0;
|
|
|
|
#endif
|
|
|
|
state->lex = lex;
|
|
|
|
|
|
|
|
sem->semstate = (void *) state;
|
|
|
|
sem->object_start = alen_object_start;
|
|
|
|
sem->scalar = alen_scalar;
|
|
|
|
sem->array_element_start = alen_array_element_start;
|
|
|
|
|
|
|
|
pg_parse_json(lex, sem);
|
|
|
|
|
|
|
|
PG_RETURN_INT32(state->count);
|
|
|
|
}
|
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
Datum
|
|
|
|
jsonb_array_length(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Jsonb *jb = PG_GETARG_JSONB(0);
|
|
|
|
|
|
|
|
if (JB_ROOT_IS_SCALAR(jb))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("cannot get array length of a scalar")));
|
|
|
|
else if (!JB_ROOT_IS_ARRAY(jb))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("cannot get array length of a non-array")));
|
|
|
|
|
|
|
|
PG_RETURN_INT32(JB_ROOT_COUNT(jb));
|
|
|
|
}
|
|
|
|
|
2013-03-29 19:12:13 +01:00
|
|
|
/*
|
2014-06-25 20:22:18 +02:00
|
|
|
* These next two checks ensure that the json is an array (since it can't be
|
2013-03-29 19:12:13 +01:00
|
|
|
* a scalar or an object).
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
|
|
|
alen_object_start(void *state)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
AlenState *_state = (AlenState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* json structure check */
|
|
|
|
if (_state->lex->lex_level == 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("cannot get array length of a non-array")));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
alen_scalar(void *state, char *token, JsonTokenType tokentype)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
AlenState *_state = (AlenState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* json structure check */
|
|
|
|
if (_state->lex->lex_level == 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("cannot get array length of a scalar")));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
alen_array_element_start(void *state, bool isnull)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
AlenState *_state = (AlenState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* just count up all the level 1 elements */
|
|
|
|
if (_state->lex->lex_level == 1)
|
|
|
|
_state->count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SQL function json_each and json_each_text
|
|
|
|
*
|
|
|
|
* decompose a json object into key value pairs.
|
|
|
|
*
|
|
|
|
* Unlike json_object_keys() these SRFs operate in materialize mode,
|
|
|
|
* stashing results into a Tuplestore object as they go.
|
|
|
|
* The construction of tuples is done using a temporary memory context
|
|
|
|
* that is cleared out after each tuple is built.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
json_each(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
return each_worker(fcinfo, false);
|
|
|
|
}
|
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
Datum
|
|
|
|
jsonb_each(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-06-26 00:25:22 +02:00
|
|
|
return each_worker_jsonb(fcinfo, "jsonb_each", false);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
}
|
|
|
|
|
2013-03-29 19:12:13 +01:00
|
|
|
Datum
|
|
|
|
json_each_text(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
return each_worker(fcinfo, true);
|
|
|
|
}
|
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
Datum
|
|
|
|
jsonb_each_text(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-06-26 00:25:22 +02:00
|
|
|
return each_worker_jsonb(fcinfo, "jsonb_each_text", true);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
}
|
|
|
|
|
2014-06-25 20:22:18 +02:00
|
|
|
static Datum
|
2014-06-26 00:25:22 +02:00
|
|
|
each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
|
2013-03-29 19:12:13 +01:00
|
|
|
{
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
Jsonb *jb = PG_GETARG_JSONB(0);
|
|
|
|
ReturnSetInfo *rsi;
|
|
|
|
Tuplestorestate *tuple_store;
|
|
|
|
TupleDesc tupdesc;
|
|
|
|
TupleDesc ret_tdesc;
|
|
|
|
MemoryContext old_cxt,
|
|
|
|
tmp_cxt;
|
|
|
|
bool skipNested = false;
|
|
|
|
JsonbIterator *it;
|
|
|
|
JsonbValue v;
|
2015-10-12 05:53:35 +02:00
|
|
|
JsonbIteratorToken r;
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
|
|
|
if (!JB_ROOT_IS_OBJECT(jb))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
2014-06-26 00:25:22 +02:00
|
|
|
errmsg("cannot call %s on a non-object",
|
|
|
|
funcname)));
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
|
|
|
rsi = (ReturnSetInfo *) fcinfo->resultinfo;
|
|
|
|
|
|
|
|
if (!rsi || !IsA(rsi, ReturnSetInfo) ||
|
|
|
|
(rsi->allowedModes & SFRM_Materialize) == 0 ||
|
|
|
|
rsi->expectedDesc == NULL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("set-valued function called in context that "
|
|
|
|
"cannot accept a set")));
|
|
|
|
|
|
|
|
rsi->returnMode = SFRM_Materialize;
|
|
|
|
|
|
|
|
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("function returning record called in context "
|
|
|
|
"that cannot accept type record")));
|
|
|
|
|
|
|
|
old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
|
|
|
|
|
|
|
|
ret_tdesc = CreateTupleDescCopy(tupdesc);
|
|
|
|
BlessTupleDesc(ret_tdesc);
|
|
|
|
tuple_store =
|
|
|
|
tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
|
|
|
|
false, work_mem);
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(old_cxt);
|
|
|
|
|
|
|
|
tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
|
|
|
|
"jsonb_each temporary cxt",
|
Add macros to make AllocSetContextCreate() calls simpler and safer.
I found that half a dozen (nearly 5%) of our AllocSetContextCreate calls
had typos in the context-sizing parameters. While none of these led to
especially significant problems, they did create minor inefficiencies,
and it's now clear that expecting people to copy-and-paste those calls
accurately is not a great idea. Let's reduce the risk of future errors
by introducing single macros that encapsulate the common use-cases.
Three such macros are enough to cover all but two special-purpose contexts;
those two calls can be left as-is, I think.
While this patch doesn't in itself improve matters for third-party
extensions, it doesn't break anything for them either, and they can
gradually adopt the simplified notation over time.
In passing, change TopMemoryContext to use the default allocation
parameters. Formerly it could only be extended 8K at a time. That was
probably reasonable when this code was written; but nowadays we create
many more contexts than we did then, so that it's not unusual to have a
couple hundred K in TopMemoryContext, even without considering various
dubious code that sticks other things there. There seems no good reason
not to let it use growing blocks like most other contexts.
Back-patch to 9.6, mostly because that's still close enough to HEAD that
it's easy to do so, and keeping the branches in sync can be expected to
avoid some future back-patching pain. The bugs fixed by these changes
don't seem to be significant enough to justify fixing them further back.
Discussion: <21072.1472321324@sss.pgh.pa.us>
2016-08-27 23:50:38 +02:00
|
|
|
ALLOCSET_DEFAULT_SIZES);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
2014-05-07 22:16:19 +02:00
|
|
|
it = JsonbIteratorInit(&jb->root);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
|
|
|
while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
|
|
|
|
{
|
|
|
|
skipNested = true;
|
|
|
|
|
|
|
|
if (r == WJB_KEY)
|
|
|
|
{
|
|
|
|
text *key;
|
|
|
|
HeapTuple tuple;
|
|
|
|
Datum values[2];
|
|
|
|
bool nulls[2] = {false, false};
|
|
|
|
|
|
|
|
/* Use the tmp context so we can clean up after each tuple is done */
|
|
|
|
old_cxt = MemoryContextSwitchTo(tmp_cxt);
|
|
|
|
|
2014-04-02 20:30:08 +02:00
|
|
|
key = cstring_to_text_with_len(v.val.string.val, v.val.string.len);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The next thing the iterator fetches should be the value, no
|
|
|
|
* matter what shape it is.
|
|
|
|
*/
|
|
|
|
r = JsonbIteratorNext(&it, &v, skipNested);
|
|
|
|
|
|
|
|
values[0] = PointerGetDatum(key);
|
|
|
|
|
|
|
|
if (as_text)
|
|
|
|
{
|
|
|
|
if (v.type == jbvNull)
|
|
|
|
{
|
|
|
|
/* a json null is an sql null in text mode */
|
|
|
|
nulls[1] = true;
|
|
|
|
values[1] = (Datum) NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
text *sv;
|
|
|
|
|
|
|
|
if (v.type == jbvString)
|
|
|
|
{
|
|
|
|
/* In text mode, scalar strings should be dequoted */
|
2014-04-02 20:30:08 +02:00
|
|
|
sv = cstring_to_text_with_len(v.val.string.val, v.val.string.len);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Turn anything else into a json string */
|
|
|
|
StringInfo jtext = makeStringInfo();
|
|
|
|
Jsonb *jb = JsonbValueToJsonb(&v);
|
|
|
|
|
2014-05-07 22:16:19 +02:00
|
|
|
(void) JsonbToCString(jtext, &jb->root, 0);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
sv = cstring_to_text_with_len(jtext->data, jtext->len);
|
|
|
|
}
|
|
|
|
|
|
|
|
values[1] = PointerGetDatum(sv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Not in text mode, just return the Jsonb */
|
|
|
|
Jsonb *val = JsonbValueToJsonb(&v);
|
|
|
|
|
|
|
|
values[1] = PointerGetDatum(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
tuple = heap_form_tuple(ret_tdesc, values, nulls);
|
|
|
|
|
|
|
|
tuplestore_puttuple(tuple_store, tuple);
|
|
|
|
|
|
|
|
/* clean up and switch back */
|
|
|
|
MemoryContextSwitchTo(old_cxt);
|
|
|
|
MemoryContextReset(tmp_cxt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MemoryContextDelete(tmp_cxt);
|
|
|
|
|
|
|
|
rsi->setResult = tuple_store;
|
|
|
|
rsi->setDesc = ret_tdesc;
|
|
|
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-25 20:22:18 +02:00
|
|
|
static Datum
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
each_worker(FunctionCallInfo fcinfo, bool as_text)
|
|
|
|
{
|
2014-06-25 20:22:18 +02:00
|
|
|
text *json = PG_GETARG_TEXT_P(0);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
JsonLexContext *lex;
|
2013-07-20 12:38:31 +02:00
|
|
|
JsonSemAction *sem;
|
2013-03-29 19:12:13 +01:00
|
|
|
ReturnSetInfo *rsi;
|
|
|
|
MemoryContext old_cxt;
|
|
|
|
TupleDesc tupdesc;
|
2013-07-20 12:38:31 +02:00
|
|
|
EachState *state;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
lex = makeJsonLexContext(json, true);
|
2013-07-20 12:38:31 +02:00
|
|
|
state = palloc0(sizeof(EachState));
|
|
|
|
sem = palloc0(sizeof(JsonSemAction));
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
rsi = (ReturnSetInfo *) fcinfo->resultinfo;
|
|
|
|
|
|
|
|
if (!rsi || !IsA(rsi, ReturnSetInfo) ||
|
|
|
|
(rsi->allowedModes & SFRM_Materialize) == 0 ||
|
|
|
|
rsi->expectedDesc == NULL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("set-valued function called in context that "
|
|
|
|
"cannot accept a set")));
|
|
|
|
|
|
|
|
rsi->returnMode = SFRM_Materialize;
|
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
(void) get_call_result_type(fcinfo, NULL, &tupdesc);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* make these in a sufficiently long-lived memory context */
|
|
|
|
old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
|
|
|
|
|
|
|
|
state->ret_tdesc = CreateTupleDescCopy(tupdesc);
|
|
|
|
BlessTupleDesc(state->ret_tdesc);
|
|
|
|
state->tuple_store =
|
|
|
|
tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
|
|
|
|
false, work_mem);
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(old_cxt);
|
|
|
|
|
|
|
|
sem->semstate = (void *) state;
|
|
|
|
sem->array_start = each_array_start;
|
|
|
|
sem->scalar = each_scalar;
|
|
|
|
sem->object_field_start = each_object_field_start;
|
|
|
|
sem->object_field_end = each_object_field_end;
|
|
|
|
|
|
|
|
state->normalize_results = as_text;
|
|
|
|
state->next_scalar = false;
|
|
|
|
state->lex = lex;
|
|
|
|
state->tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
|
|
|
|
"json_each temporary cxt",
|
Add macros to make AllocSetContextCreate() calls simpler and safer.
I found that half a dozen (nearly 5%) of our AllocSetContextCreate calls
had typos in the context-sizing parameters. While none of these led to
especially significant problems, they did create minor inefficiencies,
and it's now clear that expecting people to copy-and-paste those calls
accurately is not a great idea. Let's reduce the risk of future errors
by introducing single macros that encapsulate the common use-cases.
Three such macros are enough to cover all but two special-purpose contexts;
those two calls can be left as-is, I think.
While this patch doesn't in itself improve matters for third-party
extensions, it doesn't break anything for them either, and they can
gradually adopt the simplified notation over time.
In passing, change TopMemoryContext to use the default allocation
parameters. Formerly it could only be extended 8K at a time. That was
probably reasonable when this code was written; but nowadays we create
many more contexts than we did then, so that it's not unusual to have a
couple hundred K in TopMemoryContext, even without considering various
dubious code that sticks other things there. There seems no good reason
not to let it use growing blocks like most other contexts.
Back-patch to 9.6, mostly because that's still close enough to HEAD that
it's easy to do so, and keeping the branches in sync can be expected to
avoid some future back-patching pain. The bugs fixed by these changes
don't seem to be significant enough to justify fixing them further back.
Discussion: <21072.1472321324@sss.pgh.pa.us>
2016-08-27 23:50:38 +02:00
|
|
|
ALLOCSET_DEFAULT_SIZES);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
pg_parse_json(lex, sem);
|
|
|
|
|
2014-02-06 05:12:51 +01:00
|
|
|
MemoryContextDelete(state->tmp_cxt);
|
2014-02-03 16:40:12 +01:00
|
|
|
|
2013-03-29 19:12:13 +01:00
|
|
|
rsi->setResult = state->tuple_store;
|
|
|
|
rsi->setDesc = state->ret_tdesc;
|
|
|
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
each_object_field_start(void *state, char *fname, bool isnull)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
EachState *_state = (EachState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* save a pointer to where the value starts */
|
|
|
|
if (_state->lex->lex_level == 1)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* next_scalar will be reset in the object_field_end handler, and
|
|
|
|
* since we know the value is a scalar there is no danger of it being
|
|
|
|
* on while recursing down the tree.
|
|
|
|
*/
|
|
|
|
if (_state->normalize_results && _state->lex->token_type == JSON_TOKEN_STRING)
|
|
|
|
_state->next_scalar = true;
|
|
|
|
else
|
|
|
|
_state->result_start = _state->lex->token_start;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
each_object_field_end(void *state, char *fname, bool isnull)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
EachState *_state = (EachState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
MemoryContext old_cxt;
|
|
|
|
int len;
|
|
|
|
text *val;
|
|
|
|
HeapTuple tuple;
|
|
|
|
Datum values[2];
|
|
|
|
bool nulls[2] = {false, false};
|
|
|
|
|
|
|
|
/* skip over nested objects */
|
|
|
|
if (_state->lex->lex_level != 1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* use the tmp context so we can clean up after each tuple is done */
|
|
|
|
old_cxt = MemoryContextSwitchTo(_state->tmp_cxt);
|
|
|
|
|
|
|
|
values[0] = CStringGetTextDatum(fname);
|
|
|
|
|
|
|
|
if (isnull && _state->normalize_results)
|
|
|
|
{
|
|
|
|
nulls[1] = true;
|
2014-06-25 20:22:18 +02:00
|
|
|
values[1] = (Datum) 0;
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
else if (_state->next_scalar)
|
|
|
|
{
|
|
|
|
values[1] = CStringGetTextDatum(_state->normalized_scalar);
|
|
|
|
_state->next_scalar = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
len = _state->lex->prev_token_terminator - _state->result_start;
|
|
|
|
val = cstring_to_text_with_len(_state->result_start, len);
|
|
|
|
values[1] = PointerGetDatum(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
tuple = heap_form_tuple(_state->ret_tdesc, values, nulls);
|
|
|
|
|
|
|
|
tuplestore_puttuple(_state->tuple_store, tuple);
|
|
|
|
|
|
|
|
/* clean up and switch back */
|
|
|
|
MemoryContextSwitchTo(old_cxt);
|
|
|
|
MemoryContextReset(_state->tmp_cxt);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
each_array_start(void *state)
|
|
|
|
{
|
|
|
|
EachState *_state = (EachState *) state;
|
|
|
|
|
|
|
|
/* json structure check */
|
|
|
|
if (_state->lex->lex_level == 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("cannot deconstruct an array as an object")));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
each_scalar(void *state, char *token, JsonTokenType tokentype)
|
|
|
|
{
|
|
|
|
EachState *_state = (EachState *) state;
|
|
|
|
|
|
|
|
/* json structure check */
|
|
|
|
if (_state->lex->lex_level == 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("cannot deconstruct a scalar")));
|
|
|
|
|
|
|
|
/* supply de-escaped value if required */
|
|
|
|
if (_state->next_scalar)
|
|
|
|
_state->normalized_scalar = token;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SQL functions json_array_elements and json_array_elements_text
|
|
|
|
*
|
|
|
|
* get the elements from a json array
|
|
|
|
*
|
|
|
|
* a lot of this processing is similar to the json_each* functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
Datum
|
|
|
|
jsonb_array_elements(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-06-26 00:25:22 +02:00
|
|
|
return elements_worker_jsonb(fcinfo, "jsonb_array_elements", false);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
jsonb_array_elements_text(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-06-26 00:25:22 +02:00
|
|
|
return elements_worker_jsonb(fcinfo, "jsonb_array_elements_text", true);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
}
|
|
|
|
|
2014-06-25 20:22:18 +02:00
|
|
|
static Datum
|
2014-06-26 00:25:22 +02:00
|
|
|
elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname,
|
|
|
|
bool as_text)
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
{
|
|
|
|
Jsonb *jb = PG_GETARG_JSONB(0);
|
|
|
|
ReturnSetInfo *rsi;
|
|
|
|
Tuplestorestate *tuple_store;
|
|
|
|
TupleDesc tupdesc;
|
|
|
|
TupleDesc ret_tdesc;
|
|
|
|
MemoryContext old_cxt,
|
|
|
|
tmp_cxt;
|
|
|
|
bool skipNested = false;
|
|
|
|
JsonbIterator *it;
|
|
|
|
JsonbValue v;
|
2015-10-12 05:53:35 +02:00
|
|
|
JsonbIteratorToken r;
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
|
|
|
if (JB_ROOT_IS_SCALAR(jb))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("cannot extract elements from a scalar")));
|
|
|
|
else if (!JB_ROOT_IS_ARRAY(jb))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("cannot extract elements from an object")));
|
|
|
|
|
|
|
|
rsi = (ReturnSetInfo *) fcinfo->resultinfo;
|
|
|
|
|
|
|
|
if (!rsi || !IsA(rsi, ReturnSetInfo) ||
|
|
|
|
(rsi->allowedModes & SFRM_Materialize) == 0 ||
|
|
|
|
rsi->expectedDesc == NULL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("set-valued function called in context that "
|
|
|
|
"cannot accept a set")));
|
|
|
|
|
|
|
|
rsi->returnMode = SFRM_Materialize;
|
|
|
|
|
|
|
|
/* it's a simple type, so don't use get_call_result_type() */
|
|
|
|
tupdesc = rsi->expectedDesc;
|
|
|
|
|
|
|
|
old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
|
|
|
|
|
|
|
|
ret_tdesc = CreateTupleDescCopy(tupdesc);
|
|
|
|
BlessTupleDesc(ret_tdesc);
|
|
|
|
tuple_store =
|
|
|
|
tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
|
|
|
|
false, work_mem);
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(old_cxt);
|
|
|
|
|
|
|
|
tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
|
2014-06-25 20:22:18 +02:00
|
|
|
"jsonb_array_elements temporary cxt",
|
Add macros to make AllocSetContextCreate() calls simpler and safer.
I found that half a dozen (nearly 5%) of our AllocSetContextCreate calls
had typos in the context-sizing parameters. While none of these led to
especially significant problems, they did create minor inefficiencies,
and it's now clear that expecting people to copy-and-paste those calls
accurately is not a great idea. Let's reduce the risk of future errors
by introducing single macros that encapsulate the common use-cases.
Three such macros are enough to cover all but two special-purpose contexts;
those two calls can be left as-is, I think.
While this patch doesn't in itself improve matters for third-party
extensions, it doesn't break anything for them either, and they can
gradually adopt the simplified notation over time.
In passing, change TopMemoryContext to use the default allocation
parameters. Formerly it could only be extended 8K at a time. That was
probably reasonable when this code was written; but nowadays we create
many more contexts than we did then, so that it's not unusual to have a
couple hundred K in TopMemoryContext, even without considering various
dubious code that sticks other things there. There seems no good reason
not to let it use growing blocks like most other contexts.
Back-patch to 9.6, mostly because that's still close enough to HEAD that
it's easy to do so, and keeping the branches in sync can be expected to
avoid some future back-patching pain. The bugs fixed by these changes
don't seem to be significant enough to justify fixing them further back.
Discussion: <21072.1472321324@sss.pgh.pa.us>
2016-08-27 23:50:38 +02:00
|
|
|
ALLOCSET_DEFAULT_SIZES);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
2014-05-07 22:16:19 +02:00
|
|
|
it = JsonbIteratorInit(&jb->root);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
|
|
|
while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
|
|
|
|
{
|
|
|
|
skipNested = true;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
if (r == WJB_ELEM)
|
|
|
|
{
|
|
|
|
HeapTuple tuple;
|
|
|
|
Datum values[1];
|
|
|
|
bool nulls[1] = {false};
|
2013-03-29 19:12:13 +01:00
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
/* use the tmp context so we can clean up after each tuple is done */
|
|
|
|
old_cxt = MemoryContextSwitchTo(tmp_cxt);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
if (!as_text)
|
|
|
|
{
|
|
|
|
Jsonb *val = JsonbValueToJsonb(&v);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
values[0] = PointerGetDatum(val);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (v.type == jbvNull)
|
|
|
|
{
|
|
|
|
/* a json null is an sql null in text mode */
|
|
|
|
nulls[0] = true;
|
|
|
|
values[0] = (Datum) NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
text *sv;
|
|
|
|
|
|
|
|
if (v.type == jbvString)
|
|
|
|
{
|
|
|
|
/* in text mode scalar strings should be dequoted */
|
2014-04-02 20:30:08 +02:00
|
|
|
sv = cstring_to_text_with_len(v.val.string.val, v.val.string.len);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* turn anything else into a json string */
|
|
|
|
StringInfo jtext = makeStringInfo();
|
|
|
|
Jsonb *jb = JsonbValueToJsonb(&v);
|
|
|
|
|
2014-05-07 22:16:19 +02:00
|
|
|
(void) JsonbToCString(jtext, &jb->root, 0);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
sv = cstring_to_text_with_len(jtext->data, jtext->len);
|
|
|
|
}
|
|
|
|
|
|
|
|
values[0] = PointerGetDatum(sv);
|
|
|
|
}
|
|
|
|
}
|
2013-03-29 19:12:13 +01:00
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
tuple = heap_form_tuple(ret_tdesc, values, nulls);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
tuplestore_puttuple(tuple_store, tuple);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
/* clean up and switch back */
|
|
|
|
MemoryContextSwitchTo(old_cxt);
|
|
|
|
MemoryContextReset(tmp_cxt);
|
|
|
|
}
|
|
|
|
}
|
2013-03-29 19:12:13 +01:00
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
MemoryContextDelete(tmp_cxt);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
rsi->setResult = tuple_store;
|
|
|
|
rsi->setDesc = ret_tdesc;
|
|
|
|
|
|
|
|
PG_RETURN_NULL();
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
json_array_elements(PG_FUNCTION_ARGS)
|
2014-01-29 21:39:01 +01:00
|
|
|
{
|
2014-06-26 00:25:22 +02:00
|
|
|
return elements_worker(fcinfo, "json_array_elements", false);
|
2014-01-29 21:39:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
json_array_elements_text(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-06-26 00:25:22 +02:00
|
|
|
return elements_worker(fcinfo, "json_array_elements_text", true);
|
2014-01-29 21:39:01 +01:00
|
|
|
}
|
|
|
|
|
2014-06-25 20:22:18 +02:00
|
|
|
static Datum
|
2014-06-26 00:25:22 +02:00
|
|
|
elements_worker(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
|
2013-03-29 19:12:13 +01:00
|
|
|
{
|
|
|
|
text *json = PG_GETARG_TEXT_P(0);
|
|
|
|
|
2014-01-29 21:39:01 +01:00
|
|
|
/* elements only needs escaped strings when as_text */
|
|
|
|
JsonLexContext *lex = makeJsonLexContext(json, as_text);
|
2013-07-20 12:38:31 +02:00
|
|
|
JsonSemAction *sem;
|
2013-03-29 19:12:13 +01:00
|
|
|
ReturnSetInfo *rsi;
|
|
|
|
MemoryContext old_cxt;
|
|
|
|
TupleDesc tupdesc;
|
2013-07-20 12:38:31 +02:00
|
|
|
ElementsState *state;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
2013-07-20 12:38:31 +02:00
|
|
|
state = palloc0(sizeof(ElementsState));
|
|
|
|
sem = palloc0(sizeof(JsonSemAction));
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
rsi = (ReturnSetInfo *) fcinfo->resultinfo;
|
|
|
|
|
|
|
|
if (!rsi || !IsA(rsi, ReturnSetInfo) ||
|
|
|
|
(rsi->allowedModes & SFRM_Materialize) == 0 ||
|
|
|
|
rsi->expectedDesc == NULL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("set-valued function called in context that "
|
|
|
|
"cannot accept a set")));
|
|
|
|
|
|
|
|
rsi->returnMode = SFRM_Materialize;
|
|
|
|
|
|
|
|
/* it's a simple type, so don't use get_call_result_type() */
|
|
|
|
tupdesc = rsi->expectedDesc;
|
|
|
|
|
|
|
|
/* make these in a sufficiently long-lived memory context */
|
|
|
|
old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
|
|
|
|
|
|
|
|
state->ret_tdesc = CreateTupleDescCopy(tupdesc);
|
|
|
|
BlessTupleDesc(state->ret_tdesc);
|
|
|
|
state->tuple_store =
|
|
|
|
tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
|
|
|
|
false, work_mem);
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(old_cxt);
|
|
|
|
|
|
|
|
sem->semstate = (void *) state;
|
|
|
|
sem->object_start = elements_object_start;
|
|
|
|
sem->scalar = elements_scalar;
|
|
|
|
sem->array_element_start = elements_array_element_start;
|
|
|
|
sem->array_element_end = elements_array_element_end;
|
|
|
|
|
2014-06-26 00:25:22 +02:00
|
|
|
state->function_name = funcname;
|
2014-01-29 21:39:01 +01:00
|
|
|
state->normalize_results = as_text;
|
|
|
|
state->next_scalar = false;
|
2013-03-29 19:12:13 +01:00
|
|
|
state->lex = lex;
|
|
|
|
state->tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
|
|
|
|
"json_array_elements temporary cxt",
|
Add macros to make AllocSetContextCreate() calls simpler and safer.
I found that half a dozen (nearly 5%) of our AllocSetContextCreate calls
had typos in the context-sizing parameters. While none of these led to
especially significant problems, they did create minor inefficiencies,
and it's now clear that expecting people to copy-and-paste those calls
accurately is not a great idea. Let's reduce the risk of future errors
by introducing single macros that encapsulate the common use-cases.
Three such macros are enough to cover all but two special-purpose contexts;
those two calls can be left as-is, I think.
While this patch doesn't in itself improve matters for third-party
extensions, it doesn't break anything for them either, and they can
gradually adopt the simplified notation over time.
In passing, change TopMemoryContext to use the default allocation
parameters. Formerly it could only be extended 8K at a time. That was
probably reasonable when this code was written; but nowadays we create
many more contexts than we did then, so that it's not unusual to have a
couple hundred K in TopMemoryContext, even without considering various
dubious code that sticks other things there. There seems no good reason
not to let it use growing blocks like most other contexts.
Back-patch to 9.6, mostly because that's still close enough to HEAD that
it's easy to do so, and keeping the branches in sync can be expected to
avoid some future back-patching pain. The bugs fixed by these changes
don't seem to be significant enough to justify fixing them further back.
Discussion: <21072.1472321324@sss.pgh.pa.us>
2016-08-27 23:50:38 +02:00
|
|
|
ALLOCSET_DEFAULT_SIZES);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
pg_parse_json(lex, sem);
|
|
|
|
|
2014-02-06 05:12:51 +01:00
|
|
|
MemoryContextDelete(state->tmp_cxt);
|
2014-02-03 16:40:12 +01:00
|
|
|
|
2013-03-29 19:12:13 +01:00
|
|
|
rsi->setResult = state->tuple_store;
|
|
|
|
rsi->setDesc = state->ret_tdesc;
|
|
|
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
elements_array_element_start(void *state, bool isnull)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
ElementsState *_state = (ElementsState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* save a pointer to where the value starts */
|
|
|
|
if (_state->lex->lex_level == 1)
|
2014-01-29 21:39:01 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* next_scalar will be reset in the array_element_end handler, and
|
|
|
|
* since we know the value is a scalar there is no danger of it being
|
|
|
|
* on while recursing down the tree.
|
|
|
|
*/
|
|
|
|
if (_state->normalize_results && _state->lex->token_type == JSON_TOKEN_STRING)
|
|
|
|
_state->next_scalar = true;
|
|
|
|
else
|
|
|
|
_state->result_start = _state->lex->token_start;
|
|
|
|
}
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
elements_array_element_end(void *state, bool isnull)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
ElementsState *_state = (ElementsState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
MemoryContext old_cxt;
|
|
|
|
int len;
|
|
|
|
text *val;
|
|
|
|
HeapTuple tuple;
|
|
|
|
Datum values[1];
|
2014-05-06 18:12:18 +02:00
|
|
|
bool nulls[1] = {false};
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* skip over nested objects */
|
|
|
|
if (_state->lex->lex_level != 1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* use the tmp context so we can clean up after each tuple is done */
|
|
|
|
old_cxt = MemoryContextSwitchTo(_state->tmp_cxt);
|
|
|
|
|
2014-01-29 21:39:01 +01:00
|
|
|
if (isnull && _state->normalize_results)
|
|
|
|
{
|
|
|
|
nulls[0] = true;
|
|
|
|
values[0] = (Datum) NULL;
|
|
|
|
}
|
|
|
|
else if (_state->next_scalar)
|
|
|
|
{
|
|
|
|
values[0] = CStringGetTextDatum(_state->normalized_scalar);
|
|
|
|
_state->next_scalar = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
len = _state->lex->prev_token_terminator - _state->result_start;
|
|
|
|
val = cstring_to_text_with_len(_state->result_start, len);
|
|
|
|
values[0] = PointerGetDatum(val);
|
|
|
|
}
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
tuple = heap_form_tuple(_state->ret_tdesc, values, nulls);
|
|
|
|
|
|
|
|
tuplestore_puttuple(_state->tuple_store, tuple);
|
|
|
|
|
|
|
|
/* clean up and switch back */
|
|
|
|
MemoryContextSwitchTo(old_cxt);
|
|
|
|
MemoryContextReset(_state->tmp_cxt);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
elements_object_start(void *state)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
ElementsState *_state = (ElementsState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* json structure check */
|
|
|
|
if (_state->lex->lex_level == 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
2014-06-26 00:25:22 +02:00
|
|
|
errmsg("cannot call %s on a non-array",
|
|
|
|
_state->function_name)));
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
elements_scalar(void *state, char *token, JsonTokenType tokentype)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
ElementsState *_state = (ElementsState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* json structure check */
|
|
|
|
if (_state->lex->lex_level == 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
2014-06-26 00:25:22 +02:00
|
|
|
errmsg("cannot call %s on a scalar",
|
|
|
|
_state->function_name)));
|
2013-03-29 19:12:13 +01:00
|
|
|
|
2014-01-29 21:39:01 +01:00
|
|
|
/* supply de-escaped value if required */
|
|
|
|
if (_state->next_scalar)
|
|
|
|
_state->normalized_scalar = token;
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SQL function json_populate_record
|
|
|
|
*
|
|
|
|
* set fields in a record from the argument json
|
|
|
|
*
|
|
|
|
* Code adapted shamelessly from hstore's populate_record
|
|
|
|
* which is in turn partly adapted from record_out.
|
|
|
|
*
|
|
|
|
* The json is decomposed into a hash table, in which each
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
* field in the record is then looked up by name. For jsonb
|
|
|
|
* we fetch the values direct from the object.
|
2013-03-29 19:12:13 +01:00
|
|
|
*/
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
Datum
|
|
|
|
jsonb_populate_record(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-06-26 00:25:22 +02:00
|
|
|
return populate_record_worker(fcinfo, "jsonb_populate_record", true);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
}
|
|
|
|
|
2014-03-26 15:18:24 +01:00
|
|
|
Datum
|
|
|
|
jsonb_to_record(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-06-26 00:25:22 +02:00
|
|
|
return populate_record_worker(fcinfo, "jsonb_to_record", false);
|
2014-03-26 15:18:24 +01:00
|
|
|
}
|
|
|
|
|
2013-03-29 19:12:13 +01:00
|
|
|
Datum
|
|
|
|
json_populate_record(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-06-26 00:25:22 +02:00
|
|
|
return populate_record_worker(fcinfo, "json_populate_record", true);
|
2014-01-28 23:48:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
json_to_record(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-06-26 00:25:22 +02:00
|
|
|
return populate_record_worker(fcinfo, "json_to_record", false);
|
2014-01-28 23:48:21 +01:00
|
|
|
}
|
|
|
|
|
2014-06-25 20:22:18 +02:00
|
|
|
static Datum
|
2014-06-26 00:25:22 +02:00
|
|
|
populate_record_worker(FunctionCallInfo fcinfo, const char *funcname,
|
|
|
|
bool have_record_arg)
|
2014-01-28 23:48:21 +01:00
|
|
|
{
|
2014-05-06 18:12:18 +02:00
|
|
|
int json_arg_num = have_record_arg ? 1 : 0;
|
2014-03-26 02:20:54 +01:00
|
|
|
Oid jtype = get_fn_expr_argtype(fcinfo->flinfo, json_arg_num);
|
2013-04-15 22:20:21 +02:00
|
|
|
text *json;
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
Jsonb *jb = NULL;
|
|
|
|
HTAB *json_hash = NULL;
|
2014-01-28 23:48:21 +01:00
|
|
|
HeapTupleHeader rec = NULL;
|
2014-01-30 00:54:14 +01:00
|
|
|
Oid tupType = InvalidOid;
|
|
|
|
int32 tupTypmod = -1;
|
2013-03-29 19:12:13 +01:00
|
|
|
TupleDesc tupdesc;
|
|
|
|
HeapTupleData tuple;
|
|
|
|
HeapTuple rettuple;
|
|
|
|
RecordIOData *my_extra;
|
|
|
|
int ncolumns;
|
|
|
|
int i;
|
|
|
|
Datum *values;
|
|
|
|
bool *nulls;
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
|
|
|
Assert(jtype == JSONOID || jtype == JSONBOID);
|
|
|
|
|
2014-01-28 23:48:21 +01:00
|
|
|
if (have_record_arg)
|
|
|
|
{
|
2014-05-06 18:12:18 +02:00
|
|
|
Oid argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
2014-01-28 23:48:21 +01:00
|
|
|
if (!type_is_rowtype(argtype))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
2014-06-26 00:25:22 +02:00
|
|
|
errmsg("first argument of %s must be a row type",
|
|
|
|
funcname)));
|
2013-03-29 19:12:13 +01:00
|
|
|
|
2014-01-28 23:48:21 +01:00
|
|
|
if (PG_ARGISNULL(0))
|
|
|
|
{
|
|
|
|
if (PG_ARGISNULL(1))
|
|
|
|
PG_RETURN_NULL();
|
2013-03-29 19:12:13 +01:00
|
|
|
|
2014-01-28 23:48:21 +01:00
|
|
|
/*
|
|
|
|
* have no tuple to look at, so the only source of type info is
|
|
|
|
* the argtype. The lookup_rowtype_tupdesc call below will error
|
|
|
|
* out if we don't have a known composite type oid here.
|
|
|
|
*/
|
|
|
|
tupType = argtype;
|
|
|
|
tupTypmod = -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rec = PG_GETARG_HEAPTUPLEHEADER(0);
|
|
|
|
|
|
|
|
if (PG_ARGISNULL(1))
|
|
|
|
PG_RETURN_POINTER(rec);
|
|
|
|
|
|
|
|
/* Extract type info from the tuple itself */
|
|
|
|
tupType = HeapTupleHeaderGetTypeId(rec);
|
|
|
|
tupTypmod = HeapTupleHeaderGetTypMod(rec);
|
|
|
|
}
|
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
else
|
2014-06-25 20:22:18 +02:00
|
|
|
{
|
|
|
|
/* json{b}_to_record case */
|
2014-01-28 23:48:21 +01:00
|
|
|
if (PG_ARGISNULL(0))
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
2014-02-26 16:47:09 +01:00
|
|
|
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("function returning record called in context "
|
|
|
|
"that cannot accept type record"),
|
|
|
|
errhint("Try calling the function in the FROM clause "
|
|
|
|
"using a column definition list.")));
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
if (jtype == JSONOID)
|
2014-01-28 23:48:21 +01:00
|
|
|
{
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
/* just get the text */
|
2014-03-26 02:20:54 +01:00
|
|
|
json = PG_GETARG_TEXT_P(json_arg_num);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
2014-06-29 19:50:58 +02:00
|
|
|
json_hash = get_json_object_as_hash(json, funcname);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
2014-01-28 23:48:21 +01:00
|
|
|
/*
|
|
|
|
* if the input json is empty, we can only skip the rest if we were
|
|
|
|
* passed in a non-null record, since otherwise there may be issues
|
|
|
|
* with domain nulls.
|
|
|
|
*/
|
|
|
|
if (hash_get_num_entries(json_hash) == 0 && rec)
|
2014-06-25 06:22:40 +02:00
|
|
|
{
|
|
|
|
hash_destroy(json_hash);
|
2015-05-04 18:38:58 +02:00
|
|
|
ReleaseTupleDesc(tupdesc);
|
2014-01-28 23:48:21 +01:00
|
|
|
PG_RETURN_POINTER(rec);
|
2014-06-25 06:22:40 +02:00
|
|
|
}
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-03-26 02:20:54 +01:00
|
|
|
jb = PG_GETARG_JSONB(json_arg_num);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
/* same logic as for json */
|
2015-05-04 18:38:58 +02:00
|
|
|
if (JB_ROOT_COUNT(jb) == 0 && rec)
|
|
|
|
{
|
|
|
|
ReleaseTupleDesc(tupdesc);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
PG_RETURN_POINTER(rec);
|
2015-05-04 18:38:58 +02:00
|
|
|
}
|
2014-01-28 23:48:21 +01:00
|
|
|
}
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
ncolumns = tupdesc->natts;
|
|
|
|
|
|
|
|
if (rec)
|
|
|
|
{
|
|
|
|
/* Build a temporary HeapTuple control structure */
|
|
|
|
tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
|
|
|
|
ItemPointerSetInvalid(&(tuple.t_self));
|
|
|
|
tuple.t_tableOid = InvalidOid;
|
|
|
|
tuple.t_data = rec;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We arrange to look up the needed I/O info just once per series of
|
|
|
|
* calls, assuming the record type doesn't change underneath us.
|
|
|
|
*/
|
|
|
|
my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
|
|
|
|
if (my_extra == NULL ||
|
|
|
|
my_extra->ncolumns != ncolumns)
|
|
|
|
{
|
|
|
|
fcinfo->flinfo->fn_extra =
|
|
|
|
MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
|
2015-02-20 23:03:12 +01:00
|
|
|
offsetof(RecordIOData, columns) +
|
|
|
|
ncolumns * sizeof(ColumnIOData));
|
2013-03-29 19:12:13 +01:00
|
|
|
my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
|
|
|
|
my_extra->record_type = InvalidOid;
|
|
|
|
my_extra->record_typmod = 0;
|
2014-03-26 23:20:56 +01:00
|
|
|
my_extra->ncolumns = ncolumns;
|
|
|
|
MemSet(my_extra->columns, 0, sizeof(ColumnIOData) * ncolumns);
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
|
2014-01-28 23:48:21 +01:00
|
|
|
if (have_record_arg && (my_extra->record_type != tupType ||
|
|
|
|
my_extra->record_typmod != tupTypmod))
|
2013-03-29 19:12:13 +01:00
|
|
|
{
|
|
|
|
MemSet(my_extra, 0,
|
2015-02-20 23:03:12 +01:00
|
|
|
offsetof(RecordIOData, columns) +
|
|
|
|
ncolumns * sizeof(ColumnIOData));
|
2013-03-29 19:12:13 +01:00
|
|
|
my_extra->record_type = tupType;
|
|
|
|
my_extra->record_typmod = tupTypmod;
|
|
|
|
my_extra->ncolumns = ncolumns;
|
|
|
|
}
|
|
|
|
|
|
|
|
values = (Datum *) palloc(ncolumns * sizeof(Datum));
|
|
|
|
nulls = (bool *) palloc(ncolumns * sizeof(bool));
|
|
|
|
|
|
|
|
if (rec)
|
|
|
|
{
|
|
|
|
/* Break down the tuple into fields */
|
|
|
|
heap_deform_tuple(&tuple, tupdesc, values, nulls);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = 0; i < ncolumns; ++i)
|
|
|
|
{
|
|
|
|
values[i] = (Datum) 0;
|
|
|
|
nulls[i] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ncolumns; ++i)
|
|
|
|
{
|
|
|
|
ColumnIOData *column_info = &my_extra->columns[i];
|
|
|
|
Oid column_type = tupdesc->attrs[i]->atttypid;
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
JsonbValue *v = NULL;
|
|
|
|
JsonHashEntry *hashentry = NULL;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* Ignore dropped columns in datatype */
|
|
|
|
if (tupdesc->attrs[i]->attisdropped)
|
|
|
|
{
|
|
|
|
nulls[i] = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
if (jtype == JSONOID)
|
|
|
|
{
|
2014-06-25 20:22:18 +02:00
|
|
|
hashentry = hash_search(json_hash,
|
|
|
|
NameStr(tupdesc->attrs[i]->attname),
|
|
|
|
HASH_FIND, NULL);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char *key = NameStr(tupdesc->attrs[i]->attname);
|
|
|
|
|
2014-05-07 22:16:19 +02:00
|
|
|
v = findJsonbValueFromContainerLen(&jb->root, JB_FOBJECT, key,
|
|
|
|
strlen(key));
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
}
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* we can't just skip here if the key wasn't found since we might have
|
|
|
|
* a domain to deal with. If we were passed in a non-null record
|
|
|
|
* datum, we assume that the existing values are valid (if they're
|
|
|
|
* not, then it's not our fault), but if we were passed in a null,
|
|
|
|
* then every field which we don't populate needs to be run through
|
|
|
|
* the input function just in case it's a domain type.
|
|
|
|
*/
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
if (((jtype == JSONOID && hashentry == NULL) ||
|
|
|
|
(jtype == JSONBOID && v == NULL)) && rec)
|
2013-03-29 19:12:13 +01:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Prepare to convert the column value from text
|
|
|
|
*/
|
|
|
|
if (column_info->column_type != column_type)
|
|
|
|
{
|
|
|
|
getTypeInputInfo(column_type,
|
|
|
|
&column_info->typiofunc,
|
|
|
|
&column_info->typioparam);
|
|
|
|
fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
|
|
|
|
fcinfo->flinfo->fn_mcxt);
|
|
|
|
column_info->column_type = column_type;
|
|
|
|
}
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
if ((jtype == JSONOID && (hashentry == NULL || hashentry->isnull)) ||
|
|
|
|
(jtype == JSONBOID && (v == NULL || v->type == jbvNull)))
|
2013-03-29 19:12:13 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* need InputFunctionCall to happen even for nulls, so that domain
|
|
|
|
* checks are done
|
|
|
|
*/
|
|
|
|
values[i] = InputFunctionCall(&column_info->proc, NULL,
|
|
|
|
column_info->typioparam,
|
|
|
|
tupdesc->attrs[i]->atttypmod);
|
|
|
|
nulls[i] = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
char *s = NULL;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
if (jtype == JSONOID)
|
|
|
|
{
|
|
|
|
/* already done the hard work in the json case */
|
|
|
|
s = hashentry->val;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (v->type == jbvString)
|
2014-04-02 20:30:08 +02:00
|
|
|
s = pnstrdup(v->val.string.val, v->val.string.len);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
else if (v->type == jbvBool)
|
2014-04-02 20:30:08 +02:00
|
|
|
s = pnstrdup((v->val.boolean) ? "t" : "f", 1);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
else if (v->type == jbvNumeric)
|
|
|
|
s = DatumGetCString(DirectFunctionCall1(numeric_out,
|
2014-05-06 18:12:18 +02:00
|
|
|
PointerGetDatum(v->val.numeric)));
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
else if (v->type == jbvBinary)
|
2014-05-07 22:16:19 +02:00
|
|
|
s = JsonbToCString(NULL, (JsonbContainer *) v->val.binary.data, v->val.binary.len);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
else
|
2014-06-26 00:25:22 +02:00
|
|
|
elog(ERROR, "unrecognized jsonb type: %d", (int) v->type);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
values[i] = InputFunctionCall(&column_info->proc, s,
|
2013-03-29 19:12:13 +01:00
|
|
|
column_info->typioparam,
|
|
|
|
tupdesc->attrs[i]->atttypmod);
|
|
|
|
nulls[i] = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rettuple = heap_form_tuple(tupdesc, values, nulls);
|
|
|
|
|
|
|
|
ReleaseTupleDesc(tupdesc);
|
|
|
|
|
2014-06-25 06:22:40 +02:00
|
|
|
if (json_hash)
|
|
|
|
hash_destroy(json_hash);
|
|
|
|
|
2013-03-29 19:12:13 +01:00
|
|
|
PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get_json_object_as_hash
|
|
|
|
*
|
|
|
|
* decompose a json object into a hash table.
|
|
|
|
*/
|
|
|
|
static HTAB *
|
2014-06-29 19:50:58 +02:00
|
|
|
get_json_object_as_hash(text *json, const char *funcname)
|
2013-03-29 19:12:13 +01:00
|
|
|
{
|
|
|
|
HASHCTL ctl;
|
|
|
|
HTAB *tab;
|
2013-07-20 12:38:31 +02:00
|
|
|
JHashState *state;
|
2013-03-29 19:12:13 +01:00
|
|
|
JsonLexContext *lex = makeJsonLexContext(json, true);
|
2013-07-20 12:38:31 +02:00
|
|
|
JsonSemAction *sem;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
memset(&ctl, 0, sizeof(ctl));
|
|
|
|
ctl.keysize = NAMEDATALEN;
|
2013-07-20 12:38:31 +02:00
|
|
|
ctl.entrysize = sizeof(JsonHashEntry);
|
2013-03-29 19:12:13 +01:00
|
|
|
ctl.hcxt = CurrentMemoryContext;
|
|
|
|
tab = hash_create("json object hashtable",
|
|
|
|
100,
|
|
|
|
&ctl,
|
|
|
|
HASH_ELEM | HASH_CONTEXT);
|
|
|
|
|
2013-07-20 12:38:31 +02:00
|
|
|
state = palloc0(sizeof(JHashState));
|
|
|
|
sem = palloc0(sizeof(JsonSemAction));
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
state->function_name = funcname;
|
|
|
|
state->hash = tab;
|
|
|
|
state->lex = lex;
|
|
|
|
|
|
|
|
sem->semstate = (void *) state;
|
|
|
|
sem->array_start = hash_array_start;
|
|
|
|
sem->scalar = hash_scalar;
|
|
|
|
sem->object_field_start = hash_object_field_start;
|
|
|
|
sem->object_field_end = hash_object_field_end;
|
|
|
|
|
|
|
|
pg_parse_json(lex, sem);
|
|
|
|
|
|
|
|
return tab;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
hash_object_field_start(void *state, char *fname, bool isnull)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
JHashState *_state = (JHashState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
if (_state->lex->lex_level > 1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (_state->lex->token_type == JSON_TOKEN_ARRAY_START ||
|
|
|
|
_state->lex->token_type == JSON_TOKEN_OBJECT_START)
|
|
|
|
{
|
2014-06-29 19:50:58 +02:00
|
|
|
/* remember start position of the whole text of the subobject */
|
2013-03-29 19:12:13 +01:00
|
|
|
_state->save_json_start = _state->lex->token_start;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* must be a scalar */
|
|
|
|
_state->save_json_start = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
hash_object_field_end(void *state, char *fname, bool isnull)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
JHashState *_state = (JHashState *) state;
|
|
|
|
JsonHashEntry *hashentry;
|
2013-03-29 19:12:13 +01:00
|
|
|
bool found;
|
|
|
|
|
|
|
|
/*
|
2014-06-25 20:22:18 +02:00
|
|
|
* Ignore nested fields.
|
2013-03-29 19:12:13 +01:00
|
|
|
*/
|
2016-03-03 05:31:39 +01:00
|
|
|
if (_state->lex->lex_level > 1)
|
2013-03-29 19:12:13 +01:00
|
|
|
return;
|
|
|
|
|
2014-06-25 20:22:18 +02:00
|
|
|
/*
|
|
|
|
* Ignore field names >= NAMEDATALEN - they can't match a record field.
|
|
|
|
* (Note: without this test, the hash code would truncate the string at
|
|
|
|
* NAMEDATALEN-1, and could then match against a similarly-truncated
|
|
|
|
* record field name. That would be a reasonable behavior, but this code
|
|
|
|
* has previously insisted on exact equality, so we keep this behavior.)
|
|
|
|
*/
|
|
|
|
if (strlen(fname) >= NAMEDATALEN)
|
|
|
|
return;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
2014-06-25 20:22:18 +02:00
|
|
|
hashentry = hash_search(_state->hash, fname, HASH_ENTER, &found);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* found being true indicates a duplicate. We don't do anything about
|
|
|
|
* that, a later field with the same name overrides the earlier field.
|
|
|
|
*/
|
|
|
|
|
|
|
|
hashentry->isnull = isnull;
|
|
|
|
if (_state->save_json_start != NULL)
|
|
|
|
{
|
|
|
|
int len = _state->lex->prev_token_terminator - _state->save_json_start;
|
|
|
|
char *val = palloc((len + 1) * sizeof(char));
|
|
|
|
|
|
|
|
memcpy(val, _state->save_json_start, len);
|
|
|
|
val[len] = '\0';
|
|
|
|
hashentry->val = val;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* must have had a scalar instead */
|
|
|
|
hashentry->val = _state->saved_scalar;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
hash_array_start(void *state)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
JHashState *_state = (JHashState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
if (_state->lex->lex_level == 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("cannot call %s on an array", _state->function_name)));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
hash_scalar(void *state, char *token, JsonTokenType tokentype)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
JHashState *_state = (JHashState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
if (_state->lex->lex_level == 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("cannot call %s on a scalar", _state->function_name)));
|
|
|
|
|
|
|
|
if (_state->lex->lex_level == 1)
|
|
|
|
_state->saved_scalar = token;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SQL function json_populate_recordset
|
|
|
|
*
|
|
|
|
* set fields in a set of records from the argument json,
|
|
|
|
* which must be an array of objects.
|
|
|
|
*
|
|
|
|
* similar to json_populate_record, but the tuple-building code
|
|
|
|
* is pushed down into the semantic action handlers so it's done
|
|
|
|
* per object in the array.
|
|
|
|
*/
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
Datum
|
|
|
|
jsonb_populate_recordset(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-06-26 00:25:22 +02:00
|
|
|
return populate_recordset_worker(fcinfo, "jsonb_populate_recordset", true);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
}
|
|
|
|
|
2014-03-26 15:18:24 +01:00
|
|
|
Datum
|
|
|
|
jsonb_to_recordset(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-06-26 00:25:22 +02:00
|
|
|
return populate_recordset_worker(fcinfo, "jsonb_to_recordset", false);
|
2014-03-26 15:18:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
json_populate_recordset(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-06-26 00:25:22 +02:00
|
|
|
return populate_recordset_worker(fcinfo, "json_populate_recordset", true);
|
2014-03-26 15:18:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
json_to_recordset(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-06-26 00:25:22 +02:00
|
|
|
return populate_recordset_worker(fcinfo, "json_to_recordset", false);
|
2014-03-26 15:18:24 +01:00
|
|
|
}
|
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
static void
|
2014-05-06 18:12:18 +02:00
|
|
|
make_row_from_rec_and_jsonb(Jsonb *element, PopulateRecordsetState *state)
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
{
|
|
|
|
Datum *values;
|
|
|
|
bool *nulls;
|
|
|
|
int i;
|
|
|
|
RecordIOData *my_extra = state->my_extra;
|
|
|
|
int ncolumns = my_extra->ncolumns;
|
|
|
|
TupleDesc tupdesc = state->ret_tdesc;
|
|
|
|
HeapTupleHeader rec = state->rec;
|
|
|
|
HeapTuple rettuple;
|
|
|
|
|
|
|
|
values = (Datum *) palloc(ncolumns * sizeof(Datum));
|
|
|
|
nulls = (bool *) palloc(ncolumns * sizeof(bool));
|
|
|
|
|
|
|
|
if (state->rec)
|
|
|
|
{
|
|
|
|
HeapTupleData tuple;
|
|
|
|
|
|
|
|
/* Build a temporary HeapTuple control structure */
|
|
|
|
tuple.t_len = HeapTupleHeaderGetDatumLength(state->rec);
|
|
|
|
ItemPointerSetInvalid(&(tuple.t_self));
|
|
|
|
tuple.t_tableOid = InvalidOid;
|
|
|
|
tuple.t_data = state->rec;
|
|
|
|
|
|
|
|
/* Break down the tuple into fields */
|
|
|
|
heap_deform_tuple(&tuple, tupdesc, values, nulls);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = 0; i < ncolumns; ++i)
|
|
|
|
{
|
|
|
|
values[i] = (Datum) 0;
|
|
|
|
nulls[i] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ncolumns; ++i)
|
|
|
|
{
|
|
|
|
ColumnIOData *column_info = &my_extra->columns[i];
|
|
|
|
Oid column_type = tupdesc->attrs[i]->atttypid;
|
|
|
|
JsonbValue *v = NULL;
|
|
|
|
char *key;
|
|
|
|
|
|
|
|
/* Ignore dropped columns in datatype */
|
|
|
|
if (tupdesc->attrs[i]->attisdropped)
|
|
|
|
{
|
|
|
|
nulls[i] = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
key = NameStr(tupdesc->attrs[i]->attname);
|
|
|
|
|
2014-05-07 22:16:19 +02:00
|
|
|
v = findJsonbValueFromContainerLen(&element->root, JB_FOBJECT,
|
|
|
|
key, strlen(key));
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We can't just skip here if the key wasn't found since we might have
|
|
|
|
* a domain to deal with. If we were passed in a non-null record
|
|
|
|
* datum, we assume that the existing values are valid (if they're
|
|
|
|
* not, then it's not our fault), but if we were passed in a null,
|
|
|
|
* then every field which we don't populate needs to be run through
|
|
|
|
* the input function just in case it's a domain type.
|
|
|
|
*/
|
|
|
|
if (v == NULL && rec)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Prepare to convert the column value from text
|
|
|
|
*/
|
|
|
|
if (column_info->column_type != column_type)
|
|
|
|
{
|
|
|
|
getTypeInputInfo(column_type,
|
|
|
|
&column_info->typiofunc,
|
|
|
|
&column_info->typioparam);
|
|
|
|
fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
|
|
|
|
state->fn_mcxt);
|
|
|
|
column_info->column_type = column_type;
|
|
|
|
}
|
|
|
|
if (v == NULL || v->type == jbvNull)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Need InputFunctionCall to happen even for nulls, so that domain
|
|
|
|
* checks are done
|
|
|
|
*/
|
|
|
|
values[i] = InputFunctionCall(&column_info->proc, NULL,
|
|
|
|
column_info->typioparam,
|
|
|
|
tupdesc->attrs[i]->atttypmod);
|
|
|
|
nulls[i] = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char *s = NULL;
|
|
|
|
|
|
|
|
if (v->type == jbvString)
|
2014-04-02 20:30:08 +02:00
|
|
|
s = pnstrdup(v->val.string.val, v->val.string.len);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
else if (v->type == jbvBool)
|
2014-04-02 20:30:08 +02:00
|
|
|
s = pnstrdup((v->val.boolean) ? "t" : "f", 1);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
else if (v->type == jbvNumeric)
|
|
|
|
s = DatumGetCString(DirectFunctionCall1(numeric_out,
|
2014-05-06 18:12:18 +02:00
|
|
|
PointerGetDatum(v->val.numeric)));
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
else if (v->type == jbvBinary)
|
2014-05-07 22:16:19 +02:00
|
|
|
s = JsonbToCString(NULL, (JsonbContainer *) v->val.binary.data, v->val.binary.len);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
else
|
2014-06-26 00:25:22 +02:00
|
|
|
elog(ERROR, "unrecognized jsonb type: %d", (int) v->type);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
|
|
|
values[i] = InputFunctionCall(&column_info->proc, s,
|
|
|
|
column_info->typioparam,
|
|
|
|
tupdesc->attrs[i]->atttypmod);
|
|
|
|
nulls[i] = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rettuple = heap_form_tuple(tupdesc, values, nulls);
|
|
|
|
|
|
|
|
tuplestore_puttuple(state->tuple_store, rettuple);
|
|
|
|
}
|
|
|
|
|
2014-01-28 23:48:21 +01:00
|
|
|
/*
|
|
|
|
* common worker for json_populate_recordset() and json_to_recordset()
|
|
|
|
*/
|
2014-06-25 20:22:18 +02:00
|
|
|
static Datum
|
2014-06-26 00:25:22 +02:00
|
|
|
populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname,
|
|
|
|
bool have_record_arg)
|
2014-01-28 23:48:21 +01:00
|
|
|
{
|
2014-05-06 18:12:18 +02:00
|
|
|
int json_arg_num = have_record_arg ? 1 : 0;
|
2014-03-26 02:20:54 +01:00
|
|
|
Oid jtype = get_fn_expr_argtype(fcinfo->flinfo, json_arg_num);
|
2013-03-29 19:12:13 +01:00
|
|
|
ReturnSetInfo *rsi;
|
|
|
|
MemoryContext old_cxt;
|
|
|
|
Oid tupType;
|
|
|
|
int32 tupTypmod;
|
|
|
|
HeapTupleHeader rec;
|
|
|
|
TupleDesc tupdesc;
|
|
|
|
RecordIOData *my_extra;
|
|
|
|
int ncolumns;
|
2013-07-20 12:38:31 +02:00
|
|
|
PopulateRecordsetState *state;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
2014-01-28 23:48:21 +01:00
|
|
|
if (have_record_arg)
|
|
|
|
{
|
2014-05-06 18:12:18 +02:00
|
|
|
Oid argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
|
2014-01-28 23:48:21 +01:00
|
|
|
|
|
|
|
if (!type_is_rowtype(argtype))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
2014-06-26 00:25:22 +02:00
|
|
|
errmsg("first argument of %s must be a row type",
|
|
|
|
funcname)));
|
2014-01-28 23:48:21 +01:00
|
|
|
}
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
rsi = (ReturnSetInfo *) fcinfo->resultinfo;
|
|
|
|
|
|
|
|
if (!rsi || !IsA(rsi, ReturnSetInfo) ||
|
|
|
|
(rsi->allowedModes & SFRM_Materialize) == 0 ||
|
|
|
|
rsi->expectedDesc == NULL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("set-valued function called in context that "
|
|
|
|
"cannot accept a set")));
|
|
|
|
|
|
|
|
rsi->returnMode = SFRM_Materialize;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get the tupdesc from the result set info - it must be a record type
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
* because we already checked that arg1 is a record type, or we're in a
|
|
|
|
* to_record function which returns a setof record.
|
2013-03-29 19:12:13 +01:00
|
|
|
*/
|
2014-02-26 16:47:09 +01:00
|
|
|
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("function returning record called in context "
|
|
|
|
"that cannot accept type record")));
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/* if the json is null send back an empty set */
|
2014-03-26 02:20:54 +01:00
|
|
|
if (PG_ARGISNULL(json_arg_num))
|
|
|
|
PG_RETURN_NULL();
|
2014-01-28 23:48:21 +01:00
|
|
|
|
2014-03-26 02:20:54 +01:00
|
|
|
if (!have_record_arg || PG_ARGISNULL(0))
|
2014-01-28 23:48:21 +01:00
|
|
|
rec = NULL;
|
2014-03-26 02:20:54 +01:00
|
|
|
else
|
|
|
|
rec = PG_GETARG_HEAPTUPLEHEADER(0);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
tupType = tupdesc->tdtypeid;
|
|
|
|
tupTypmod = tupdesc->tdtypmod;
|
|
|
|
ncolumns = tupdesc->natts;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We arrange to look up the needed I/O info just once per series of
|
|
|
|
* calls, assuming the record type doesn't change underneath us.
|
|
|
|
*/
|
|
|
|
my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
|
|
|
|
if (my_extra == NULL ||
|
|
|
|
my_extra->ncolumns != ncolumns)
|
|
|
|
{
|
|
|
|
fcinfo->flinfo->fn_extra =
|
|
|
|
MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
|
2015-02-20 23:03:12 +01:00
|
|
|
offsetof(RecordIOData, columns) +
|
|
|
|
ncolumns * sizeof(ColumnIOData));
|
2013-03-29 19:12:13 +01:00
|
|
|
my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
|
|
|
|
my_extra->record_type = InvalidOid;
|
|
|
|
my_extra->record_typmod = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (my_extra->record_type != tupType ||
|
|
|
|
my_extra->record_typmod != tupTypmod)
|
|
|
|
{
|
|
|
|
MemSet(my_extra, 0,
|
2015-02-20 23:03:12 +01:00
|
|
|
offsetof(RecordIOData, columns) +
|
|
|
|
ncolumns * sizeof(ColumnIOData));
|
2013-03-29 19:12:13 +01:00
|
|
|
my_extra->record_type = tupType;
|
|
|
|
my_extra->record_typmod = tupTypmod;
|
|
|
|
my_extra->ncolumns = ncolumns;
|
|
|
|
}
|
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
state = palloc0(sizeof(PopulateRecordsetState));
|
2013-03-29 19:12:13 +01:00
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
/* make these in a sufficiently long-lived memory context */
|
|
|
|
old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
|
2015-03-31 14:12:27 +02:00
|
|
|
state->ret_tdesc = CreateTupleDescCopy(tupdesc);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
BlessTupleDesc(state->ret_tdesc);
|
|
|
|
state->tuple_store = tuplestore_begin_heap(rsi->allowedModes &
|
|
|
|
SFRM_Materialize_Random,
|
|
|
|
false, work_mem);
|
|
|
|
MemoryContextSwitchTo(old_cxt);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
2014-06-26 00:25:22 +02:00
|
|
|
state->function_name = funcname;
|
2013-03-29 19:12:13 +01:00
|
|
|
state->my_extra = my_extra;
|
|
|
|
state->rec = rec;
|
|
|
|
state->fn_mcxt = fcinfo->flinfo->fn_mcxt;
|
|
|
|
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
if (jtype == JSONOID)
|
|
|
|
{
|
2014-06-25 20:22:18 +02:00
|
|
|
text *json = PG_GETARG_TEXT_P(json_arg_num);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
JsonLexContext *lex;
|
|
|
|
JsonSemAction *sem;
|
|
|
|
|
|
|
|
sem = palloc0(sizeof(JsonSemAction));
|
|
|
|
|
|
|
|
lex = makeJsonLexContext(json, true);
|
|
|
|
|
|
|
|
sem->semstate = (void *) state;
|
|
|
|
sem->array_start = populate_recordset_array_start;
|
|
|
|
sem->array_element_start = populate_recordset_array_element_start;
|
|
|
|
sem->scalar = populate_recordset_scalar;
|
|
|
|
sem->object_field_start = populate_recordset_object_field_start;
|
|
|
|
sem->object_field_end = populate_recordset_object_field_end;
|
|
|
|
sem->object_start = populate_recordset_object_start;
|
|
|
|
sem->object_end = populate_recordset_object_end;
|
|
|
|
|
|
|
|
state->lex = lex;
|
|
|
|
|
|
|
|
pg_parse_json(lex, sem);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-06-25 20:22:18 +02:00
|
|
|
Jsonb *jb = PG_GETARG_JSONB(json_arg_num);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
JsonbIterator *it;
|
|
|
|
JsonbValue v;
|
|
|
|
bool skipNested = false;
|
2015-10-12 05:53:35 +02:00
|
|
|
JsonbIteratorToken r;
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
|
|
|
Assert(jtype == JSONBOID);
|
|
|
|
|
|
|
|
if (JB_ROOT_IS_SCALAR(jb) || !JB_ROOT_IS_ARRAY(jb))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
2014-06-26 00:25:22 +02:00
|
|
|
errmsg("cannot call %s on a non-array",
|
|
|
|
funcname)));
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
2014-05-07 22:16:19 +02:00
|
|
|
it = JsonbIteratorInit(&jb->root);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
|
|
|
while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
|
|
|
|
{
|
|
|
|
skipNested = true;
|
|
|
|
|
|
|
|
if (r == WJB_ELEM)
|
|
|
|
{
|
|
|
|
Jsonb *element = JsonbValueToJsonb(&v);
|
|
|
|
|
|
|
|
if (!JB_ROOT_IS_OBJECT(element))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
2014-06-26 00:25:22 +02:00
|
|
|
errmsg("argument of %s must be an array of objects",
|
|
|
|
funcname)));
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
make_row_from_rec_and_jsonb(element, state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
rsi->setResult = state->tuple_store;
|
|
|
|
rsi->setDesc = state->ret_tdesc;
|
|
|
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
populate_recordset_object_start(void *state)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
int lex_level = _state->lex->lex_level;
|
|
|
|
HASHCTL ctl;
|
|
|
|
|
2014-06-25 06:22:40 +02:00
|
|
|
/* Reject object at top level: we must have an array at level 0 */
|
2013-03-29 19:12:13 +01:00
|
|
|
if (lex_level == 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
2014-06-26 00:25:22 +02:00
|
|
|
errmsg("cannot call %s on an object",
|
|
|
|
_state->function_name)));
|
2013-03-29 19:12:13 +01:00
|
|
|
|
2014-06-29 19:50:58 +02:00
|
|
|
/* Nested objects require no special processing */
|
2014-06-25 06:22:40 +02:00
|
|
|
if (lex_level > 1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Object at level 1: set up a new hash table for this object */
|
2013-03-29 19:12:13 +01:00
|
|
|
memset(&ctl, 0, sizeof(ctl));
|
|
|
|
ctl.keysize = NAMEDATALEN;
|
2013-07-20 12:38:31 +02:00
|
|
|
ctl.entrysize = sizeof(JsonHashEntry);
|
2013-03-29 19:12:13 +01:00
|
|
|
ctl.hcxt = CurrentMemoryContext;
|
|
|
|
_state->json_hash = hash_create("json object hashtable",
|
|
|
|
100,
|
|
|
|
&ctl,
|
|
|
|
HASH_ELEM | HASH_CONTEXT);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
populate_recordset_object_end(void *state)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
HTAB *json_hash = _state->json_hash;
|
|
|
|
Datum *values;
|
|
|
|
bool *nulls;
|
|
|
|
int i;
|
|
|
|
RecordIOData *my_extra = _state->my_extra;
|
|
|
|
int ncolumns = my_extra->ncolumns;
|
|
|
|
TupleDesc tupdesc = _state->ret_tdesc;
|
2013-07-20 12:38:31 +02:00
|
|
|
JsonHashEntry *hashentry;
|
2013-03-29 19:12:13 +01:00
|
|
|
HeapTupleHeader rec = _state->rec;
|
|
|
|
HeapTuple rettuple;
|
|
|
|
|
2014-06-25 06:22:40 +02:00
|
|
|
/* Nested objects require no special processing */
|
2013-03-29 19:12:13 +01:00
|
|
|
if (_state->lex->lex_level > 1)
|
|
|
|
return;
|
|
|
|
|
2014-06-25 06:22:40 +02:00
|
|
|
/* Otherwise, construct and return a tuple based on this level-1 object */
|
2013-03-29 19:12:13 +01:00
|
|
|
values = (Datum *) palloc(ncolumns * sizeof(Datum));
|
|
|
|
nulls = (bool *) palloc(ncolumns * sizeof(bool));
|
|
|
|
|
|
|
|
if (_state->rec)
|
|
|
|
{
|
|
|
|
HeapTupleData tuple;
|
|
|
|
|
|
|
|
/* Build a temporary HeapTuple control structure */
|
|
|
|
tuple.t_len = HeapTupleHeaderGetDatumLength(_state->rec);
|
|
|
|
ItemPointerSetInvalid(&(tuple.t_self));
|
|
|
|
tuple.t_tableOid = InvalidOid;
|
|
|
|
tuple.t_data = _state->rec;
|
|
|
|
|
|
|
|
/* Break down the tuple into fields */
|
|
|
|
heap_deform_tuple(&tuple, tupdesc, values, nulls);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = 0; i < ncolumns; ++i)
|
|
|
|
{
|
|
|
|
values[i] = (Datum) 0;
|
|
|
|
nulls[i] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ncolumns; ++i)
|
|
|
|
{
|
|
|
|
ColumnIOData *column_info = &my_extra->columns[i];
|
|
|
|
Oid column_type = tupdesc->attrs[i]->atttypid;
|
|
|
|
char *value;
|
|
|
|
|
|
|
|
/* Ignore dropped columns in datatype */
|
|
|
|
if (tupdesc->attrs[i]->attisdropped)
|
|
|
|
{
|
|
|
|
nulls[i] = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-06-25 20:22:18 +02:00
|
|
|
hashentry = hash_search(json_hash,
|
|
|
|
NameStr(tupdesc->attrs[i]->attname),
|
|
|
|
HASH_FIND, NULL);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* we can't just skip here if the key wasn't found since we might have
|
|
|
|
* a domain to deal with. If we were passed in a non-null record
|
|
|
|
* datum, we assume that the existing values are valid (if they're
|
|
|
|
* not, then it's not our fault), but if we were passed in a null,
|
|
|
|
* then every field which we don't populate needs to be run through
|
|
|
|
* the input function just in case it's a domain type.
|
|
|
|
*/
|
|
|
|
if (hashentry == NULL && rec)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Prepare to convert the column value from text
|
|
|
|
*/
|
|
|
|
if (column_info->column_type != column_type)
|
|
|
|
{
|
|
|
|
getTypeInputInfo(column_type,
|
|
|
|
&column_info->typiofunc,
|
|
|
|
&column_info->typioparam);
|
|
|
|
fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
|
|
|
|
_state->fn_mcxt);
|
|
|
|
column_info->column_type = column_type;
|
|
|
|
}
|
|
|
|
if (hashentry == NULL || hashentry->isnull)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* need InputFunctionCall to happen even for nulls, so that domain
|
|
|
|
* checks are done
|
|
|
|
*/
|
|
|
|
values[i] = InputFunctionCall(&column_info->proc, NULL,
|
|
|
|
column_info->typioparam,
|
|
|
|
tupdesc->attrs[i]->atttypmod);
|
|
|
|
nulls[i] = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
value = hashentry->val;
|
|
|
|
|
|
|
|
values[i] = InputFunctionCall(&column_info->proc, value,
|
|
|
|
column_info->typioparam,
|
|
|
|
tupdesc->attrs[i]->atttypmod);
|
|
|
|
nulls[i] = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rettuple = heap_form_tuple(tupdesc, values, nulls);
|
|
|
|
|
|
|
|
tuplestore_puttuple(_state->tuple_store, rettuple);
|
|
|
|
|
2014-06-25 06:22:40 +02:00
|
|
|
/* Done with hash for this object */
|
2013-03-29 19:12:13 +01:00
|
|
|
hash_destroy(json_hash);
|
2014-06-25 06:22:40 +02:00
|
|
|
_state->json_hash = NULL;
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
populate_recordset_array_element_start(void *state, bool isnull)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
if (_state->lex->lex_level == 1 &&
|
|
|
|
_state->lex->token_type != JSON_TOKEN_OBJECT_START)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
2014-06-26 00:25:22 +02:00
|
|
|
errmsg("argument of %s must be an array of objects",
|
|
|
|
_state->function_name)));
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
populate_recordset_array_start(void *state)
|
|
|
|
{
|
2014-06-29 19:50:58 +02:00
|
|
|
/* nothing to do */
|
2013-03-29 19:12:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
populate_recordset_scalar(void *state, char *token, JsonTokenType tokentype)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
if (_state->lex->lex_level == 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
2014-06-26 00:25:22 +02:00
|
|
|
errmsg("cannot call %s on a scalar",
|
|
|
|
_state->function_name)));
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
if (_state->lex->lex_level == 2)
|
|
|
|
_state->saved_scalar = token;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
populate_recordset_object_field_start(void *state, char *fname, bool isnull)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
if (_state->lex->lex_level > 2)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (_state->lex->token_type == JSON_TOKEN_ARRAY_START ||
|
|
|
|
_state->lex->token_type == JSON_TOKEN_OBJECT_START)
|
|
|
|
{
|
|
|
|
_state->save_json_start = _state->lex->token_start;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_state->save_json_start = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
populate_recordset_object_field_end(void *state, char *fname, bool isnull)
|
|
|
|
{
|
2013-07-20 12:38:31 +02:00
|
|
|
PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
|
|
|
|
JsonHashEntry *hashentry;
|
2013-03-29 19:12:13 +01:00
|
|
|
bool found;
|
|
|
|
|
|
|
|
/*
|
2014-06-25 20:22:18 +02:00
|
|
|
* Ignore nested fields.
|
2013-03-29 19:12:13 +01:00
|
|
|
*/
|
2014-06-25 20:22:18 +02:00
|
|
|
if (_state->lex->lex_level > 2)
|
2013-03-29 19:12:13 +01:00
|
|
|
return;
|
|
|
|
|
2014-06-25 20:22:18 +02:00
|
|
|
/*
|
|
|
|
* Ignore field names >= NAMEDATALEN - they can't match a record field.
|
|
|
|
* (Note: without this test, the hash code would truncate the string at
|
|
|
|
* NAMEDATALEN-1, and could then match against a similarly-truncated
|
|
|
|
* record field name. That would be a reasonable behavior, but this code
|
|
|
|
* has previously insisted on exact equality, so we keep this behavior.)
|
|
|
|
*/
|
|
|
|
if (strlen(fname) >= NAMEDATALEN)
|
|
|
|
return;
|
2013-03-29 19:12:13 +01:00
|
|
|
|
2014-06-25 20:22:18 +02:00
|
|
|
hashentry = hash_search(_state->json_hash, fname, HASH_ENTER, &found);
|
2013-03-29 19:12:13 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* found being true indicates a duplicate. We don't do anything about
|
|
|
|
* that, a later field with the same name overrides the earlier field.
|
|
|
|
*/
|
|
|
|
|
|
|
|
hashentry->isnull = isnull;
|
|
|
|
if (_state->save_json_start != NULL)
|
|
|
|
{
|
|
|
|
int len = _state->lex->prev_token_terminator - _state->save_json_start;
|
|
|
|
char *val = palloc((len + 1) * sizeof(char));
|
|
|
|
|
|
|
|
memcpy(val, _state->save_json_start, len);
|
|
|
|
val[len] = '\0';
|
|
|
|
hashentry->val = val;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* must have had a scalar instead */
|
|
|
|
hashentry->val = _state->saved_scalar;
|
|
|
|
}
|
|
|
|
}
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
|
|
|
/*
|
2014-05-07 22:16:19 +02:00
|
|
|
* findJsonbValueFromContainer() wrapper that sets up JsonbValue key string.
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
*/
|
|
|
|
static JsonbValue *
|
2014-05-07 22:16:19 +02:00
|
|
|
findJsonbValueFromContainerLen(JsonbContainer *container, uint32 flags,
|
|
|
|
char *key, uint32 keylen)
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
{
|
|
|
|
JsonbValue k;
|
|
|
|
|
|
|
|
k.type = jbvString;
|
2014-04-02 20:30:08 +02:00
|
|
|
k.val.string.val = key;
|
|
|
|
k.val.string.len = keylen;
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
|
2014-05-07 22:16:19 +02:00
|
|
|
return findJsonbValueFromContainer(container, flags, &k);
|
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is
stored in a format that does not require reparsing the orgiginal text in order
to process it, making it much more suitable for indexing and other operations.
Insignificant whitespace is discarded, and the order of object keys is not
preserved. Neither are duplicate object keys kept - the later value for a given
key is the only one stored.
The new type has all the functions and operators that the json type has,
with the exception of the json generation functions (to_json, json_agg etc.)
and with identical semantics. In addition, there are operator classes for
hash and btree indexing, and two classes for GIN indexing, that have no
equivalent in the json type.
This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which
was intended to provide similar facilities to a nested hstore type, but which
in the end proved to have some significant compatibility issues.
Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan.
Review: Andres Freund
2014-03-23 21:40:19 +01:00
|
|
|
}
|
2014-12-12 15:00:43 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Semantic actions for json_strip_nulls.
|
|
|
|
*
|
|
|
|
* Simply repeat the input on the output unless we encounter
|
|
|
|
* a null object field. State for this is set when the field
|
|
|
|
* is started and reset when the scalar action (which must be next)
|
|
|
|
* is called.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
|
|
|
sn_object_start(void *state)
|
|
|
|
{
|
|
|
|
StripnullState *_state = (StripnullState *) state;
|
2015-05-24 03:35:49 +02:00
|
|
|
|
2014-12-12 15:00:43 +01:00
|
|
|
appendStringInfoCharMacro(_state->strval, '{');
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sn_object_end(void *state)
|
|
|
|
{
|
|
|
|
StripnullState *_state = (StripnullState *) state;
|
2015-05-24 03:35:49 +02:00
|
|
|
|
2014-12-12 15:00:43 +01:00
|
|
|
appendStringInfoCharMacro(_state->strval, '}');
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sn_array_start(void *state)
|
|
|
|
{
|
|
|
|
StripnullState *_state = (StripnullState *) state;
|
2015-05-24 03:35:49 +02:00
|
|
|
|
2014-12-12 15:00:43 +01:00
|
|
|
appendStringInfoCharMacro(_state->strval, '[');
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sn_array_end(void *state)
|
|
|
|
{
|
|
|
|
StripnullState *_state = (StripnullState *) state;
|
2015-05-24 03:35:49 +02:00
|
|
|
|
2014-12-12 15:00:43 +01:00
|
|
|
appendStringInfoCharMacro(_state->strval, ']');
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-05-24 03:35:49 +02:00
|
|
|
sn_object_field_start(void *state, char *fname, bool isnull)
|
2014-12-12 15:00:43 +01:00
|
|
|
{
|
|
|
|
StripnullState *_state = (StripnullState *) state;
|
|
|
|
|
|
|
|
if (isnull)
|
|
|
|
{
|
|
|
|
/*
|
2015-05-24 03:35:49 +02:00
|
|
|
* The next thing must be a scalar or isnull couldn't be true, so
|
|
|
|
* there is no danger of this state being carried down into a nested
|
|
|
|
* object or array. The flag will be reset in the scalar action.
|
2014-12-12 15:00:43 +01:00
|
|
|
*/
|
|
|
|
_state->skip_next_null = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_state->strval->data[_state->strval->len - 1] != '{')
|
|
|
|
appendStringInfoCharMacro(_state->strval, ',');
|
|
|
|
|
|
|
|
/*
|
2015-05-24 03:35:49 +02:00
|
|
|
* Unfortunately we don't have the quoted and escaped string any more, so
|
|
|
|
* we have to re-escape it.
|
2014-12-12 15:00:43 +01:00
|
|
|
*/
|
2015-05-24 03:35:49 +02:00
|
|
|
escape_json(_state->strval, fname);
|
2014-12-12 15:00:43 +01:00
|
|
|
|
|
|
|
appendStringInfoCharMacro(_state->strval, ':');
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-05-24 03:35:49 +02:00
|
|
|
sn_array_element_start(void *state, bool isnull)
|
2014-12-12 15:00:43 +01:00
|
|
|
{
|
|
|
|
StripnullState *_state = (StripnullState *) state;
|
|
|
|
|
|
|
|
if (_state->strval->data[_state->strval->len - 1] != '[')
|
|
|
|
appendStringInfoCharMacro(_state->strval, ',');
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sn_scalar(void *state, char *token, JsonTokenType tokentype)
|
|
|
|
{
|
|
|
|
StripnullState *_state = (StripnullState *) state;
|
|
|
|
|
|
|
|
if (_state->skip_next_null)
|
|
|
|
{
|
2015-05-24 03:35:49 +02:00
|
|
|
Assert(tokentype == JSON_TOKEN_NULL);
|
2014-12-12 15:00:43 +01:00
|
|
|
_state->skip_next_null = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tokentype == JSON_TOKEN_STRING)
|
|
|
|
escape_json(_state->strval, token);
|
|
|
|
else
|
|
|
|
appendStringInfoString(_state->strval, token);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SQL function json_strip_nulls(json) -> json
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
json_strip_nulls(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
text *json = PG_GETARG_TEXT_P(0);
|
2015-05-24 03:35:49 +02:00
|
|
|
StripnullState *state;
|
2014-12-12 15:00:43 +01:00
|
|
|
JsonLexContext *lex;
|
|
|
|
JsonSemAction *sem;
|
|
|
|
|
|
|
|
lex = makeJsonLexContext(json, true);
|
|
|
|
state = palloc0(sizeof(StripnullState));
|
|
|
|
sem = palloc0(sizeof(JsonSemAction));
|
|
|
|
|
|
|
|
state->strval = makeStringInfo();
|
|
|
|
state->skip_next_null = false;
|
|
|
|
state->lex = lex;
|
|
|
|
|
|
|
|
sem->semstate = (void *) state;
|
|
|
|
sem->object_start = sn_object_start;
|
|
|
|
sem->object_end = sn_object_end;
|
|
|
|
sem->array_start = sn_array_start;
|
|
|
|
sem->array_end = sn_array_end;
|
|
|
|
sem->scalar = sn_scalar;
|
|
|
|
sem->array_element_start = sn_array_element_start;
|
|
|
|
sem->object_field_start = sn_object_field_start;
|
|
|
|
|
|
|
|
pg_parse_json(lex, sem);
|
|
|
|
|
|
|
|
PG_RETURN_TEXT_P(cstring_to_text_with_len(state->strval->data,
|
|
|
|
state->strval->len));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SQL function jsonb_strip_nulls(jsonb) -> jsonb
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
jsonb_strip_nulls(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2015-05-24 03:35:49 +02:00
|
|
|
Jsonb *jb = PG_GETARG_JSONB(0);
|
2014-12-12 15:00:43 +01:00
|
|
|
JsonbIterator *it;
|
|
|
|
JsonbParseState *parseState = NULL;
|
|
|
|
JsonbValue *res = NULL;
|
2015-05-24 03:35:49 +02:00
|
|
|
JsonbValue v,
|
|
|
|
k;
|
2015-10-12 05:53:35 +02:00
|
|
|
JsonbIteratorToken type;
|
2015-05-24 03:35:49 +02:00
|
|
|
bool last_was_key = false;
|
2014-12-12 15:00:43 +01:00
|
|
|
|
|
|
|
if (JB_ROOT_IS_SCALAR(jb))
|
|
|
|
PG_RETURN_POINTER(jb);
|
|
|
|
|
|
|
|
it = JsonbIteratorInit(&jb->root);
|
|
|
|
|
|
|
|
while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
|
|
|
|
{
|
2015-05-24 03:35:49 +02:00
|
|
|
Assert(!(type == WJB_KEY && last_was_key));
|
2014-12-12 15:00:43 +01:00
|
|
|
|
|
|
|
if (type == WJB_KEY)
|
|
|
|
{
|
|
|
|
/* stash the key until we know if it has a null value */
|
|
|
|
k = v;
|
|
|
|
last_was_key = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (last_was_key)
|
|
|
|
{
|
|
|
|
/* if the last element was a key this one can't be */
|
|
|
|
last_was_key = false;
|
|
|
|
|
|
|
|
/* skip this field if value is null */
|
|
|
|
if (type == WJB_VALUE && v.type == jbvNull)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* otherwise, do a delayed push of the key */
|
2014-12-16 16:32:06 +01:00
|
|
|
(void) pushJsonbValue(&parseState, WJB_KEY, &k);
|
2014-12-12 15:00:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (type == WJB_VALUE || type == WJB_ELEM)
|
|
|
|
res = pushJsonbValue(&parseState, type, &v);
|
|
|
|
else
|
|
|
|
res = pushJsonbValue(&parseState, type, NULL);
|
|
|
|
}
|
|
|
|
|
2014-12-16 16:32:06 +01:00
|
|
|
Assert(res != NULL);
|
|
|
|
|
2014-12-12 15:00:43 +01:00
|
|
|
PG_RETURN_POINTER(JsonbValueToJsonb(res));
|
|
|
|
}
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Add values from the jsonb to the parse state.
|
|
|
|
*
|
|
|
|
* If the parse state container is an object, the jsonb is pushed as
|
|
|
|
* a value, not a key.
|
|
|
|
*
|
2015-05-27 04:54:11 +02:00
|
|
|
* This needs to be done using an iterator because pushJsonbValue doesn't
|
|
|
|
* like getting jbvBinary values, so we can't just push jb as a whole.
|
2015-05-12 21:52:45 +02:00
|
|
|
*/
|
|
|
|
static void
|
2015-05-24 03:35:49 +02:00
|
|
|
addJsonbToParseState(JsonbParseState **jbps, Jsonb *jb)
|
2015-05-12 21:52:45 +02:00
|
|
|
{
|
|
|
|
JsonbIterator *it;
|
2015-05-24 03:35:49 +02:00
|
|
|
JsonbValue *o = &(*jbps)->contVal;
|
|
|
|
JsonbValue v;
|
2015-10-12 05:53:35 +02:00
|
|
|
JsonbIteratorToken type;
|
2015-05-12 21:52:45 +02:00
|
|
|
|
2015-05-27 04:54:11 +02:00
|
|
|
it = JsonbIteratorInit(&jb->root);
|
|
|
|
|
2015-05-12 21:52:45 +02:00
|
|
|
Assert(o->type == jbvArray || o->type == jbvObject);
|
|
|
|
|
|
|
|
if (JB_ROOT_IS_SCALAR(jb))
|
|
|
|
{
|
2015-05-24 03:35:49 +02:00
|
|
|
(void) JsonbIteratorNext(&it, &v, false); /* skip array header */
|
|
|
|
(void) JsonbIteratorNext(&it, &v, false); /* fetch scalar value */
|
2015-05-12 21:52:45 +02:00
|
|
|
|
2015-05-27 04:54:11 +02:00
|
|
|
switch (o->type)
|
|
|
|
{
|
|
|
|
case jbvArray:
|
|
|
|
(void) pushJsonbValue(jbps, WJB_ELEM, &v);
|
|
|
|
break;
|
|
|
|
case jbvObject:
|
|
|
|
(void) pushJsonbValue(jbps, WJB_VALUE, &v);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
elog(ERROR, "unexpected parent of nested structure");
|
|
|
|
}
|
2015-05-12 21:52:45 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-05-27 04:54:11 +02:00
|
|
|
while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
|
|
|
|
{
|
|
|
|
if (type == WJB_KEY || type == WJB_VALUE || type == WJB_ELEM)
|
|
|
|
(void) pushJsonbValue(jbps, type, &v);
|
|
|
|
else
|
|
|
|
(void) pushJsonbValue(jbps, type, NULL);
|
|
|
|
}
|
2015-05-12 21:52:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SQL function jsonb_pretty (jsonb)
|
|
|
|
*
|
|
|
|
* Pretty-printed text for the jsonb
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
jsonb_pretty(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Jsonb *jb = PG_GETARG_JSONB(0);
|
|
|
|
StringInfo str = makeStringInfo();
|
|
|
|
|
|
|
|
JsonbToCStringIndent(str, &jb->root, VARSIZE(jb));
|
|
|
|
|
|
|
|
PG_RETURN_TEXT_P(cstring_to_text_with_len(str->data, str->len));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SQL function jsonb_concat (jsonb, jsonb)
|
|
|
|
*
|
|
|
|
* function for || operator
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
jsonb_concat(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Jsonb *jb1 = PG_GETARG_JSONB(0);
|
|
|
|
Jsonb *jb2 = PG_GETARG_JSONB(1);
|
|
|
|
JsonbParseState *state = NULL;
|
|
|
|
JsonbValue *res;
|
2015-05-24 03:35:49 +02:00
|
|
|
JsonbIterator *it1,
|
|
|
|
*it2;
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
/*
|
2016-06-10 00:02:36 +02:00
|
|
|
* If one of the jsonb is empty, just return the other if it's not scalar
|
|
|
|
* and both are of the same kind. If it's a scalar or they are of
|
|
|
|
* different kinds we need to perform the concatenation even if one is
|
2015-09-13 23:06:45 +02:00
|
|
|
* empty.
|
2015-05-12 21:52:45 +02:00
|
|
|
*/
|
2015-09-13 23:06:45 +02:00
|
|
|
if (JB_ROOT_IS_OBJECT(jb1) == JB_ROOT_IS_OBJECT(jb2))
|
|
|
|
{
|
|
|
|
if (JB_ROOT_COUNT(jb1) == 0 && !JB_ROOT_IS_SCALAR(jb2))
|
|
|
|
PG_RETURN_JSONB(jb2);
|
|
|
|
else if (JB_ROOT_COUNT(jb2) == 0 && !JB_ROOT_IS_SCALAR(jb1))
|
|
|
|
PG_RETURN_JSONB(jb1);
|
|
|
|
}
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
it1 = JsonbIteratorInit(&jb1->root);
|
|
|
|
it2 = JsonbIteratorInit(&jb2->root);
|
|
|
|
|
|
|
|
res = IteratorConcat(&it1, &it2, &state);
|
|
|
|
|
2015-05-25 17:43:06 +02:00
|
|
|
Assert(res != NULL);
|
2015-05-12 21:52:45 +02:00
|
|
|
|
2015-05-25 17:43:06 +02:00
|
|
|
PG_RETURN_JSONB(JsonbValueToJsonb(res));
|
2015-05-12 21:52:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SQL function jsonb_delete (jsonb, text)
|
|
|
|
*
|
|
|
|
* return a copy of the jsonb with the indicated item
|
|
|
|
* removed.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
jsonb_delete(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Jsonb *in = PG_GETARG_JSONB(0);
|
|
|
|
text *key = PG_GETARG_TEXT_PP(1);
|
|
|
|
char *keyptr = VARDATA_ANY(key);
|
|
|
|
int keylen = VARSIZE_ANY_EXHDR(key);
|
|
|
|
JsonbParseState *state = NULL;
|
|
|
|
JsonbIterator *it;
|
|
|
|
JsonbValue v,
|
|
|
|
*res = NULL;
|
|
|
|
bool skipNested = false;
|
2015-10-12 05:53:35 +02:00
|
|
|
JsonbIteratorToken r;
|
2015-05-12 21:52:45 +02:00
|
|
|
|
2015-05-13 19:52:08 +02:00
|
|
|
if (JB_ROOT_IS_SCALAR(in))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("cannot delete from scalar")));
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
if (JB_ROOT_COUNT(in) == 0)
|
2015-05-13 19:52:08 +02:00
|
|
|
PG_RETURN_JSONB(in);
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
it = JsonbIteratorInit(&in->root);
|
|
|
|
|
|
|
|
while ((r = JsonbIteratorNext(&it, &v, skipNested)) != 0)
|
|
|
|
{
|
|
|
|
skipNested = true;
|
|
|
|
|
|
|
|
if ((r == WJB_ELEM || r == WJB_KEY) &&
|
|
|
|
(v.type == jbvString && keylen == v.val.string.len &&
|
|
|
|
memcmp(keyptr, v.val.string.val, keylen) == 0))
|
|
|
|
{
|
|
|
|
/* skip corresponding value as well */
|
|
|
|
if (r == WJB_KEY)
|
|
|
|
JsonbIteratorNext(&it, &v, true);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
|
|
|
|
}
|
|
|
|
|
2015-05-13 19:52:08 +02:00
|
|
|
Assert(res != NULL);
|
2015-05-12 21:52:45 +02:00
|
|
|
|
2015-05-13 19:52:08 +02:00
|
|
|
PG_RETURN_JSONB(JsonbValueToJsonb(res));
|
2015-05-12 21:52:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SQL function jsonb_delete (jsonb, int)
|
|
|
|
*
|
|
|
|
* return a copy of the jsonb with the indicated item
|
|
|
|
* removed. Negative int means count back from the
|
|
|
|
* end of the items.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
jsonb_delete_idx(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Jsonb *in = PG_GETARG_JSONB(0);
|
|
|
|
int idx = PG_GETARG_INT32(1);
|
|
|
|
JsonbParseState *state = NULL;
|
|
|
|
JsonbIterator *it;
|
2015-10-12 05:53:35 +02:00
|
|
|
uint32 i = 0,
|
2015-05-12 21:52:45 +02:00
|
|
|
n;
|
|
|
|
JsonbValue v,
|
|
|
|
*res = NULL;
|
2015-10-12 05:53:35 +02:00
|
|
|
JsonbIteratorToken r;
|
2015-05-12 21:52:45 +02:00
|
|
|
|
2015-05-13 19:52:08 +02:00
|
|
|
if (JB_ROOT_IS_SCALAR(in))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("cannot delete from scalar")));
|
|
|
|
|
2015-06-08 02:46:00 +02:00
|
|
|
if (JB_ROOT_IS_OBJECT(in))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
2015-12-11 04:05:27 +01:00
|
|
|
errmsg("cannot delete from object using integer index")));
|
2015-06-08 02:46:00 +02:00
|
|
|
|
2015-05-12 21:52:45 +02:00
|
|
|
if (JB_ROOT_COUNT(in) == 0)
|
2015-05-13 19:52:08 +02:00
|
|
|
PG_RETURN_JSONB(in);
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
it = JsonbIteratorInit(&in->root);
|
|
|
|
|
|
|
|
r = JsonbIteratorNext(&it, &v, false);
|
2016-06-10 00:02:36 +02:00
|
|
|
Assert(r == WJB_BEGIN_ARRAY);
|
Support JSON negative array subscripts everywhere
Previously, there was an inconsistency across json/jsonb operators that
operate on datums containing JSON arrays -- only some operators
supported negative array count-from-the-end subscripting. Specifically,
only a new-to-9.5 jsonb deletion operator had support (the new "jsonb -
integer" operator). This inconsistency seemed likely to be
counter-intuitive to users. To fix, allow all places where the user can
supply an integer subscript to accept a negative subscript value,
including path-orientated operators and functions, as well as other
extraction operators. This will need to be called out as an
incompatibility in the 9.5 release notes, since it's possible that users
are relying on certain established extraction operators changed here
yielding NULL in the event of a negative subscript.
For the json type, this requires adding a way of cheaply getting the
total JSON array element count ahead of time when parsing arrays with a
negative subscript involved, necessitating an ad-hoc lex and parse.
This is followed by a "conversion" from a negative subscript to its
equivalent positive-wise value using the count. From there on, it's as
if a positive-wise value was originally provided.
Note that there is still a minor inconsistency here across jsonb
deletion operators. Unlike the aforementioned new "-" deletion operator
that accepts an integer on its right hand side, the new "#-" path
orientated deletion variant does not throw an error when it appears like
an array subscript (input that could be recognized by as an integer
literal) is being used on an object, which is wrong-headed. The reason
for not being stricter is that it could be the case that an object pair
happens to have a key value that looks like an integer; in general,
these two possibilities are impossible to differentiate with rhs path
text[] argument elements. However, we still don't allow the "#-"
path-orientated deletion operator to perform array-style subscripting.
Rather, we just return the original left operand value in the event of a
negative subscript (which seems analogous to how the established
"jsonb/json #> text[]" path-orientated operator may yield NULL in the
event of an invalid subscript).
In passing, make SetArrayPath() stricter about not accepting cases where
there is trailing non-numeric garbage bytes rather than a clean NUL
byte. This means, for example, that strings like "10e10" are now not
accepted as an array subscript of 10 by some new-to-9.5 path-orientated
jsonb operators (e.g. the new #- operator). Finally, remove dead code
for jsonb subscript deletion; arguably, this should have been done in
commit b81c7b409.
Peter Geoghegan and Andrew Dunstan
2015-07-18 02:56:13 +02:00
|
|
|
n = v.val.array.nElems;
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
{
|
|
|
|
if (-idx > n)
|
|
|
|
idx = n;
|
|
|
|
else
|
|
|
|
idx = n + idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (idx >= n)
|
2015-05-13 19:52:08 +02:00
|
|
|
PG_RETURN_JSONB(in);
|
2015-05-12 21:52:45 +02:00
|
|
|
|
2015-07-19 19:19:38 +02:00
|
|
|
pushJsonbValue(&state, r, NULL);
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
while ((r = JsonbIteratorNext(&it, &v, true)) != 0)
|
|
|
|
{
|
Support JSON negative array subscripts everywhere
Previously, there was an inconsistency across json/jsonb operators that
operate on datums containing JSON arrays -- only some operators
supported negative array count-from-the-end subscripting. Specifically,
only a new-to-9.5 jsonb deletion operator had support (the new "jsonb -
integer" operator). This inconsistency seemed likely to be
counter-intuitive to users. To fix, allow all places where the user can
supply an integer subscript to accept a negative subscript value,
including path-orientated operators and functions, as well as other
extraction operators. This will need to be called out as an
incompatibility in the 9.5 release notes, since it's possible that users
are relying on certain established extraction operators changed here
yielding NULL in the event of a negative subscript.
For the json type, this requires adding a way of cheaply getting the
total JSON array element count ahead of time when parsing arrays with a
negative subscript involved, necessitating an ad-hoc lex and parse.
This is followed by a "conversion" from a negative subscript to its
equivalent positive-wise value using the count. From there on, it's as
if a positive-wise value was originally provided.
Note that there is still a minor inconsistency here across jsonb
deletion operators. Unlike the aforementioned new "-" deletion operator
that accepts an integer on its right hand side, the new "#-" path
orientated deletion variant does not throw an error when it appears like
an array subscript (input that could be recognized by as an integer
literal) is being used on an object, which is wrong-headed. The reason
for not being stricter is that it could be the case that an object pair
happens to have a key value that looks like an integer; in general,
these two possibilities are impossible to differentiate with rhs path
text[] argument elements. However, we still don't allow the "#-"
path-orientated deletion operator to perform array-style subscripting.
Rather, we just return the original left operand value in the event of a
negative subscript (which seems analogous to how the established
"jsonb/json #> text[]" path-orientated operator may yield NULL in the
event of an invalid subscript).
In passing, make SetArrayPath() stricter about not accepting cases where
there is trailing non-numeric garbage bytes rather than a clean NUL
byte. This means, for example, that strings like "10e10" are now not
accepted as an array subscript of 10 by some new-to-9.5 path-orientated
jsonb operators (e.g. the new #- operator). Finally, remove dead code
for jsonb subscript deletion; arguably, this should have been done in
commit b81c7b409.
Peter Geoghegan and Andrew Dunstan
2015-07-18 02:56:13 +02:00
|
|
|
if (r == WJB_ELEM)
|
2015-05-12 21:52:45 +02:00
|
|
|
{
|
|
|
|
if (i++ == idx)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
|
|
|
|
}
|
|
|
|
|
2015-05-24 03:35:49 +02:00
|
|
|
Assert(res != NULL);
|
2015-05-12 21:52:45 +02:00
|
|
|
|
2015-05-13 19:52:08 +02:00
|
|
|
PG_RETURN_JSONB(JsonbValueToJsonb(res));
|
2015-05-12 21:52:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2015-06-01 02:34:10 +02:00
|
|
|
* SQL function jsonb_set(jsonb, text[], jsonb, boolean)
|
|
|
|
*
|
2015-05-12 21:52:45 +02:00
|
|
|
*/
|
|
|
|
Datum
|
2015-06-01 02:34:10 +02:00
|
|
|
jsonb_set(PG_FUNCTION_ARGS)
|
2015-05-12 21:52:45 +02:00
|
|
|
{
|
|
|
|
Jsonb *in = PG_GETARG_JSONB(0);
|
|
|
|
ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
|
|
|
|
Jsonb *newval = PG_GETARG_JSONB(2);
|
2015-06-01 02:34:10 +02:00
|
|
|
bool create = PG_GETARG_BOOL(3);
|
2015-05-12 21:52:45 +02:00
|
|
|
JsonbValue *res = NULL;
|
|
|
|
Datum *path_elems;
|
|
|
|
bool *path_nulls;
|
|
|
|
int path_len;
|
|
|
|
JsonbIterator *it;
|
|
|
|
JsonbParseState *st = NULL;
|
|
|
|
|
|
|
|
if (ARR_NDIM(path) > 1)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
|
|
|
errmsg("wrong number of array subscripts")));
|
|
|
|
|
2015-05-13 19:52:08 +02:00
|
|
|
if (JB_ROOT_IS_SCALAR(in))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
2015-06-01 02:34:10 +02:00
|
|
|
errmsg("cannot set path in scalar")));
|
2015-05-13 19:52:08 +02:00
|
|
|
|
2015-06-01 02:34:10 +02:00
|
|
|
if (JB_ROOT_COUNT(in) == 0 && !create)
|
2015-05-13 19:52:08 +02:00
|
|
|
PG_RETURN_JSONB(in);
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
deconstruct_array(path, TEXTOID, -1, false, 'i',
|
|
|
|
&path_elems, &path_nulls, &path_len);
|
|
|
|
|
|
|
|
if (path_len == 0)
|
2015-05-13 19:52:08 +02:00
|
|
|
PG_RETURN_JSONB(in);
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
it = JsonbIteratorInit(&in->root);
|
|
|
|
|
2015-06-01 02:34:10 +02:00
|
|
|
res = setPath(&it, path_elems, path_nulls, path_len, &st,
|
2016-10-13 06:25:28 +02:00
|
|
|
0, newval, create ? JB_PATH_CREATE : JB_PATH_REPLACE);
|
2015-05-12 21:52:45 +02:00
|
|
|
|
2015-05-24 03:35:49 +02:00
|
|
|
Assert(res != NULL);
|
2015-05-12 21:52:45 +02:00
|
|
|
|
2015-05-13 19:52:08 +02:00
|
|
|
PG_RETURN_JSONB(JsonbValueToJsonb(res));
|
2015-05-12 21:52:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SQL function jsonb_delete(jsonb, text[])
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
jsonb_delete_path(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Jsonb *in = PG_GETARG_JSONB(0);
|
|
|
|
ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
|
|
|
|
JsonbValue *res = NULL;
|
|
|
|
Datum *path_elems;
|
|
|
|
bool *path_nulls;
|
|
|
|
int path_len;
|
|
|
|
JsonbIterator *it;
|
|
|
|
JsonbParseState *st = NULL;
|
|
|
|
|
|
|
|
if (ARR_NDIM(path) > 1)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
|
|
|
errmsg("wrong number of array subscripts")));
|
|
|
|
|
2015-05-13 19:52:08 +02:00
|
|
|
if (JB_ROOT_IS_SCALAR(in))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("cannot delete path in scalar")));
|
|
|
|
|
2015-05-12 21:52:45 +02:00
|
|
|
if (JB_ROOT_COUNT(in) == 0)
|
2015-05-13 19:52:08 +02:00
|
|
|
PG_RETURN_JSONB(in);
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
deconstruct_array(path, TEXTOID, -1, false, 'i',
|
|
|
|
&path_elems, &path_nulls, &path_len);
|
|
|
|
|
|
|
|
if (path_len == 0)
|
2015-05-13 19:52:08 +02:00
|
|
|
PG_RETURN_JSONB(in);
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
it = JsonbIteratorInit(&in->root);
|
|
|
|
|
2016-04-06 18:20:17 +02:00
|
|
|
res = setPath(&it, path_elems, path_nulls, path_len, &st,
|
|
|
|
0, NULL, JB_PATH_DELETE);
|
|
|
|
|
|
|
|
Assert(res != NULL);
|
|
|
|
|
|
|
|
PG_RETURN_JSONB(JsonbValueToJsonb(res));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SQL function jsonb_insert(jsonb, text[], jsonb, boolean)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
jsonb_insert(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Jsonb *in = PG_GETARG_JSONB(0);
|
|
|
|
ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
|
|
|
|
Jsonb *newval = PG_GETARG_JSONB(2);
|
|
|
|
bool after = PG_GETARG_BOOL(3);
|
|
|
|
JsonbValue *res = NULL;
|
|
|
|
Datum *path_elems;
|
|
|
|
bool *path_nulls;
|
|
|
|
int path_len;
|
|
|
|
JsonbIterator *it;
|
|
|
|
JsonbParseState *st = NULL;
|
|
|
|
|
|
|
|
if (ARR_NDIM(path) > 1)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
|
|
|
errmsg("wrong number of array subscripts")));
|
|
|
|
|
|
|
|
if (JB_ROOT_IS_SCALAR(in))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("cannot set path in scalar")));
|
|
|
|
|
|
|
|
deconstruct_array(path, TEXTOID, -1, false, 'i',
|
|
|
|
&path_elems, &path_nulls, &path_len);
|
|
|
|
|
|
|
|
if (path_len == 0)
|
|
|
|
PG_RETURN_JSONB(in);
|
|
|
|
|
|
|
|
it = JsonbIteratorInit(&in->root);
|
|
|
|
|
|
|
|
res = setPath(&it, path_elems, path_nulls, path_len, &st, 0, newval,
|
|
|
|
after ? JB_PATH_INSERT_AFTER : JB_PATH_INSERT_BEFORE);
|
2015-05-12 21:52:45 +02:00
|
|
|
|
2015-05-24 03:35:49 +02:00
|
|
|
Assert(res != NULL);
|
2015-05-12 21:52:45 +02:00
|
|
|
|
2015-05-13 19:52:08 +02:00
|
|
|
PG_RETURN_JSONB(JsonbValueToJsonb(res));
|
2015-05-12 21:52:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Iterate over all jsonb objects and merge them into one.
|
|
|
|
* The logic of this function copied from the same hstore function,
|
|
|
|
* except the case, when it1 & it2 represents jbvObject.
|
|
|
|
* In that case we just append the content of it2 to it1 without any
|
|
|
|
* verifications.
|
|
|
|
*/
|
|
|
|
static JsonbValue *
|
|
|
|
IteratorConcat(JsonbIterator **it1, JsonbIterator **it2,
|
|
|
|
JsonbParseState **state)
|
|
|
|
{
|
|
|
|
JsonbValue v1,
|
|
|
|
v2,
|
|
|
|
*res = NULL;
|
2015-10-12 05:53:35 +02:00
|
|
|
JsonbIteratorToken r1,
|
|
|
|
r2,
|
|
|
|
rk1,
|
|
|
|
rk2;
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
r1 = rk1 = JsonbIteratorNext(it1, &v1, false);
|
|
|
|
r2 = rk2 = JsonbIteratorNext(it2, &v2, false);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Both elements are objects.
|
|
|
|
*/
|
|
|
|
if (rk1 == WJB_BEGIN_OBJECT && rk2 == WJB_BEGIN_OBJECT)
|
|
|
|
{
|
|
|
|
/*
|
2015-05-17 14:57:30 +02:00
|
|
|
* Append the all tokens from v1 to res, except last WJB_END_OBJECT
|
2015-05-12 21:52:45 +02:00
|
|
|
* (because res will not be finished yet).
|
|
|
|
*/
|
2015-05-25 17:43:06 +02:00
|
|
|
pushJsonbValue(state, r1, NULL);
|
|
|
|
while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_OBJECT)
|
2015-06-01 02:34:10 +02:00
|
|
|
pushJsonbValue(state, r1, &v1);
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Append the all tokens from v2 to res, include last WJB_END_OBJECT
|
|
|
|
* (the concatenation will be completed).
|
|
|
|
*/
|
2015-05-25 17:43:06 +02:00
|
|
|
while ((r2 = JsonbIteratorNext(it2, &v2, true)) != 0)
|
|
|
|
res = pushJsonbValue(state, r2, r2 != WJB_END_OBJECT ? &v2 : NULL);
|
2015-05-12 21:52:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Both elements are arrays (either can be scalar).
|
|
|
|
*/
|
|
|
|
else if (rk1 == WJB_BEGIN_ARRAY && rk2 == WJB_BEGIN_ARRAY)
|
|
|
|
{
|
2015-05-25 17:43:06 +02:00
|
|
|
pushJsonbValue(state, r1, NULL);
|
2015-05-12 21:52:45 +02:00
|
|
|
|
2015-05-25 17:43:06 +02:00
|
|
|
while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_ARRAY)
|
|
|
|
{
|
|
|
|
Assert(r1 == WJB_ELEM);
|
2015-05-12 21:52:45 +02:00
|
|
|
pushJsonbValue(state, r1, &v1);
|
|
|
|
}
|
|
|
|
|
2015-06-01 02:34:10 +02:00
|
|
|
while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_END_ARRAY)
|
2015-05-12 21:52:45 +02:00
|
|
|
{
|
2015-05-25 17:43:06 +02:00
|
|
|
Assert(r2 == WJB_ELEM);
|
|
|
|
pushJsonbValue(state, WJB_ELEM, &v2);
|
2015-05-12 21:52:45 +02:00
|
|
|
}
|
|
|
|
|
2015-05-25 17:43:06 +02:00
|
|
|
res = pushJsonbValue(state, WJB_END_ARRAY, NULL /* signal to sort */ );
|
2015-05-12 21:52:45 +02:00
|
|
|
}
|
|
|
|
/* have we got array || object or object || array? */
|
|
|
|
else if (((rk1 == WJB_BEGIN_ARRAY && !(*it1)->isScalar) && rk2 == WJB_BEGIN_OBJECT) ||
|
|
|
|
(rk1 == WJB_BEGIN_OBJECT && (rk2 == WJB_BEGIN_ARRAY && !(*it2)->isScalar)))
|
|
|
|
{
|
|
|
|
|
|
|
|
JsonbIterator **it_array = rk1 == WJB_BEGIN_ARRAY ? it1 : it2;
|
|
|
|
JsonbIterator **it_object = rk1 == WJB_BEGIN_OBJECT ? it1 : it2;
|
|
|
|
|
2015-05-25 17:43:06 +02:00
|
|
|
bool prepend = (rk1 == WJB_BEGIN_OBJECT);
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
pushJsonbValue(state, WJB_BEGIN_ARRAY, NULL);
|
2015-05-25 17:43:06 +02:00
|
|
|
|
2015-05-12 21:52:45 +02:00
|
|
|
if (prepend)
|
|
|
|
{
|
|
|
|
pushJsonbValue(state, WJB_BEGIN_OBJECT, NULL);
|
2015-05-25 17:43:06 +02:00
|
|
|
while ((r1 = JsonbIteratorNext(it_object, &v1, true)) != 0)
|
|
|
|
pushJsonbValue(state, r1, r1 != WJB_END_OBJECT ? &v1 : NULL);
|
2015-05-12 21:52:45 +02:00
|
|
|
|
2015-05-25 17:43:06 +02:00
|
|
|
while ((r2 = JsonbIteratorNext(it_array, &v2, true)) != 0)
|
|
|
|
res = pushJsonbValue(state, r2, r2 != WJB_END_ARRAY ? &v2 : NULL);
|
2015-05-12 21:52:45 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-05-25 17:43:06 +02:00
|
|
|
while ((r1 = JsonbIteratorNext(it_array, &v1, true)) != WJB_END_ARRAY)
|
|
|
|
pushJsonbValue(state, r1, &v1);
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
pushJsonbValue(state, WJB_BEGIN_OBJECT, NULL);
|
2015-05-25 17:43:06 +02:00
|
|
|
while ((r2 = JsonbIteratorNext(it_object, &v2, true)) != 0)
|
|
|
|
pushJsonbValue(state, r2, r2 != WJB_END_OBJECT ? &v2 : NULL);
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
res = pushJsonbValue(state, WJB_END_ARRAY, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* This must be scalar || object or object || scalar, as that's all
|
|
|
|
* that's left. Both of these make no sense, so error out.
|
|
|
|
*/
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("invalid concatenation of jsonb objects")));
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2016-04-06 18:20:17 +02:00
|
|
|
* Do most of the heavy work for jsonb_set/jsonb_insert
|
|
|
|
*
|
|
|
|
* If JB_PATH_DELETE bit is set in op_type, the element is to be removed.
|
2015-06-01 02:34:10 +02:00
|
|
|
*
|
2016-04-06 18:20:17 +02:00
|
|
|
* If any bit mentioned in JB_PATH_CREATE_OR_INSERT is set in op_type,
|
|
|
|
* we create the new value if the key or array index does not exist.
|
2015-06-01 02:34:10 +02:00
|
|
|
*
|
2016-04-06 18:20:17 +02:00
|
|
|
* Bits JB_PATH_INSERT_BEFORE and JB_PATH_INSERT_AFTER in op_type
|
|
|
|
* behave as JB_PATH_CREATE if new value is inserted in JsonbObject.
|
|
|
|
*
|
|
|
|
* All path elements before the last must already exist
|
|
|
|
* whatever bits in op_type are set, or nothing is done.
|
2015-05-12 21:52:45 +02:00
|
|
|
*/
|
|
|
|
static JsonbValue *
|
2015-06-01 02:34:10 +02:00
|
|
|
setPath(JsonbIterator **it, Datum *path_elems,
|
|
|
|
bool *path_nulls, int path_len,
|
2016-04-06 18:20:17 +02:00
|
|
|
JsonbParseState **st, int level, Jsonb *newval, int op_type)
|
2015-05-12 21:52:45 +02:00
|
|
|
{
|
|
|
|
JsonbValue v;
|
2015-10-12 05:53:35 +02:00
|
|
|
JsonbIteratorToken r;
|
2016-03-23 16:00:39 +01:00
|
|
|
JsonbValue *res;
|
2015-05-12 21:52:45 +02:00
|
|
|
|
2015-10-05 16:06:29 +02:00
|
|
|
check_stack_depth();
|
|
|
|
|
2015-10-04 19:28:16 +02:00
|
|
|
if (path_nulls[level])
|
2016-03-23 16:00:39 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
|
|
|
errmsg("path element at position %d is null",
|
|
|
|
level + 1)));
|
2015-10-04 19:28:16 +02:00
|
|
|
|
2015-05-12 21:52:45 +02:00
|
|
|
r = JsonbIteratorNext(it, &v, false);
|
|
|
|
|
|
|
|
switch (r)
|
|
|
|
{
|
|
|
|
case WJB_BEGIN_ARRAY:
|
|
|
|
(void) pushJsonbValue(st, r, NULL);
|
2015-06-01 02:34:10 +02:00
|
|
|
setPathArray(it, path_elems, path_nulls, path_len, st, level,
|
2016-04-06 18:20:17 +02:00
|
|
|
newval, v.val.array.nElems, op_type);
|
2015-05-12 21:52:45 +02:00
|
|
|
r = JsonbIteratorNext(it, &v, false);
|
|
|
|
Assert(r == WJB_END_ARRAY);
|
|
|
|
res = pushJsonbValue(st, r, NULL);
|
|
|
|
break;
|
|
|
|
case WJB_BEGIN_OBJECT:
|
|
|
|
(void) pushJsonbValue(st, r, NULL);
|
2015-06-01 02:34:10 +02:00
|
|
|
setPathObject(it, path_elems, path_nulls, path_len, st, level,
|
2016-04-06 18:20:17 +02:00
|
|
|
newval, v.val.object.nPairs, op_type);
|
2015-05-12 21:52:45 +02:00
|
|
|
r = JsonbIteratorNext(it, &v, true);
|
|
|
|
Assert(r == WJB_END_OBJECT);
|
|
|
|
res = pushJsonbValue(st, r, NULL);
|
|
|
|
break;
|
|
|
|
case WJB_ELEM:
|
|
|
|
case WJB_VALUE:
|
|
|
|
res = pushJsonbValue(st, r, &v);
|
|
|
|
break;
|
|
|
|
default:
|
2016-03-23 16:00:39 +01:00
|
|
|
elog(ERROR, "unrecognized iterator result: %d", (int) r);
|
|
|
|
res = NULL; /* keep compiler quiet */
|
|
|
|
break;
|
2015-05-12 21:52:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2015-06-01 02:34:10 +02:00
|
|
|
* Object walker for setPath
|
2015-05-12 21:52:45 +02:00
|
|
|
*/
|
|
|
|
static void
|
2015-06-01 02:34:10 +02:00
|
|
|
setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
|
|
|
|
int path_len, JsonbParseState **st, int level,
|
2016-04-06 18:20:17 +02:00
|
|
|
Jsonb *newval, uint32 npairs, int op_type)
|
2015-05-12 21:52:45 +02:00
|
|
|
{
|
|
|
|
JsonbValue v;
|
|
|
|
int i;
|
|
|
|
JsonbValue k;
|
|
|
|
bool done = false;
|
|
|
|
|
|
|
|
if (level >= path_len || path_nulls[level])
|
|
|
|
done = true;
|
|
|
|
|
2015-06-01 02:34:10 +02:00
|
|
|
/* empty object is a special case for create */
|
2016-04-06 18:20:17 +02:00
|
|
|
if ((npairs == 0) && (op_type & JB_PATH_CREATE_OR_INSERT) &&
|
|
|
|
(level == path_len - 1))
|
2015-06-01 02:34:10 +02:00
|
|
|
{
|
2015-06-01 04:56:53 +02:00
|
|
|
JsonbValue newkey;
|
2015-06-01 02:34:10 +02:00
|
|
|
|
2015-06-01 04:56:53 +02:00
|
|
|
newkey.type = jbvString;
|
|
|
|
newkey.val.string.len = VARSIZE_ANY_EXHDR(path_elems[level]);
|
|
|
|
newkey.val.string.val = VARDATA_ANY(path_elems[level]);
|
2015-06-01 02:34:10 +02:00
|
|
|
|
2015-06-01 04:56:53 +02:00
|
|
|
(void) pushJsonbValue(st, WJB_KEY, &newkey);
|
2015-06-01 02:34:10 +02:00
|
|
|
addJsonbToParseState(st, newval);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < npairs; i++)
|
2015-05-12 21:52:45 +02:00
|
|
|
{
|
2015-10-12 05:53:35 +02:00
|
|
|
JsonbIteratorToken r = JsonbIteratorNext(it, &k, true);
|
2015-05-24 03:35:49 +02:00
|
|
|
|
2015-05-12 21:52:45 +02:00
|
|
|
Assert(r == WJB_KEY);
|
|
|
|
|
|
|
|
if (!done &&
|
|
|
|
k.val.string.len == VARSIZE_ANY_EXHDR(path_elems[level]) &&
|
|
|
|
memcmp(k.val.string.val, VARDATA_ANY(path_elems[level]),
|
|
|
|
k.val.string.len) == 0)
|
|
|
|
{
|
|
|
|
if (level == path_len - 1)
|
|
|
|
{
|
2016-04-06 18:20:17 +02:00
|
|
|
/*
|
2016-06-10 00:02:36 +02:00
|
|
|
* called from jsonb_insert(), it forbids redefining an
|
2016-07-26 04:07:53 +02:00
|
|
|
* existing value
|
2016-04-06 18:20:17 +02:00
|
|
|
*/
|
|
|
|
if (op_type & (JB_PATH_INSERT_BEFORE | JB_PATH_INSERT_AFTER))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("cannot replace existing key"),
|
|
|
|
errhint("Try using the function jsonb_set "
|
|
|
|
"to replace key value.")));
|
|
|
|
|
2016-06-10 00:02:36 +02:00
|
|
|
r = JsonbIteratorNext(it, &v, true); /* skip value */
|
2016-04-06 18:20:17 +02:00
|
|
|
if (!(op_type & JB_PATH_DELETE))
|
2015-05-12 21:52:45 +02:00
|
|
|
{
|
|
|
|
(void) pushJsonbValue(st, WJB_KEY, &k);
|
|
|
|
addJsonbToParseState(st, newval);
|
|
|
|
}
|
2015-06-01 02:34:10 +02:00
|
|
|
done = true;
|
2015-05-12 21:52:45 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
(void) pushJsonbValue(st, r, &k);
|
2015-06-01 02:34:10 +02:00
|
|
|
setPath(it, path_elems, path_nulls, path_len,
|
2016-04-06 18:20:17 +02:00
|
|
|
st, level + 1, newval, op_type);
|
2015-05-12 21:52:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-04-06 18:20:17 +02:00
|
|
|
if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done &&
|
|
|
|
level == path_len - 1 && i == npairs - 1)
|
2015-06-01 02:34:10 +02:00
|
|
|
{
|
2015-06-01 04:56:53 +02:00
|
|
|
JsonbValue newkey;
|
2015-06-01 02:34:10 +02:00
|
|
|
|
2015-06-01 04:56:53 +02:00
|
|
|
newkey.type = jbvString;
|
|
|
|
newkey.val.string.len = VARSIZE_ANY_EXHDR(path_elems[level]);
|
|
|
|
newkey.val.string.val = VARDATA_ANY(path_elems[level]);
|
2015-06-01 02:34:10 +02:00
|
|
|
|
2015-06-01 04:56:53 +02:00
|
|
|
(void) pushJsonbValue(st, WJB_KEY, &newkey);
|
2015-06-01 02:34:10 +02:00
|
|
|
addJsonbToParseState(st, newval);
|
|
|
|
}
|
|
|
|
|
2015-05-12 21:52:45 +02:00
|
|
|
(void) pushJsonbValue(st, r, &k);
|
|
|
|
r = JsonbIteratorNext(it, &v, false);
|
|
|
|
(void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
|
|
|
|
if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
|
|
|
|
{
|
2015-05-24 03:35:49 +02:00
|
|
|
int walking_level = 1;
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
while (walking_level != 0)
|
|
|
|
{
|
|
|
|
r = JsonbIteratorNext(it, &v, false);
|
|
|
|
|
|
|
|
if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
|
|
|
|
++walking_level;
|
|
|
|
if (r == WJB_END_ARRAY || r == WJB_END_OBJECT)
|
|
|
|
--walking_level;
|
|
|
|
|
|
|
|
(void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2015-06-01 02:34:10 +02:00
|
|
|
* Array walker for setPath
|
2015-05-12 21:52:45 +02:00
|
|
|
*/
|
|
|
|
static void
|
2015-06-01 02:34:10 +02:00
|
|
|
setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
|
|
|
|
int path_len, JsonbParseState **st, int level,
|
2016-04-06 18:20:17 +02:00
|
|
|
Jsonb *newval, uint32 nelems, int op_type)
|
2015-05-12 21:52:45 +02:00
|
|
|
{
|
|
|
|
JsonbValue v;
|
|
|
|
int idx,
|
|
|
|
i;
|
2015-06-01 02:34:10 +02:00
|
|
|
bool done = false;
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
/* pick correct index */
|
|
|
|
if (level < path_len && !path_nulls[level])
|
|
|
|
{
|
2016-03-23 15:43:13 +01:00
|
|
|
char *c = TextDatumGetCString(path_elems[level]);
|
2015-06-13 01:26:03 +02:00
|
|
|
long lindex;
|
2016-03-23 16:00:39 +01:00
|
|
|
char *badp;
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
errno = 0;
|
2015-06-13 01:26:03 +02:00
|
|
|
lindex = strtol(c, &badp, 10);
|
Support JSON negative array subscripts everywhere
Previously, there was an inconsistency across json/jsonb operators that
operate on datums containing JSON arrays -- only some operators
supported negative array count-from-the-end subscripting. Specifically,
only a new-to-9.5 jsonb deletion operator had support (the new "jsonb -
integer" operator). This inconsistency seemed likely to be
counter-intuitive to users. To fix, allow all places where the user can
supply an integer subscript to accept a negative subscript value,
including path-orientated operators and functions, as well as other
extraction operators. This will need to be called out as an
incompatibility in the 9.5 release notes, since it's possible that users
are relying on certain established extraction operators changed here
yielding NULL in the event of a negative subscript.
For the json type, this requires adding a way of cheaply getting the
total JSON array element count ahead of time when parsing arrays with a
negative subscript involved, necessitating an ad-hoc lex and parse.
This is followed by a "conversion" from a negative subscript to its
equivalent positive-wise value using the count. From there on, it's as
if a positive-wise value was originally provided.
Note that there is still a minor inconsistency here across jsonb
deletion operators. Unlike the aforementioned new "-" deletion operator
that accepts an integer on its right hand side, the new "#-" path
orientated deletion variant does not throw an error when it appears like
an array subscript (input that could be recognized by as an integer
literal) is being used on an object, which is wrong-headed. The reason
for not being stricter is that it could be the case that an object pair
happens to have a key value that looks like an integer; in general,
these two possibilities are impossible to differentiate with rhs path
text[] argument elements. However, we still don't allow the "#-"
path-orientated deletion operator to perform array-style subscripting.
Rather, we just return the original left operand value in the event of a
negative subscript (which seems analogous to how the established
"jsonb/json #> text[]" path-orientated operator may yield NULL in the
event of an invalid subscript).
In passing, make SetArrayPath() stricter about not accepting cases where
there is trailing non-numeric garbage bytes rather than a clean NUL
byte. This means, for example, that strings like "10e10" are now not
accepted as an array subscript of 10 by some new-to-9.5 path-orientated
jsonb operators (e.g. the new #- operator). Finally, remove dead code
for jsonb subscript deletion; arguably, this should have been done in
commit b81c7b409.
Peter Geoghegan and Andrew Dunstan
2015-07-18 02:56:13 +02:00
|
|
|
if (errno != 0 || badp == c || *badp != '\0' || lindex > INT_MAX ||
|
|
|
|
lindex < INT_MIN)
|
2016-03-23 16:00:39 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
|
|
errmsg("path element at position %d is not an integer: \"%s\"",
|
|
|
|
level + 1, c)));
|
|
|
|
idx = lindex;
|
2015-05-12 21:52:45 +02:00
|
|
|
}
|
|
|
|
else
|
2015-06-01 02:34:10 +02:00
|
|
|
idx = nelems;
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
{
|
2015-06-01 02:34:10 +02:00
|
|
|
if (-idx > nelems)
|
Support JSON negative array subscripts everywhere
Previously, there was an inconsistency across json/jsonb operators that
operate on datums containing JSON arrays -- only some operators
supported negative array count-from-the-end subscripting. Specifically,
only a new-to-9.5 jsonb deletion operator had support (the new "jsonb -
integer" operator). This inconsistency seemed likely to be
counter-intuitive to users. To fix, allow all places where the user can
supply an integer subscript to accept a negative subscript value,
including path-orientated operators and functions, as well as other
extraction operators. This will need to be called out as an
incompatibility in the 9.5 release notes, since it's possible that users
are relying on certain established extraction operators changed here
yielding NULL in the event of a negative subscript.
For the json type, this requires adding a way of cheaply getting the
total JSON array element count ahead of time when parsing arrays with a
negative subscript involved, necessitating an ad-hoc lex and parse.
This is followed by a "conversion" from a negative subscript to its
equivalent positive-wise value using the count. From there on, it's as
if a positive-wise value was originally provided.
Note that there is still a minor inconsistency here across jsonb
deletion operators. Unlike the aforementioned new "-" deletion operator
that accepts an integer on its right hand side, the new "#-" path
orientated deletion variant does not throw an error when it appears like
an array subscript (input that could be recognized by as an integer
literal) is being used on an object, which is wrong-headed. The reason
for not being stricter is that it could be the case that an object pair
happens to have a key value that looks like an integer; in general,
these two possibilities are impossible to differentiate with rhs path
text[] argument elements. However, we still don't allow the "#-"
path-orientated deletion operator to perform array-style subscripting.
Rather, we just return the original left operand value in the event of a
negative subscript (which seems analogous to how the established
"jsonb/json #> text[]" path-orientated operator may yield NULL in the
event of an invalid subscript).
In passing, make SetArrayPath() stricter about not accepting cases where
there is trailing non-numeric garbage bytes rather than a clean NUL
byte. This means, for example, that strings like "10e10" are now not
accepted as an array subscript of 10 by some new-to-9.5 path-orientated
jsonb operators (e.g. the new #- operator). Finally, remove dead code
for jsonb subscript deletion; arguably, this should have been done in
commit b81c7b409.
Peter Geoghegan and Andrew Dunstan
2015-07-18 02:56:13 +02:00
|
|
|
idx = INT_MIN;
|
2015-05-12 21:52:45 +02:00
|
|
|
else
|
2015-06-01 02:34:10 +02:00
|
|
|
idx = nelems + idx;
|
2015-05-12 21:52:45 +02:00
|
|
|
}
|
|
|
|
|
2015-06-01 02:34:10 +02:00
|
|
|
if (idx > 0 && idx > nelems)
|
|
|
|
idx = nelems;
|
|
|
|
|
|
|
|
/*
|
Support JSON negative array subscripts everywhere
Previously, there was an inconsistency across json/jsonb operators that
operate on datums containing JSON arrays -- only some operators
supported negative array count-from-the-end subscripting. Specifically,
only a new-to-9.5 jsonb deletion operator had support (the new "jsonb -
integer" operator). This inconsistency seemed likely to be
counter-intuitive to users. To fix, allow all places where the user can
supply an integer subscript to accept a negative subscript value,
including path-orientated operators and functions, as well as other
extraction operators. This will need to be called out as an
incompatibility in the 9.5 release notes, since it's possible that users
are relying on certain established extraction operators changed here
yielding NULL in the event of a negative subscript.
For the json type, this requires adding a way of cheaply getting the
total JSON array element count ahead of time when parsing arrays with a
negative subscript involved, necessitating an ad-hoc lex and parse.
This is followed by a "conversion" from a negative subscript to its
equivalent positive-wise value using the count. From there on, it's as
if a positive-wise value was originally provided.
Note that there is still a minor inconsistency here across jsonb
deletion operators. Unlike the aforementioned new "-" deletion operator
that accepts an integer on its right hand side, the new "#-" path
orientated deletion variant does not throw an error when it appears like
an array subscript (input that could be recognized by as an integer
literal) is being used on an object, which is wrong-headed. The reason
for not being stricter is that it could be the case that an object pair
happens to have a key value that looks like an integer; in general,
these two possibilities are impossible to differentiate with rhs path
text[] argument elements. However, we still don't allow the "#-"
path-orientated deletion operator to perform array-style subscripting.
Rather, we just return the original left operand value in the event of a
negative subscript (which seems analogous to how the established
"jsonb/json #> text[]" path-orientated operator may yield NULL in the
event of an invalid subscript).
In passing, make SetArrayPath() stricter about not accepting cases where
there is trailing non-numeric garbage bytes rather than a clean NUL
byte. This means, for example, that strings like "10e10" are now not
accepted as an array subscript of 10 by some new-to-9.5 path-orientated
jsonb operators (e.g. the new #- operator). Finally, remove dead code
for jsonb subscript deletion; arguably, this should have been done in
commit b81c7b409.
Peter Geoghegan and Andrew Dunstan
2015-07-18 02:56:13 +02:00
|
|
|
* if we're creating, and idx == INT_MIN, we prepend the new value to the
|
|
|
|
* array also if the array is empty - in which case we don't really care
|
|
|
|
* what the idx value is
|
2015-06-01 02:34:10 +02:00
|
|
|
*/
|
|
|
|
|
2016-04-06 18:20:17 +02:00
|
|
|
if ((idx == INT_MIN || nelems == 0) && (level == path_len - 1) &&
|
|
|
|
(op_type & JB_PATH_CREATE_OR_INSERT))
|
2015-06-01 02:34:10 +02:00
|
|
|
{
|
|
|
|
Assert(newval != NULL);
|
|
|
|
addJsonbToParseState(st, newval);
|
|
|
|
done = true;
|
|
|
|
}
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
/* iterate over the array elements */
|
2015-06-01 02:34:10 +02:00
|
|
|
for (i = 0; i < nelems; i++)
|
2015-05-12 21:52:45 +02:00
|
|
|
{
|
2015-10-12 05:53:35 +02:00
|
|
|
JsonbIteratorToken r;
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
if (i == idx && level < path_len)
|
|
|
|
{
|
|
|
|
if (level == path_len - 1)
|
|
|
|
{
|
2015-05-24 03:35:49 +02:00
|
|
|
r = JsonbIteratorNext(it, &v, true); /* skip */
|
2016-04-06 18:20:17 +02:00
|
|
|
|
|
|
|
if (op_type & (JB_PATH_INSERT_BEFORE | JB_PATH_CREATE))
|
|
|
|
addJsonbToParseState(st, newval);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We should keep current value only in case of
|
2016-06-10 00:02:36 +02:00
|
|
|
* JB_PATH_INSERT_BEFORE or JB_PATH_INSERT_AFTER because
|
|
|
|
* otherwise it should be deleted or replaced
|
2016-04-06 18:20:17 +02:00
|
|
|
*/
|
|
|
|
if (op_type & (JB_PATH_INSERT_AFTER | JB_PATH_INSERT_BEFORE))
|
|
|
|
(void) pushJsonbValue(st, r, &v);
|
|
|
|
|
2016-10-13 06:25:28 +02:00
|
|
|
if (op_type & (JB_PATH_INSERT_AFTER | JB_PATH_REPLACE))
|
2015-05-12 21:52:45 +02:00
|
|
|
addJsonbToParseState(st, newval);
|
2015-06-01 02:34:10 +02:00
|
|
|
|
|
|
|
done = true;
|
2015-05-12 21:52:45 +02:00
|
|
|
}
|
|
|
|
else
|
2015-06-01 02:34:10 +02:00
|
|
|
(void) setPath(it, path_elems, path_nulls, path_len,
|
2016-04-06 18:20:17 +02:00
|
|
|
st, level + 1, newval, op_type);
|
2015-05-12 21:52:45 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
r = JsonbIteratorNext(it, &v, false);
|
|
|
|
|
|
|
|
(void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
|
|
|
|
|
|
|
|
if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
|
|
|
|
{
|
2015-05-24 03:35:49 +02:00
|
|
|
int walking_level = 1;
|
2015-05-12 21:52:45 +02:00
|
|
|
|
|
|
|
while (walking_level != 0)
|
|
|
|
{
|
|
|
|
r = JsonbIteratorNext(it, &v, false);
|
|
|
|
|
|
|
|
if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
|
|
|
|
++walking_level;
|
|
|
|
if (r == WJB_END_ARRAY || r == WJB_END_OBJECT)
|
|
|
|
--walking_level;
|
|
|
|
|
|
|
|
(void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
|
|
|
|
}
|
|
|
|
}
|
2015-06-01 02:34:10 +02:00
|
|
|
|
2016-10-13 06:25:28 +02:00
|
|
|
if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done &&
|
2016-04-06 18:20:17 +02:00
|
|
|
level == path_len - 1 && i == nelems - 1)
|
2015-06-01 02:34:10 +02:00
|
|
|
{
|
|
|
|
addJsonbToParseState(st, newval);
|
|
|
|
}
|
2015-05-12 21:52:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|