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