PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
jsonb_plperl.c
Go to the documentation of this file.
1#include "postgres.h"
2
3#include <math.h>
4
5#include "fmgr.h"
6#include "plperl.h"
7#include "utils/fmgrprotos.h"
8#include "utils/jsonb.h"
9
11 .name = "jsonb_plperl",
12 .version = PG_VERSION
13);
14
15static SV *Jsonb_to_SV(JsonbContainer *jsonb);
16static JsonbValue *SV_to_JsonbValue(SV *obj, JsonbParseState **ps, bool is_elem);
17
18
19static SV *
21{
22 dTHX;
23
24 switch (jbv->type)
25 {
26 case jbvBinary:
27 return Jsonb_to_SV(jbv->val.binary.data);
28
29 case jbvNumeric:
30 {
32 NumericGetDatum(jbv->val.numeric)));
33 SV *result = newSVnv(SvNV(cstr2sv(str)));
34
35 pfree(str);
36 return result;
37 }
38
39 case jbvString:
40 {
41 char *str = pnstrdup(jbv->val.string.val,
42 jbv->val.string.len);
43 SV *result = cstr2sv(str);
44
45 pfree(str);
46 return result;
47 }
48
49 case jbvBool:
50 return newSVnv(SvNV(jbv->val.boolean ? &PL_sv_yes : &PL_sv_no));
51
52 case jbvNull:
53 return newSV(0);
54
55 default:
56 elog(ERROR, "unexpected jsonb value type: %d", jbv->type);
57 return NULL;
58 }
59}
60
61static SV *
63{
64 dTHX;
65 JsonbValue v;
66 JsonbIterator *it;
68
69 it = JsonbIteratorInit(jsonb);
70 r = JsonbIteratorNext(&it, &v, true);
71
72 switch (r)
73 {
74 case WJB_BEGIN_ARRAY:
75 if (v.val.array.rawScalar)
76 {
77 JsonbValue tmp;
78
79 if ((r = JsonbIteratorNext(&it, &v, true)) != WJB_ELEM ||
80 (r = JsonbIteratorNext(&it, &tmp, true)) != WJB_END_ARRAY ||
81 (r = JsonbIteratorNext(&it, &tmp, true)) != WJB_DONE)
82 elog(ERROR, "unexpected jsonb token: %d", r);
83
84 return JsonbValue_to_SV(&v);
85 }
86 else
87 {
88 AV *av = newAV();
89
90 while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
91 {
92 if (r == WJB_ELEM)
93 av_push(av, JsonbValue_to_SV(&v));
94 }
95
96 return newRV((SV *) av);
97 }
98
100 {
101 HV *hv = newHV();
102
103 while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
104 {
105 if (r == WJB_KEY)
106 {
107 /* json key in v, json value in val */
109
110 if (JsonbIteratorNext(&it, &val, true) == WJB_VALUE)
111 {
112 SV *value = JsonbValue_to_SV(&val);
113
114 (void) hv_store(hv,
115 v.val.string.val, v.val.string.len,
116 value, 0);
117 }
118 }
119 }
120
121 return newRV((SV *) hv);
122 }
123
124 default:
125 elog(ERROR, "unexpected jsonb token: %d", r);
126 return NULL;
127 }
128}
129
130static JsonbValue *
131AV_to_JsonbValue(AV *in, JsonbParseState **jsonb_state)
132{
133 dTHX;
134 SSize_t pcount = av_len(in) + 1;
135 SSize_t i;
136
137 pushJsonbValue(jsonb_state, WJB_BEGIN_ARRAY, NULL);
138
139 for (i = 0; i < pcount; i++)
140 {
141 SV **value = av_fetch(in, i, FALSE);
142
143 if (value)
144 (void) SV_to_JsonbValue(*value, jsonb_state, true);
145 }
146
147 return pushJsonbValue(jsonb_state, WJB_END_ARRAY, NULL);
148}
149
150static JsonbValue *
151HV_to_JsonbValue(HV *obj, JsonbParseState **jsonb_state)
152{
153 dTHX;
155 SV *val;
156 char *kstr;
157 I32 klen;
158
159 key.type = jbvString;
160
161 pushJsonbValue(jsonb_state, WJB_BEGIN_OBJECT, NULL);
162
163 (void) hv_iterinit(obj);
164
165 while ((val = hv_iternextsv(obj, &kstr, &klen)))
166 {
167 key.val.string.val = pnstrdup(kstr, klen);
168 key.val.string.len = klen;
169 pushJsonbValue(jsonb_state, WJB_KEY, &key);
170 (void) SV_to_JsonbValue(val, jsonb_state, false);
171 }
172
173 return pushJsonbValue(jsonb_state, WJB_END_OBJECT, NULL);
174}
175
176static JsonbValue *
177SV_to_JsonbValue(SV *in, JsonbParseState **jsonb_state, bool is_elem)
178{
179 dTHX;
180 JsonbValue out; /* result */
181
182 /* Dereference references recursively. */
183 while (SvROK(in))
184 in = SvRV(in);
185
186 switch (SvTYPE(in))
187 {
188 case SVt_PVAV:
189 return AV_to_JsonbValue((AV *) in, jsonb_state);
190
191 case SVt_PVHV:
192 return HV_to_JsonbValue((HV *) in, jsonb_state);
193
194 default:
195 if (!SvOK(in))
196 {
197 out.type = jbvNull;
198 }
199 else if (SvUOK(in))
200 {
201 /*
202 * If UV is >=64 bits, we have no better way to make this
203 * happen than converting to text and back. Given the low
204 * usage of UV in Perl code, it's not clear it's worth working
205 * hard to provide alternate code paths.
206 */
207 const char *strval = SvPV_nolen(in);
208
209 out.type = jbvNumeric;
210 out.val.numeric =
212 CStringGetDatum(strval),
214 Int32GetDatum(-1)));
215 }
216 else if (SvIOK(in))
217 {
218 IV ival = SvIV(in);
219
220 out.type = jbvNumeric;
221 out.val.numeric = int64_to_numeric(ival);
222 }
223 else if (SvNOK(in))
224 {
225 double nval = SvNV(in);
226
227 /*
228 * jsonb doesn't allow infinity or NaN (per JSON
229 * specification), but the numeric type that is used for the
230 * storage accepts those, so we have to reject them here
231 * explicitly.
232 */
233 if (isinf(nval))
235 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
236 errmsg("cannot convert infinity to jsonb")));
237 if (isnan(nval))
239 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
240 errmsg("cannot convert NaN to jsonb")));
241
242 out.type = jbvNumeric;
243 out.val.numeric =
245 Float8GetDatum(nval)));
246 }
247 else if (SvPOK(in))
248 {
249 out.type = jbvString;
250 out.val.string.val = sv2cstr(in);
251 out.val.string.len = strlen(out.val.string.val);
252 }
253 else
254 {
255 /*
256 * XXX It might be nice if we could include the Perl type in
257 * the error message.
258 */
260 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
261 errmsg("cannot transform this Perl type to jsonb")));
262 return NULL;
263 }
264 }
265
266 /* Push result into 'jsonb_state' unless it is a raw scalar. */
267 return *jsonb_state
268 ? pushJsonbValue(jsonb_state, is_elem ? WJB_ELEM : WJB_VALUE, &out)
269 : memcpy(palloc(sizeof(JsonbValue)), &out, sizeof(JsonbValue));
270}
271
272
274
275Datum
277{
278 dTHX;
279 Jsonb *in = PG_GETARG_JSONB_P(0);
280 SV *sv = Jsonb_to_SV(&in->root);
281
282 return PointerGetDatum(sv);
283}
284
285
287
288Datum
290{
291 dTHX;
292 JsonbParseState *jsonb_state = NULL;
293 SV *in = (SV *) PG_GETARG_POINTER(0);
294 JsonbValue *out = SV_to_JsonbValue(in, &jsonb_state, true);
295 Jsonb *result = JsonbValueToJsonb(out);
296
297 PG_RETURN_JSONB_P(result);
298}
Datum float8_numeric(PG_FUNCTION_ARGS)
Definition: numeric.c:4711
Numeric int64_to_numeric(int64 val)
Definition: numeric.c:4401
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:816
Datum numeric_in(PG_FUNCTION_ARGS)
Definition: numeric.c:637
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
Datum Float8GetDatum(float8 X)
Definition: fmgr.c:1816
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:682
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:686
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
const char * str
struct parser_state ps
long val
Definition: informix.c:689
static struct @165 value
int i
Definition: isn.c:77
@ jbvNumeric
Definition: jsonb.h:230
@ jbvBool
Definition: jsonb.h:231
@ jbvBinary
Definition: jsonb.h:236
@ jbvNull
Definition: jsonb.h:228
@ jbvString
Definition: jsonb.h:229
#define PG_RETURN_JSONB_P(x)
Definition: jsonb.h:393
#define PG_GETARG_JSONB_P(x)
Definition: jsonb.h:391
JsonbIteratorToken
Definition: jsonb.h:21
@ WJB_KEY
Definition: jsonb.h:23
@ WJB_DONE
Definition: jsonb.h:22
@ WJB_END_ARRAY
Definition: jsonb.h:27
@ WJB_VALUE
Definition: jsonb.h:24
@ WJB_END_OBJECT
Definition: jsonb.h:29
@ WJB_ELEM
Definition: jsonb.h:25
@ WJB_BEGIN_OBJECT
Definition: jsonb.h:28
@ WJB_BEGIN_ARRAY
Definition: jsonb.h:26
static SV * JsonbValue_to_SV(JsonbValue *jbv)
Definition: jsonb_plperl.c:20
static SV * Jsonb_to_SV(JsonbContainer *jsonb)
Definition: jsonb_plperl.c:62
PG_FUNCTION_INFO_V1(jsonb_to_plperl)
static JsonbValue * HV_to_JsonbValue(HV *obj, JsonbParseState **jsonb_state)
Definition: jsonb_plperl.c:151
static JsonbValue * SV_to_JsonbValue(SV *obj, JsonbParseState **ps, bool is_elem)
Definition: jsonb_plperl.c:177
Datum jsonb_to_plperl(PG_FUNCTION_ARGS)
Definition: jsonb_plperl.c:276
static JsonbValue * AV_to_JsonbValue(AV *in, JsonbParseState **jsonb_state)
Definition: jsonb_plperl.c:131
Datum plperl_to_jsonb(PG_FUNCTION_ARGS)
Definition: jsonb_plperl.c:289
PG_MODULE_MAGIC_EXT(.name="jsonb_plperl",.version=PG_VERSION)
JsonbValue * pushJsonbValue(JsonbParseState **pstate, JsonbIteratorToken seq, JsonbValue *jbval)
Definition: jsonb_util.c:573
JsonbIterator * JsonbIteratorInit(JsonbContainer *container)
Definition: jsonb_util.c:824
JsonbIteratorToken JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested)
Definition: jsonb_util.c:860
Jsonb * JsonbValueToJsonb(JsonbValue *val)
Definition: jsonb_util.c:92
void pfree(void *pointer)
Definition: mcxt.c:2150
void * palloc(Size size)
Definition: mcxt.c:1943
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:2336
static Numeric DatumGetNumeric(Datum X)
Definition: numeric.h:61
static Datum NumericGetDatum(Numeric X)
Definition: numeric.h:73
static char * sv2cstr(SV *sv)
Definition: plperl.h:89
static SV * cstr2sv(const char *str)
Definition: plperl.h:147
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static char * DatumGetCString(Datum X)
Definition: postgres.h:340
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:355
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:217
#define InvalidOid
Definition: postgres_ext.h:35
#define PL_sv_yes
Definition: ppport.h:11781
#define dTHX
Definition: ppport.h:11306
#define SvPV_nolen(sv)
Definition: ppport.h:14072
#define PL_sv_no
Definition: ppport.h:11779
struct @10::@11 av[32]
enum jbvType type
Definition: jsonb.h:255
char * val
Definition: jsonb.h:264
Definition: jsonb.h:213
JsonbContainer root
Definition: jsonb.h:215
const char * name