PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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 "miscadmin.h"
7#include "plperl.h"
8#include "utils/fmgrprotos.h"
9#include "utils/jsonb.h"
10
12 .name = "jsonb_plperl",
13 .version = PG_VERSION
14);
15
16static SV *Jsonb_to_SV(JsonbContainer *jsonb);
17static void SV_to_JsonbValue(SV *in, JsonbInState *jsonb_state, bool is_elem);
18
19
20static SV *
22{
23 dTHX;
24
25 switch (jbv->type)
26 {
27 case jbvBinary:
28 return Jsonb_to_SV(jbv->val.binary.data);
29
30 case jbvNumeric:
31 {
33 NumericGetDatum(jbv->val.numeric)));
35
36 pfree(str);
37 return result;
38 }
39
40 case jbvString:
41 {
42 char *str = pnstrdup(jbv->val.string.val,
43 jbv->val.string.len);
44 SV *result = cstr2sv(str);
45
46 pfree(str);
47 return result;
48 }
49
50 case jbvBool:
51 return newSVnv(SvNV(jbv->val.boolean ? &PL_sv_yes : &PL_sv_no));
52
53 case jbvNull:
54 return newSV(0);
55
56 default:
57 elog(ERROR, "unexpected jsonb value type: %d", jbv->type);
58 return NULL;
59 }
60}
61
62static SV *
64{
65 dTHX;
66 JsonbValue v;
69
70 /* this can recurse via JsonbValue_to_SV() */
72
73 it = JsonbIteratorInit(jsonb);
74 r = JsonbIteratorNext(&it, &v, true);
75
76 switch (r)
77 {
78 case WJB_BEGIN_ARRAY:
79 if (v.val.array.rawScalar)
80 {
81 JsonbValue tmp;
82
83 if ((r = JsonbIteratorNext(&it, &v, true)) != WJB_ELEM ||
84 (r = JsonbIteratorNext(&it, &tmp, true)) != WJB_END_ARRAY ||
85 (r = JsonbIteratorNext(&it, &tmp, true)) != WJB_DONE)
86 elog(ERROR, "unexpected jsonb token: %d", r);
87
88 return JsonbValue_to_SV(&v);
89 }
90 else
91 {
92 AV *av = newAV();
93
94 while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
95 {
96 if (r == WJB_ELEM)
98 }
99
100 return newRV((SV *) av);
101 }
102
103 case WJB_BEGIN_OBJECT:
104 {
105 HV *hv = newHV();
106
107 while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
108 {
109 if (r == WJB_KEY)
110 {
111 /* json key in v, json value in val */
113
114 if (JsonbIteratorNext(&it, &val, true) == WJB_VALUE)
115 {
117
118 (void) hv_store(hv,
119 v.val.string.val, v.val.string.len,
120 value, 0);
121 }
122 }
123 }
124
125 return newRV((SV *) hv);
126 }
127
128 default:
129 elog(ERROR, "unexpected jsonb token: %d", r);
130 return NULL;
131 }
132}
133
134static void
136{
137 dTHX;
138 SSize_t pcount = av_len(in) + 1;
139 SSize_t i;
140
142
143 for (i = 0; i < pcount; i++)
144 {
145 SV **value = av_fetch(in, i, FALSE);
146
147 if (value)
149 }
150
152}
153
154static void
156{
157 dTHX;
158 JsonbValue key;
159 SV *val;
160 char *kstr;
161 I32 klen;
162
163 key.type = jbvString;
164
166
167 (void) hv_iterinit(obj);
168
169 while ((val = hv_iternextsv(obj, &kstr, &klen)))
170 {
171 key.val.string.val = pnstrdup(kstr, klen);
172 key.val.string.len = klen;
175 }
176
178}
179
180static void
182{
183 dTHX;
184 JsonbValue out; /* result */
185
186 /* this can recurse via AV_to_JsonbValue() or HV_to_JsonbValue() */
188
189 /* Dereference references recursively. */
190 while (SvROK(in))
191 {
192 /*
193 * It's possible for circular references to make this an infinite
194 * loop. Checking for such a situation seems like much more trouble
195 * than it's worth, but let's provide a way to break out of the loop.
196 */
198 in = SvRV(in);
199 }
200
201 switch (SvTYPE(in))
202 {
203 case SVt_PVAV:
205 return;
206
207 case SVt_PVHV:
209 return;
210
211 default:
212 if (!SvOK(in))
213 {
214 out.type = jbvNull;
215 }
216 else if (SvUOK(in))
217 {
218 /*
219 * If UV is >=64 bits, we have no better way to make this
220 * happen than converting to text and back. Given the low
221 * usage of UV in Perl code, it's not clear it's worth working
222 * hard to provide alternate code paths.
223 */
224 const char *strval = SvPV_nolen(in);
225
226 out.type = jbvNumeric;
227 out.val.numeric =
229 CStringGetDatum(strval),
231 Int32GetDatum(-1)));
232 }
233 else if (SvIOK(in))
234 {
235 IV ival = SvIV(in);
236
237 out.type = jbvNumeric;
238 out.val.numeric = int64_to_numeric(ival);
239 }
240 else if (SvNOK(in))
241 {
242 double nval = SvNV(in);
243
244 /*
245 * jsonb doesn't allow infinity or NaN (per JSON
246 * specification), but the numeric type that is used for the
247 * storage accepts those, so we have to reject them here
248 * explicitly.
249 */
250 if (isinf(nval))
253 errmsg("cannot convert infinity to jsonb")));
254 if (isnan(nval))
257 errmsg("cannot convert NaN to jsonb")));
258
259 out.type = jbvNumeric;
260 out.val.numeric =
263 }
264 else if (SvPOK(in))
265 {
266 out.type = jbvString;
267 out.val.string.val = sv2cstr(in);
268 out.val.string.len = strlen(out.val.string.val);
269 }
270 else
271 {
272 /*
273 * XXX It might be nice if we could include the Perl type in
274 * the error message.
275 */
278 errmsg("cannot transform this Perl type to jsonb")));
279 }
280 }
281
282 if (jsonb_state->parseState)
283 {
284 /* We're in an array or object, so push value as element or field. */
286 }
287 else
288 {
289 /*
290 * We are at top level, so it's a raw scalar. If we just shove the
291 * scalar value into jsonb_state->result, JsonbValueToJsonb will take
292 * care of wrapping it into a dummy array.
293 */
295 memcpy(jsonb_state->result, &out, sizeof(JsonbValue));
296 }
297}
298
299
301
302Datum
304{
305 dTHX;
306 Jsonb *in = PG_GETARG_JSONB_P(0);
307 SV *sv = Jsonb_to_SV(&in->root);
308
309 return PointerGetDatum(sv);
310}
311
312
314
315Datum
Datum float8_numeric(PG_FUNCTION_ARGS)
Definition numeric.c:4544
Numeric int64_to_numeric(int64 val)
Definition numeric.c:4270
Datum numeric_out(PG_FUNCTION_ARGS)
Definition numeric.c:799
Datum numeric_in(PG_FUNCTION_ARGS)
Definition numeric.c:626
uint32 result
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
int errcode(int sqlerrcode)
Definition elog.c:875
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
#define palloc_object(type)
Definition fe_memutils.h:89
#define PG_GETARG_POINTER(n)
Definition fmgr.h:277
#define PG_MODULE_MAGIC_EXT(...)
Definition fmgr.h:540
#define DirectFunctionCall1(func, arg1)
Definition fmgr.h:688
#define PG_FUNCTION_INFO_V1(funcname)
Definition fmgr.h:417
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition fmgr.h:692
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
const char * str
long val
Definition informix.c:689
static struct @173 value
int i
Definition isn.c:77
@ jbvNumeric
Definition jsonb.h:232
@ jbvBool
Definition jsonb.h:233
@ jbvBinary
Definition jsonb.h:238
@ jbvNull
Definition jsonb.h:230
@ jbvString
Definition jsonb.h:231
#define PG_RETURN_JSONB_P(x)
Definition jsonb.h:420
#define PG_GETARG_JSONB_P(x)
Definition jsonb.h:418
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)
static SV * Jsonb_to_SV(JsonbContainer *jsonb)
static void HV_to_JsonbValue(HV *obj, JsonbInState *jsonb_state)
static void SV_to_JsonbValue(SV *in, JsonbInState *jsonb_state, bool is_elem)
Datum jsonb_to_plperl(PG_FUNCTION_ARGS)
static void AV_to_JsonbValue(AV *in, JsonbInState *jsonb_state)
Datum plperl_to_jsonb(PG_FUNCTION_ARGS)
void pushJsonbValue(JsonbInState *pstate, JsonbIteratorToken seq, JsonbValue *jbval)
Definition jsonb_util.c:583
JsonbIterator * JsonbIteratorInit(JsonbContainer *container)
Definition jsonb_util.c:935
JsonbIteratorToken JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested)
Definition jsonb_util.c:973
Jsonb * JsonbValueToJsonb(JsonbValue *val)
Definition jsonb_util.c:96
void pfree(void *pointer)
Definition mcxt.c:1619
char * pnstrdup(const char *in, Size len)
Definition mcxt.c:1921
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:125
static Numeric DatumGetNumeric(Datum X)
Definition numeric.h:64
static Datum NumericGetDatum(Numeric X)
Definition numeric.h:76
static char * errmsg
static char * sv2cstr(SV *sv)
Definition plperl.h:89
static SV * cstr2sv(const char *str)
Definition plperl.h:147
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
static char * DatumGetCString(Datum X)
Definition postgres.h:365
uint64_t Datum
Definition postgres.h:70
static Datum Float8GetDatum(float8 X)
Definition postgres.h:515
static Datum CStringGetDatum(const char *X)
Definition postgres.h:383
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212
#define PointerGetDatum(X)
Definition postgres.h:354
#define InvalidOid
#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
static int fb(int x)
struct @10::@11 av[32]
void check_stack_depth(void)
Definition stack_depth.c:96
enum jbvType type
Definition jsonb.h:257
char * val
Definition jsonb.h:266
Definition jsonb.h:215
JsonbContainer root
Definition jsonb.h:217
const char * name