diff options
| author | Andrew Dunstan | 2014-03-23 20:40:19 +0000 |
|---|---|---|
| committer | Andrew Dunstan | 2014-03-23 20:40:19 +0000 |
| commit | d9134d0a355cfa447adc80db4505d5931084278a (patch) | |
| tree | cefe155d0f0f71b9279444a86eab4b1b1facafdb /src/include | |
| parent | b2b2491b06074e68fc7c96148cb0fdf0c8eb0469 (diff) | |
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
Diffstat (limited to 'src/include')
| -rw-r--r-- | src/include/catalog/pg_amop.h | 27 | ||||
| -rw-r--r-- | src/include/catalog/pg_amproc.h | 13 | ||||
| -rw-r--r-- | src/include/catalog/pg_cast.h | 4 | ||||
| -rw-r--r-- | src/include/catalog/pg_opclass.h | 4 | ||||
| -rw-r--r-- | src/include/catalog/pg_operator.h | 37 | ||||
| -rw-r--r-- | src/include/catalog/pg_opfamily.h | 5 | ||||
| -rw-r--r-- | src/include/catalog/pg_proc.h | 81 | ||||
| -rw-r--r-- | src/include/catalog/pg_type.h | 6 | ||||
| -rw-r--r-- | src/include/funcapi.h | 9 | ||||
| -rw-r--r-- | src/include/utils/json.h | 15 | ||||
| -rw-r--r-- | src/include/utils/jsonapi.h | 8 | ||||
| -rw-r--r-- | src/include/utils/jsonb.h | 320 | ||||
| -rw-r--r-- | src/include/utils/numeric.h | 1 |
13 files changed, 524 insertions, 6 deletions
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h index 7c1bc1d04c..2623113557 100644 --- a/src/include/catalog/pg_amop.h +++ b/src/include/catalog/pg_amop.h @@ -778,6 +778,33 @@ DATA(insert ( 4017 25 25 14 s 667 4000 0 )); DATA(insert ( 4017 25 25 15 s 666 4000 0 )); /* + * btree jsonb_ops + */ +DATA(insert ( 4033 3802 3802 1 s 3242 403 0 )); +DATA(insert ( 4033 3802 3802 2 s 3244 403 0 )); +DATA(insert ( 4033 3802 3802 3 s 3240 403 0 )); +DATA(insert ( 4033 3802 3802 4 s 3245 403 0 )); +DATA(insert ( 4033 3802 3802 5 s 3243 403 0 )); + +/* + * hash jsonb ops + */ +DATA(insert ( 4034 3802 3802 1 s 3240 405 0 )); + +/* + * GIN jsonb ops + */ +DATA(insert ( 4036 3802 3802 7 s 3246 2742 0 )); +DATA(insert ( 4036 3802 25 9 s 3247 2742 0 )); +DATA(insert ( 4036 3802 1009 10 s 3248 2742 0 )); +DATA(insert ( 4036 3802 1009 11 s 3249 2742 0 )); + +/* + * GIN jsonb hash ops + */ +DATA(insert ( 4037 3802 3802 7 s 3246 2742 0 )); + +/* * SP-GiST range_ops */ DATA(insert ( 3474 3831 3831 1 s 3893 4000 0 )); diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h index e3773e9759..b28dd563a8 100644 --- a/src/include/catalog/pg_amproc.h +++ b/src/include/catalog/pg_amproc.h @@ -138,6 +138,7 @@ DATA(insert ( 3522 3500 3500 1 3514 )); DATA(insert ( 3626 3614 3614 1 3622 )); DATA(insert ( 3683 3615 3615 1 3668 )); DATA(insert ( 3901 3831 3831 1 3870 )); +DATA(insert ( 4033 3802 3802 1 4044 )); /* hash */ @@ -175,6 +176,7 @@ DATA(insert ( 2235 1033 1033 1 329 )); DATA(insert ( 2969 2950 2950 1 2963 )); DATA(insert ( 3523 3500 3500 1 3515 )); DATA(insert ( 3903 3831 3831 1 3902 )); +DATA(insert ( 4034 3802 3802 1 4045 )); /* gist */ @@ -387,7 +389,16 @@ DATA(insert ( 3659 3614 3614 3 3657 )); DATA(insert ( 3659 3614 3614 4 3658 )); DATA(insert ( 3659 3614 3614 5 2700 )); DATA(insert ( 3659 3614 3614 6 3921 )); - +DATA(insert ( 4036 3802 3802 1 3480 )); +DATA(insert ( 4036 3802 3802 2 3482 )); +DATA(insert ( 4036 3802 3802 3 3483 )); +DATA(insert ( 4036 3802 3802 4 3484 )); +DATA(insert ( 4036 3802 3802 6 3488 )); +DATA(insert ( 4037 3802 3802 1 351 )); +DATA(insert ( 4037 3802 3802 2 3485 )); +DATA(insert ( 4037 3802 3802 3 3486 )); +DATA(insert ( 4037 3802 3802 4 3487 )); +DATA(insert ( 4037 3802 3802 6 3489 )); /* sp-gist */ DATA(insert ( 3474 3831 3831 1 3469 )); diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h index 3544d0a6ad..e037957472 100644 --- a/src/include/catalog/pg_cast.h +++ b/src/include/catalog/pg_cast.h @@ -359,4 +359,8 @@ DATA(insert ( 1560 1560 1685 i f )); DATA(insert ( 1562 1562 1687 i f )); DATA(insert ( 1700 1700 1703 i f )); +/* json to/from jsonb */ +DATA(insert ( 114 3802 0 e i )); +DATA(insert ( 3802 114 0 e i )); + #endif /* PG_CAST_H */ diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h index 6860637482..63a40a8412 100644 --- a/src/include/catalog/pg_opclass.h +++ b/src/include/catalog/pg_opclass.h @@ -228,5 +228,9 @@ DATA(insert ( 4000 range_ops PGNSP PGUID 3474 3831 t 0 )); DATA(insert ( 4000 quad_point_ops PGNSP PGUID 4015 600 t 0 )); DATA(insert ( 4000 kd_point_ops PGNSP PGUID 4016 600 f 0 )); DATA(insert ( 4000 text_ops PGNSP PGUID 4017 25 t 0 )); +DATA(insert ( 403 jsonb_ops PGNSP PGUID 4033 3802 t 0 )); +DATA(insert ( 405 jsonb_ops PGNSP PGUID 4034 3802 t 0 )); +DATA(insert ( 2742 jsonb_ops PGNSP PGUID 4036 3802 t 25 )); +DATA(insert ( 2742 jsonb_hash_ops PGNSP PGUID 4037 3802 f 23 )); #endif /* PG_OPCLASS_H */ diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index e07d6d9ef9..ac09034f3d 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -1769,8 +1769,41 @@ DATA(insert OID = 3966 ( "#>" PGNSP PGUID b f f 114 1009 114 0 0 json_extrac DESCR("get value from json with path elements"); DATA(insert OID = 3967 ( "#>>" PGNSP PGUID b f f 114 1009 25 0 0 json_extract_path_text_op - - )); DESCR("get value from json as text with path elements"); - - +DATA(insert OID = 3211 ( "->" PGNSP PGUID b f f 3802 25 3802 0 0 jsonb_object_field - - )); +DESCR("get jsonb object field"); +DATA(insert OID = 3477 ( "->>" PGNSP PGUID b f f 3802 25 25 0 0 jsonb_object_field_text - - )); +DESCR("get jsonb object field as text"); +DATA(insert OID = 3212 ( "->" PGNSP PGUID b f f 3802 23 3802 0 0 jsonb_array_element - - )); +DESCR("get jsonb array element"); +DATA(insert OID = 3481 ( "->>" PGNSP PGUID b f f 3802 23 25 0 0 jsonb_array_element_text - - )); +DESCR("get jsonb array element as text"); +DATA(insert OID = 3213 ( "#>" PGNSP PGUID b f f 3802 1009 3802 0 0 jsonb_extract_path_op - - )); +DESCR("get value from jsonb with path elements"); +DATA(insert OID = 3206 ( "#>>" PGNSP PGUID b f f 3802 1009 25 0 0 jsonb_extract_path_text_op - - )); +DESCR("get value from jsonb as text with path elements"); +DATA(insert OID = 3240 ( "=" PGNSP PGUID b t t 3802 3802 16 3240 3241 jsonb_eq eqsel eqjoinsel )); +DESCR("equal"); +DATA(insert OID = 3241 ( "<>" PGNSP PGUID b f f 3802 3802 16 3241 3240 jsonb_ne neqsel neqjoinsel )); +DESCR("not equal"); +DATA(insert OID = 3242 ( "<" PGNSP PGUID b f f 3802 3802 16 3243 3245 jsonb_lt scalarltsel scalarltjoinsel )); +DESCR("less than"); +DATA(insert OID = 3243 ( ">" PGNSP PGUID b f f 3802 3802 16 3242 3244 jsonb_gt scalargtsel scalargtjoinsel )); +DESCR("greater than"); +DATA(insert OID = 3244 ( "<=" PGNSP PGUID b f f 3802 3802 16 3245 3243 jsonb_le scalarltsel scalarltjoinsel )); +DESCR("less than or equal to"); +DATA(insert OID = 3245 ( ">=" PGNSP PGUID b f f 3802 3802 16 3244 3242 jsonb_ge scalargtsel scalargtjoinsel )); +DESCR("greater than or equal to"); +/* No commutator? */ +DATA(insert OID = 3246 ( "@>" PGNSP PGUID b f f 3802 3802 16 0 3250 jsonb_contains contsel contjoinsel )); +DESCR("contains"); +DATA(insert OID = 3247 ( "?" PGNSP PGUID b f f 3802 25 16 0 0 jsonb_exists contsel contjoinsel )); +DESCR("exists"); +DATA(insert OID = 3248 ( "?|" PGNSP PGUID b f f 3802 1009 16 0 0 jsonb_exists_any contsel contjoinsel )); +DESCR("exists any"); +DATA(insert OID = 3249 ( "?&" PGNSP PGUID b f f 3802 1009 16 0 0 jsonb_exists_all contsel contjoinsel )); +DESCR("exists all"); +DATA(insert OID = 3250 ( "<@" PGNSP PGUID b f f 3802 3802 16 0 3246 jsonb_contained contsel contjoinsel )); +DESCR("contained"); /* * function prototypes diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h index 229dcb1288..775be86c1a 100644 --- a/src/include/catalog/pg_opfamily.h +++ b/src/include/catalog/pg_opfamily.h @@ -147,6 +147,11 @@ DATA(insert OID = 3474 ( 4000 range_ops PGNSP PGUID )); DATA(insert OID = 4015 ( 4000 quad_point_ops PGNSP PGUID )); DATA(insert OID = 4016 ( 4000 kd_point_ops PGNSP PGUID )); DATA(insert OID = 4017 ( 4000 text_ops PGNSP PGUID )); +DATA(insert OID = 4033 ( 403 jsonb_ops PGNSP PGUID )); +DATA(insert OID = 4034 ( 405 jsonb_ops PGNSP PGUID )); +DATA(insert OID = 4035 ( 783 jsonb_ops PGNSP PGUID )); +DATA(insert OID = 4036 ( 2742 jsonb_ops PGNSP PGUID )); +DATA(insert OID = 4037 ( 2742 jsonb_hash_ops PGNSP PGUID )); #define TEXT_SPGIST_FAM_OID 4017 #endif /* PG_OPFAMILY_H */ diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 4bd23fc5fd..56f0f11ebe 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -4173,6 +4173,8 @@ DESCR("get value from json as text with path elements"); DATA(insert OID = 3954 ( json_extract_path_text_op PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 25 "114 1009" _null_ _null_ "{from_json,path_elems}" _null_ json_extract_path_text _null_ _null_ _null_ )); DATA(insert OID = 3955 ( json_array_elements PGNSP PGUID 12 1 100 0 0 f f f f t t i 1 0 114 "114" "{114,114}" "{i,o}" "{from_json,value}" _null_ json_array_elements _null_ _null_ _null_ )); DESCR("key value pairs of a json object"); +DATA(insert OID = 3969 ( json_array_elements_text PGNSP PGUID 12 1 100 0 0 f f f f t t i 1 0 25 "114" "{114,25}" "{i,o}" "{from_json,value}" _null_ json_array_elements_text _null_ _null_ _null_ )); +DESCR("elements of json array"); DATA(insert OID = 3956 ( json_array_length PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 23 "114" _null_ _null_ _null_ _null_ json_array_length _null_ _null_ _null_ )); DESCR("length of json array"); DATA(insert OID = 3957 ( json_object_keys PGNSP PGUID 12 1 100 0 0 f f f f t t i 1 0 25 "114" _null_ _null_ _null_ _null_ json_object_keys _null_ _null_ _null_ )); @@ -4191,8 +4193,6 @@ DATA(insert OID = 3205 ( json_to_recordset PGNSP PGUID 12 1 100 0 0 f f f f f DESCR("get set of records with fields from a json array of objects"); DATA(insert OID = 3968 ( json_typeof PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 25 "114" _null_ _null_ _null_ _null_ json_typeof _null_ _null_ _null_ )); DESCR("get the type of a json value"); -DATA(insert OID = 3969 ( json_array_elements_text PGNSP PGUID 12 1 100 0 0 f f f f t t i 1 0 25 "114" "{114,25}" "{i,o}" "{from_json,value}" _null_ json_array_elements_text _null_ _null_ _null_ )); -DESCR("elements of json array"); /* uuid */ DATA(insert OID = 2952 ( uuid_in PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2950 "2275" _null_ _null_ _null_ _null_ uuid_in _null_ _null_ _null_ )); @@ -4510,6 +4510,83 @@ DESCR("I/O"); DATA(insert OID = 3774 ( regdictionarysend PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 17 "3769" _null_ _null_ _null_ _null_ regdictionarysend _null_ _null_ _null_ )); DESCR("I/O"); +/* jsonb */ +DATA(insert OID = 3806 ( jsonb_in PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 3802 "2275" _null_ _null_ _null_ _null_ jsonb_in _null_ _null_ _null_ )); +DESCR("I/O"); +DATA(insert OID = 3805 ( jsonb_recv PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 3802 "2281" _null_ _null_ _null_ _null_ jsonb_recv _null_ _null_ _null_ )); +DESCR("I/O"); +DATA(insert OID = 3804 ( jsonb_out PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "3802" _null_ _null_ _null_ _null_ jsonb_out _null_ _null_ _null_ )); +DESCR("I/O"); +DATA(insert OID = 3803 ( jsonb_send PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 17 "3802" _null_ _null_ _null_ _null_ jsonb_send _null_ _null_ _null_ )); +DESCR("I/O"); + +DATA(insert OID = 3478 ( jsonb_object_field PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 3802 "3802 25" _null_ _null_ "{from_json, field_name}" _null_ jsonb_object_field _null_ _null_ _null_ )); +DATA(insert OID = 3214 ( jsonb_object_field_text PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 25 "3802 25" _null_ _null_ "{from_json, field_name}" _null_ jsonb_object_field_text _null_ _null_ _null_ )); +DATA(insert OID = 3215 ( jsonb_array_element PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 3802 "3802 23" _null_ _null_ "{from_json, element_index}" _null_ jsonb_array_element _null_ _null_ _null_ )); +DATA(insert OID = 3216 ( jsonb_array_element_text PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 25 "3802 23" _null_ _null_ "{from_json, element_index}" _null_ jsonb_array_element_text _null_ _null_ _null_ )); +DATA(insert OID = 3217 ( jsonb_extract_path PGNSP PGUID 12 1 0 25 0 f f f f t f i 2 0 3802 "3802 1009" "{3802,1009}" "{i,v}" "{from_json,path_elems}" _null_ jsonb_extract_path _null_ _null_ _null_ )); +DESCR("get value from jsonb with path elements"); +DATA(insert OID = 3939 ( jsonb_extract_path_op PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 3802 "3802 1009" _null_ _null_ "{from_json,path_elems}" _null_ jsonb_extract_path _null_ _null_ _null_ )); +DATA(insert OID = 3940 ( jsonb_extract_path_text PGNSP PGUID 12 1 0 25 0 f f f f t f i 2 0 25 "3802 1009" "{3802,1009}" "{i,v}" "{from_json,path_elems}" _null_ jsonb_extract_path_text _null_ _null_ _null_ )); +DESCR("get value from jsonb as text with path elements"); +DATA(insert OID = 3218 ( jsonb_extract_path_text_op PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 25 "3802 1009" _null_ _null_ "{from_json,path_elems}" _null_ jsonb_extract_path_text _null_ _null_ _null_ )); +DATA(insert OID = 3219 ( jsonb_array_elements PGNSP PGUID 12 1 100 0 0 f f f f t t i 1 0 3802 "3802" "{3802,3802}" "{i,o}" "{from_json,value}" _null_ jsonb_array_elements _null_ _null_ _null_ )); +DESCR("elements of a jsonb array"); +DATA(insert OID = 3465 ( jsonb_array_elements_text PGNSP PGUID 12 1 100 0 0 f f f f t t i 1 0 25 "3802" "{3802,25}" "{i,o}" "{from_json,value}" _null_ jsonb_array_elements_text _null_ _null_ _null_ )); +DESCR("elements of jsonb array"); +DATA(insert OID = 3207 ( jsonb_array_length PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 23 "3802" _null_ _null_ _null_ _null_ jsonb_array_length _null_ _null_ _null_ )); +DESCR("length of jsonb array"); +DATA(insert OID = 3931 ( jsonb_object_keys PGNSP PGUID 12 1 100 0 0 f f f f t t i 1 0 25 "3802" _null_ _null_ _null_ _null_ jsonb_object_keys _null_ _null_ _null_ )); +DESCR("get jsonb object keys"); +DATA(insert OID = 3208 ( jsonb_each PGNSP PGUID 12 1 100 0 0 f f f f t t i 1 0 2249 "3802" "{3802,25,3802}" "{i,o,o}" "{from_json,key,value}" _null_ jsonb_each _null_ _null_ _null_ )); +DESCR("key value pairs of a jsonb object"); +DATA(insert OID = 3932 ( jsonb_each_text PGNSP PGUID 12 1 100 0 0 f f f f t t i 1 0 2249 "3802" "{3802,25,25}" "{i,o,o}" "{from_json,key,value}" _null_ jsonb_each_text _null_ _null_ _null_ )); +DESCR("key value pairs of a jsonb object"); +DATA(insert OID = 3209 ( jsonb_populate_record PGNSP PGUID 12 1 0 0 0 f f f f f f s 3 0 2283 "2283 3802 16" _null_ _null_ _null_ _null_ jsonb_populate_record _null_ _null_ _null_ )); +DESCR("get record fields from a jsonb object"); +DATA(insert OID = 3475 ( jsonb_populate_recordset PGNSP PGUID 12 1 100 0 0 f f f f f t s 3 0 2283 "2283 3802 16" _null_ _null_ _null_ _null_ jsonb_populate_recordset _null_ _null_ _null_ )); +DESCR("get set of records with fields from a jsonb array of objects"); +DATA(insert OID = 3210 ( jsonb_typeof PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 25 "3802" _null_ _null_ _null_ _null_ jsonb_typeof _null_ _null_ _null_ )); +DESCR("get the type of a jsonb value"); +DATA(insert OID = 4038 ( jsonb_ne PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3802 3802" _null_ _null_ _null_ _null_ jsonb_ne _null_ _null_ _null_ )); +DATA(insert OID = 4039 ( jsonb_lt PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3802 3802" _null_ _null_ _null_ _null_ jsonb_lt _null_ _null_ _null_ )); +DATA(insert OID = 4040 ( jsonb_gt PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3802 3802" _null_ _null_ _null_ _null_ jsonb_gt _null_ _null_ _null_ )); +DATA(insert OID = 4041 ( jsonb_le PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3802 3802" _null_ _null_ _null_ _null_ jsonb_le _null_ _null_ _null_ )); +DATA(insert OID = 4042 ( jsonb_ge PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3802 3802" _null_ _null_ _null_ _null_ jsonb_ge _null_ _null_ _null_ )); +DATA(insert OID = 4043 ( jsonb_eq PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3802 3802" _null_ _null_ _null_ _null_ jsonb_eq _null_ _null_ _null_ )); +DATA(insert OID = 4044 ( jsonb_cmp PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 23 "3802 3802" _null_ _null_ _null_ _null_ jsonb_cmp _null_ _null_ _null_ )); +DESCR("less-equal-greater"); +DATA(insert OID = 4045 ( jsonb_hash PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 23 "3802" _null_ _null_ _null_ _null_ jsonb_hash _null_ _null_ _null_ )); +DESCR("hash"); +DATA(insert OID = 4046 ( jsonb_contains PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3802 3802" _null_ _null_ _null_ _null_ jsonb_contains _null_ _null_ _null_ )); +DESCR("implementation of @> operator"); +DATA(insert OID = 4047 ( jsonb_exists PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3802 25" _null_ _null_ _null_ _null_ jsonb_exists _null_ _null_ _null_ )); +DESCR("implementation of ? operator"); +DATA(insert OID = 4048 ( jsonb_exists_any PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3802 1009" _null_ _null_ _null_ _null_ jsonb_exists_any _null_ _null_ _null_ )); +DESCR("implementation of ?| operator"); +DATA(insert OID = 4049 ( jsonb_exists_all PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3802 1009" _null_ _null_ _null_ _null_ jsonb_exists_all _null_ _null_ _null_ )); +DESCR("implementation of ?& operator"); +DATA(insert OID = 4050 ( jsonb_contained PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3802 3802" _null_ _null_ _null_ _null_ jsonb_contained _null_ _null_ _null_ )); +DESCR("implementation of <@ operator"); +DATA(insert OID = 3480 ( gin_compare_jsonb PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 23 "25 25" _null_ _null_ _null_ _null_ gin_compare_jsonb _null_ _null_ _null_ )); +DESCR("GIN support"); +DATA(insert OID = 3482 ( gin_extract_jsonb PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ gin_extract_jsonb _null_ _null_ _null_ )); +DESCR("GIN support"); +DATA(insert OID = 3483 ( gin_extract_jsonb_query PGNSP PGUID 12 1 0 0 0 f f f f t f i 7 0 2281 "2277 2281 21 2281 2281 2281 2281" _null_ _null_ _null_ _null_ gin_extract_jsonb_query _null_ _null_ _null_ )); +DESCR("GIN support"); +DATA(insert OID = 3484 ( gin_consistent_jsonb PGNSP PGUID 12 1 0 0 0 f f f f t f i 8 0 16 "2281 21 2277 23 2281 2281 2281 2281" _null_ _null_ _null_ _null_ gin_consistent_jsonb _null_ _null_ _null_ )); +DESCR("GIN support"); +DATA(insert OID = 3488 ( gin_triconsistent_jsonb PGNSP PGUID 12 1 0 0 0 f f f f t f i 7 0 16 "2281 21 2277 23 2281 2281 2281" _null_ _null_ _null_ _null_ gin_triconsistent_jsonb _null_ _null_ _null_ )); +DESCR("GIN support"); +DATA(insert OID = 3485 ( gin_extract_jsonb_hash PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ gin_extract_jsonb_hash _null_ _null_ _null_ )); +DESCR("GIN support"); +DATA(insert OID = 3486 ( gin_extract_jsonb_query_hash PGNSP PGUID 12 1 0 0 0 f f f f t f i 7 0 2281 "2277 2281 21 2281 2281 2281 2281" _null_ _null_ _null_ _null_ gin_extract_jsonb_query_hash _null_ _null_ _null_ )); +DESCR("GIN support"); +DATA(insert OID = 3487 ( gin_consistent_jsonb_hash PGNSP PGUID 12 1 0 0 0 f f f f t f i 8 0 16 "2281 21 2277 23 2281 2281 2281 2281" _null_ _null_ _null_ _null_ gin_consistent_jsonb_hash _null_ _null_ _null_ )); +DESCR("GIN support"); +DATA(insert OID = 3489 ( gin_triconsistent_jsonb_hash PGNSP PGUID 12 1 0 0 0 f f f f t f i 7 0 16 "2281 21 2277 23 2281 2281 2281" _null_ _null_ _null_ _null_ gin_triconsistent_jsonb_hash _null_ _null_ _null_ )); +DESCR("GIN support"); + /* txid */ DATA(insert OID = 2939 ( txid_snapshot_in PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2970 "2275" _null_ _null_ _null_ _null_ txid_snapshot_in _null_ _null_ _null_ )); DESCR("I/O"); diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index 4c060f54b3..92d50bb36e 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -606,6 +606,12 @@ DATA(insert OID = 3645 ( _tsquery PGNSP PGUID -1 f b A f t \054 0 3615 0 array_ DATA(insert OID = 3735 ( _regconfig PGNSP PGUID -1 f b A f t \054 0 3734 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ )); DATA(insert OID = 3770 ( _regdictionary PGNSP PGUID -1 f b A f t \054 0 3769 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ )); +/* jsonb */ +DATA(insert OID = 3802 ( jsonb PGNSP PGUID -1 f b C f t \054 0 0 3807 jsonb_in jsonb_out jsonb_recv jsonb_send - - - i x f 0 -1 0 0 _null_ _null_ _null_ )); +DESCR("Binary JSON"); +#define JSONBOID 3802 +DATA(insert OID = 3807 ( _jsonb PGNSP PGUID -1 f b A f t \054 0 3802 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ )); + DATA(insert OID = 2970 ( txid_snapshot PGNSP PGUID -1 f b U f t \054 0 0 2949 txid_snapshot_in txid_snapshot_out txid_snapshot_recv txid_snapshot_send - - - d x f 0 -1 0 0 _null_ _null_ _null_ )); DESCR("txid snapshot"); DATA(insert OID = 2949 ( _txid_snapshot PGNSP PGUID -1 f b A f t \054 0 2970 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ )); diff --git a/src/include/funcapi.h b/src/include/funcapi.h index 9982e590b8..3610fc80d8 100644 --- a/src/include/funcapi.h +++ b/src/include/funcapi.h @@ -293,6 +293,15 @@ extern void end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx); PG_RETURN_DATUM(_result); \ } while (0) +#define SRF_RETURN_NEXT_NULL(_funcctx) \ + do { \ + ReturnSetInfo *rsi; \ + (_funcctx)->call_cntr++; \ + rsi = (ReturnSetInfo *) fcinfo->resultinfo; \ + rsi->isDone = ExprMultipleResult; \ + PG_RETURN_NULL(); \ + } while (0) + #define SRF_RETURN_DONE(_funcctx) \ do { \ ReturnSetInfo *rsi; \ diff --git a/src/include/utils/json.h b/src/include/utils/json.h index baf751e999..b5e947bd7a 100644 --- a/src/include/utils/json.h +++ b/src/include/utils/json.h @@ -64,4 +64,19 @@ extern Datum json_populate_recordset(PG_FUNCTION_ARGS); extern Datum json_to_record(PG_FUNCTION_ARGS); extern Datum json_to_recordset(PG_FUNCTION_ARGS); +extern Datum jsonb_object_field(PG_FUNCTION_ARGS); +extern Datum jsonb_object_field_text(PG_FUNCTION_ARGS); +extern Datum jsonb_array_element(PG_FUNCTION_ARGS); +extern Datum jsonb_array_element_text(PG_FUNCTION_ARGS); +extern Datum jsonb_extract_path(PG_FUNCTION_ARGS); +extern Datum jsonb_extract_path_text(PG_FUNCTION_ARGS); +extern Datum jsonb_object_keys(PG_FUNCTION_ARGS); +extern Datum jsonb_array_length(PG_FUNCTION_ARGS); +extern Datum jsonb_each(PG_FUNCTION_ARGS); +extern Datum jsonb_each_text(PG_FUNCTION_ARGS); +extern Datum jsonb_array_elements_text(PG_FUNCTION_ARGS); +extern Datum jsonb_array_elements(PG_FUNCTION_ARGS); +extern Datum jsonb_populate_record(PG_FUNCTION_ARGS); +extern Datum jsonb_populate_recordset(PG_FUNCTION_ARGS); + #endif /* JSON_H */ diff --git a/src/include/utils/jsonapi.h b/src/include/utils/jsonapi.h index 32fb0f79e7..7a4fbfe454 100644 --- a/src/include/utils/jsonapi.h +++ b/src/include/utils/jsonapi.h @@ -100,11 +100,17 @@ typedef struct JsonSemAction extern void pg_parse_json(JsonLexContext *lex, JsonSemAction *sem); /* - * constructor for JsonLexContext, with or without strval element. + * constructors for JsonLexContext, with or without strval element. * If supplied, the strval element will contain a de-escaped version of * the lexeme. However, doing this imposes a performance penalty, so * it should be avoided if the de-escaped lexeme is not required. + * + * If you already have the json as a text* value, use the first of these + * functions, otherwise use makeJsonLexContextCstringLen(). */ extern JsonLexContext *makeJsonLexContext(text *json, bool need_escapes); +extern JsonLexContext *makeJsonLexContextCstringLen(char *json, + int len, + bool need_escapes); #endif /* JSONAPI_H */ diff --git a/src/include/utils/jsonb.h b/src/include/utils/jsonb.h new file mode 100644 index 0000000000..a70cbd5940 --- /dev/null +++ b/src/include/utils/jsonb.h @@ -0,0 +1,320 @@ +/*------------------------------------------------------------------------- + * + * jsonb.h + * Declarations for jsonb data type support. + * + * Copyright (c) 1996-2014, PostgreSQL Global Development Group + * + * src/include/utils/jsonb.h + * + *------------------------------------------------------------------------- + */ +#ifndef __JSONB_H__ +#define __JSONB_H__ + +#include "lib/stringinfo.h" +#include "utils/array.h" +#include "utils/numeric.h" + +/* + * JB_CMASK is used to extract count of items + * + * It's not possible to get more than 2^28 items into an Jsonb. + */ +#define JB_CMASK 0x0FFFFFFF + +#define JB_FSCALAR 0x10000000 +#define JB_FOBJECT 0x20000000 +#define JB_FARRAY 0x40000000 + +/* Get information on varlena Jsonb */ +#define JB_ROOT_COUNT(jbp_) ( *(uint32*) VARDATA(jbp_) & JB_CMASK) +#define JB_ROOT_IS_SCALAR(jbp_) ( *(uint32*) VARDATA(jbp_) & JB_FSCALAR) +#define JB_ROOT_IS_OBJECT(jbp_) ( *(uint32*) VARDATA(jbp_) & JB_FOBJECT) +#define JB_ROOT_IS_ARRAY(jbp_) ( *(uint32*) VARDATA(jbp_) & JB_FARRAY) + +/* Jentry macros */ +#define JENTRY_POSMASK 0x0FFFFFFF +#define JENTRY_ISFIRST 0x80000000 +#define JENTRY_TYPEMASK (~(JENTRY_POSMASK | JENTRY_ISFIRST)) +#define JENTRY_ISSTRING 0x00000000 +#define JENTRY_ISNUMERIC 0x10000000 +#define JENTRY_ISNEST 0x20000000 +#define JENTRY_ISNULL 0x40000000 +#define JENTRY_ISBOOL (JENTRY_ISNUMERIC | JENTRY_ISNEST) +#define JENTRY_ISFALSE JENTRY_ISBOOL +#define JENTRY_ISTRUE (JENTRY_ISBOOL | 0x40000000) +/* Note possible multiple evaluations, also access to prior array element */ +#define JBE_ISFIRST(je_) (((je_).header & JENTRY_ISFIRST) != 0) +#define JBE_ISSTRING(je_) (((je_).header & JENTRY_TYPEMASK) == JENTRY_ISSTRING) +#define JBE_ISNUMERIC(je_) (((je_).header & JENTRY_TYPEMASK) == JENTRY_ISNUMERIC) +#define JBE_ISNEST(je_) (((je_).header & JENTRY_TYPEMASK) == JENTRY_ISNEST) +#define JBE_ISNULL(je_) (((je_).header & JENTRY_TYPEMASK) == JENTRY_ISNULL) +#define JBE_ISBOOL(je_) (((je_).header & JENTRY_TYPEMASK & JENTRY_ISBOOL) == JENTRY_ISBOOL) +#define JBE_ISBOOL_TRUE(je_) (((je_).header & JENTRY_TYPEMASK) == JENTRY_ISTRUE) +#define JBE_ISBOOL_FALSE(je_) (JBE_ISBOOL(je_) && !JBE_ISBOOL_TRUE(je_)) + +/* Get offset for Jentry */ +#define JBE_ENDPOS(je_) ((je_).header & JENTRY_POSMASK) +#define JBE_OFF(je_) (JBE_ISFIRST(je_) ? 0 : JBE_ENDPOS((&(je_))[-1])) +#define JBE_LEN(je_) (JBE_ISFIRST(je_) ? \ + JBE_ENDPOS(je_) \ + : JBE_ENDPOS(je_) - JBE_ENDPOS((&(je_))[-1])) + +/* Flags indicating a stage of sequential Jsonb processing */ +#define WJB_DONE 0x000 +#define WJB_KEY 0x001 +#define WJB_VALUE 0x002 +#define WJB_ELEM 0x004 +#define WJB_BEGIN_ARRAY 0x008 +#define WJB_END_ARRAY 0x010 +#define WJB_BEGIN_OBJECT 0x020 +#define WJB_END_OBJECT 0x040 + +/* + * When using a GIN index for jsonb, we choose to index both keys and values. + * The storage format is text, with K, or V prepended to the string to indicate + * key/element or value/element. + * + * Jsonb Keys and string array elements are treated equivalently when + * serialized to text index storage. One day we may wish to create an opclass + * that only indexes values, but for now keys and values are stored in GIN + * indexes in a way that doesn't really consider their relationship to each + * other. + */ +#define JKEYELEM 'K' +#define JVAL 'V' + +#define JsonbContainsStrategyNumber 7 +#define JsonbExistsStrategyNumber 9 +#define JsonbExistsAnyStrategyNumber 10 +#define JsonbExistsAllStrategyNumber 11 + +/* Convenience macros */ +#define DatumGetJsonb(d) ((Jsonb *) PG_DETOAST_DATUM(d)) +#define JsonbGetDatum(p) PointerGetDatum(p) +#define PG_GETARG_JSONB(x) DatumGetJsonb(PG_GETARG_DATUM(x)) +#define PG_RETURN_JSONB(x) PG_RETURN_POINTER(x) + +typedef struct JsonbPair JsonbPair; +typedef struct JsonbValue JsonbValue; +typedef char* JsonbSuperHeader; + +/* + * Jsonbs are varlena objects, so must meet the varlena convention that the + * first int32 of the object contains the total object size in bytes. Be sure + * to use VARSIZE() and SET_VARSIZE() to access it, though! + * + * Jsonb is the on-disk representation, in contrast to the in-memory JsonbValue + * representation. Often, JsonbValues are just shims through which a Jsonb + * buffer is accessed, but they can also be deep copied and passed around. + * + * We have an abstraction called a "superheader". This is a pointer that + * conventionally points to the first item after our 4-byte uncompressed + * varlena header, from which we can read flags using bitwise operations. + * + * Frequently, we pass a superheader reference to a function, and it doesn't + * matter if it points to just after the start of a Jsonb, or to a temp buffer. + */ +typedef struct +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + uint32 superheader; + /* (array of JEntry follows, size determined using uint32 superheader) */ +} Jsonb; + +/* + * JEntry: there is one of these for each key _and_ value for objects. Arrays + * have one per element. + * + * The position offset points to the _end_ so that we can get the length by + * subtraction from the previous entry. The JENTRY_ISFIRST flag indicates if + * there is a previous entry. + */ +typedef struct +{ + uint32 header; /* Shares some flags with superheader */ +} JEntry; + +#define IsAJsonbScalar(jsonbval) ((jsonbval)->type >= jbvNull && \ + (jsonbval)->type <= jbvBool) + +/* + * JsonbValue: In-memory representation of Jsonb. This is a convenient + * deserialized representation, that can easily support using the anonymous + * union across underlying types during manipulation. The Jsonb on-disk + * representation has various alignment considerations. + */ +struct JsonbValue +{ + enum + { + /* Scalar types */ + jbvNull = 0x0, + jbvString, + jbvNumeric, + jbvBool, + /* Composite types */ + jbvArray = 0x10, + jbvObject, + /* Binary (i.e. struct Jsonb) jbvArray/jbvObject */ + jbvBinary + } type; /* Influences sort order */ + + int estSize; /* Estimated size of node (including + * subnodes) */ + + union + { + Numeric numeric; + bool boolean; + struct + { + int len; + char *val; /* Not necessarily null-terminated */ + } string; /* String primitive type */ + + struct + { + int nElems; + JsonbValue *elems; + bool rawScalar; /* Top-level "raw scalar" array? */ + } array; /* Array container type */ + + struct + { + int nPairs; /* 1 pair, 2 elements */ + JsonbPair *pairs; + } object; /* Associative container type */ + + struct + { + int len; + char *data; + } binary; + }; +}; + +/* + * Pair within an Object. + * + * Pairs with duplicate keys are de-duplicated. We store the order for the + * benefit of doing so in a well-defined way with respect to the original + * observed order (which is "last observed wins"). This is only used briefly + * when originally constructing a Jsonb. + */ +struct JsonbPair +{ + JsonbValue key; /* Must be a jbvString */ + JsonbValue value; /* May be of any type */ + uint32 order; /* preserves order of pairs with equal keys */ +}; + +/* Conversion state used when parsing Jsonb from text, or for type coercion */ +typedef struct JsonbParseState +{ + JsonbValue contVal; + Size size; + struct JsonbParseState *next; +} JsonbParseState; + +/* + * JsonbIterator holds details of the type for each iteration. It also stores a + * Jsonb varlena buffer, which can be directly accessed in some contexts. + */ +typedef enum +{ + jbi_start = 0x0, + jbi_key, + jbi_value, + jbi_elem +} JsonbIterState; + +typedef struct JsonbIterator +{ + /* Jsonb varlena buffer (may or may not be root) */ + char *buffer; + + /* Current value */ + uint32 containerType; /* Never of value JB_FSCALAR, since + * scalars will appear in pseudo-arrays */ + uint32 nElems; /* Number of elements in metaArray + * (will be nPairs for objects) */ + bool isScalar; /* Pseudo-array scalar value? */ + JEntry *meta; + + /* Current item in buffer (up to nElems, but must * 2 for objects) */ + int i; + + /* + * Data proper. Note that this points just past end of "meta" array. We + * use its metadata (Jentrys) with JBE_OFF() macro to find appropriate + * offsets into this array. + */ + char *dataProper; + + /* Private state */ + JsonbIterState state; + + struct JsonbIterator *parent; +} JsonbIterator; + +/* I/O routines */ +extern Datum jsonb_in(PG_FUNCTION_ARGS); +extern Datum jsonb_out(PG_FUNCTION_ARGS); +extern Datum jsonb_recv(PG_FUNCTION_ARGS); +extern Datum jsonb_send(PG_FUNCTION_ARGS); +extern Datum jsonb_typeof(PG_FUNCTION_ARGS); + +/* Indexing-related ops */ +extern Datum jsonb_exists(PG_FUNCTION_ARGS); +extern Datum jsonb_exists_any(PG_FUNCTION_ARGS); +extern Datum jsonb_exists_all(PG_FUNCTION_ARGS); +extern Datum jsonb_contains(PG_FUNCTION_ARGS); +extern Datum jsonb_contained(PG_FUNCTION_ARGS); +extern Datum jsonb_ne(PG_FUNCTION_ARGS); +extern Datum jsonb_lt(PG_FUNCTION_ARGS); +extern Datum jsonb_gt(PG_FUNCTION_ARGS); +extern Datum jsonb_le(PG_FUNCTION_ARGS); +extern Datum jsonb_ge(PG_FUNCTION_ARGS); +extern Datum jsonb_eq(PG_FUNCTION_ARGS); +extern Datum jsonb_cmp(PG_FUNCTION_ARGS); +extern Datum jsonb_hash(PG_FUNCTION_ARGS); + +/* GIN support functions */ +extern Datum gin_compare_jsonb(PG_FUNCTION_ARGS); +extern Datum gin_extract_jsonb(PG_FUNCTION_ARGS); +extern Datum gin_extract_jsonb_query(PG_FUNCTION_ARGS); +extern Datum gin_consistent_jsonb(PG_FUNCTION_ARGS); +extern Datum gin_triconsistent_jsonb(PG_FUNCTION_ARGS); +/* GIN hash opclass functions */ +extern Datum gin_extract_jsonb_hash(PG_FUNCTION_ARGS); +extern Datum gin_extract_jsonb_query_hash(PG_FUNCTION_ARGS); +extern Datum gin_consistent_jsonb_hash(PG_FUNCTION_ARGS); +extern Datum gin_triconsistent_jsonb_hash(PG_FUNCTION_ARGS); + +/* Support functions */ +extern int compareJsonbSuperHeaderValue(JsonbSuperHeader a, + JsonbSuperHeader b); +extern JsonbValue *findJsonbValueFromSuperHeader(JsonbSuperHeader sheader, + uint32 flags, + uint32 *lowbound, + JsonbValue *key); +extern JsonbValue *getIthJsonbValueFromSuperHeader(JsonbSuperHeader sheader, + uint32 i); +extern JsonbValue *pushJsonbValue(JsonbParseState ** pstate, int seq, + JsonbValue *scalarVal); +extern JsonbIterator *JsonbIteratorInit(JsonbSuperHeader buffer); +extern int JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, + bool skipNested); +extern Jsonb *JsonbValueToJsonb(JsonbValue *val); +extern bool JsonbDeepContains(JsonbIterator ** val, + JsonbIterator ** mContained); +extern JsonbValue *arrayToJsonbSortedArray(ArrayType *a); +extern void JsonbHashScalarValue(const JsonbValue * scalarVal, uint32 * hash); + +/* jsonb.c support function */ +extern char *JsonbToCString(StringInfo out, JsonbSuperHeader in, + int estimated_len); + +#endif /* __JSONB_H__ */ diff --git a/src/include/utils/numeric.h b/src/include/utils/numeric.h index c230e0f415..d298718f7d 100644 --- a/src/include/utils/numeric.h +++ b/src/include/utils/numeric.h @@ -58,5 +58,6 @@ typedef struct NumericData *Numeric; extern bool numeric_is_nan(Numeric num); int32 numeric_maximum_size(int32 typmod); extern char *numeric_out_sci(Numeric num, int scale); +extern char *numeric_normalize(Numeric num); #endif /* _PG_NUMERIC_H_ */ |
