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 "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 void SV_to_JsonbValue(SV *obj, JsonbInState *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;
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)
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 {
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 void
132{
133 dTHX;
134 SSize_t pcount = av_len(in) + 1;
135 SSize_t i;
136
138
139 for (i = 0; i < pcount; i++)
140 {
141 SV **value = av_fetch(in, i, FALSE);
142
143 if (value)
145 }
146
148}
149
150static void
152{
153 dTHX;
154 JsonbValue key;
155 SV *val;
156 char *kstr;
157 I32 klen;
158
159 key.type = jbvString;
160
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;
171 }
172
174}
175
176static void
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:
190 return;
191
192 case SVt_PVHV:
194 return;
195
196 default:
197 if (!SvOK(in))
198 {
199 out.type = jbvNull;
200 }
201 else if (SvUOK(in))
202 {
203 /*
204 * If UV is >=64 bits, we have no better way to make this
205 * happen than converting to text and back. Given the low
206 * usage of UV in Perl code, it's not clear it's worth working
207 * hard to provide alternate code paths.
208 */
209 const char *strval = SvPV_nolen(in);
210
211 out.type = jbvNumeric;
212 out.val.numeric =
214 CStringGetDatum(strval),
216 Int32GetDatum(-1)));
217 }
218 else if (SvIOK(in))
219 {
220 IV ival = SvIV(in);
221
222 out.type = jbvNumeric;
223 out.val.numeric = int64_to_numeric(ival);
224 }
225 else if (SvNOK(in))
226 {
227 double nval = SvNV(in);
228
229 /*
230 * jsonb doesn't allow infinity or NaN (per JSON
231 * specification), but the numeric type that is used for the
232 * storage accepts those, so we have to reject them here
233 * explicitly.
234 */
235 if (isinf(nval))
238 errmsg("cannot convert infinity to jsonb")));
239 if (isnan(nval))
242 errmsg("cannot convert NaN to jsonb")));
243
244 out.type = jbvNumeric;
245 out.val.numeric =
248 }
249 else if (SvPOK(in))
250 {
251 out.type = jbvString;
252 out.val.string.val = sv2cstr(in);
253 out.val.string.len = strlen(out.val.string.val);
254 }
255 else
256 {
257 /*
258 * XXX It might be nice if we could include the Perl type in
259 * the error message.
260 */
263 errmsg("cannot transform this Perl type to jsonb")));
264 }
265 }
266
267 if (jsonb_state->parseState)
268 {
269 /* We're in an array or object, so push value as element or field. */
271 }
272 else
273 {
274 /*
275 * We are at top level, so it's a raw scalar. If we just shove the
276 * scalar value into jsonb_state->result, JsonbValueToJsonb will take
277 * care of wrapping it into a dummy array.
278 */
280 memcpy(jsonb_state->result, &out, sizeof(JsonbValue));
281 }
282}
283
284
286
287Datum
289{
290 dTHX;
291 Jsonb *in = PG_GETARG_JSONB_P(0);
292 SV *sv = Jsonb_to_SV(&in->root);
293
294 return PointerGetDatum(sv);
295}
296
297
299
300Datum
Datum float8_numeric(PG_FUNCTION_ARGS)
Definition numeric.c:4521
Numeric int64_to_numeric(int64 val)
Definition numeric.c:4259
Datum numeric_out(PG_FUNCTION_ARGS)
Definition numeric.c:799
Datum numeric_in(PG_FUNCTION_ARGS)
Definition numeric.c:626
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
#define palloc_object(type)
Definition fe_memutils.h:74
#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:684
#define PG_FUNCTION_INFO_V1(funcname)
Definition fmgr.h:417
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition fmgr.h:688
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
const char * str
struct parser_state ps
long val
Definition informix.c:689
static struct @172 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 *obj, JsonbInState *ps, 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:1616
char * pnstrdup(const char *in, Size len)
Definition mcxt.c:1792
static Numeric DatumGetNumeric(Datum X)
Definition numeric.h:64
static Datum NumericGetDatum(Numeric X)
Definition numeric.h:76
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:352
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:262
static char * DatumGetCString(Datum X)
Definition postgres.h:365
uint64_t Datum
Definition postgres.h:70
static Datum Float8GetDatum(float8 X)
Definition postgres.h:512
static Datum CStringGetDatum(const char *X)
Definition postgres.h:380
static Datum Int32GetDatum(int32 X)
Definition postgres.h:222
#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]
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