Age Owner TLA Line data Source code
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"
1832 peter_e 9 ECB :
1832 peter_e 10 GIC 2 : PG_MODULE_MAGIC;
11 :
12 : static SV *Jsonb_to_SV(JsonbContainer *jsonb);
13 : static JsonbValue *SV_to_JsonbValue(SV *obj, JsonbParseState **ps, bool is_elem);
14 :
15 :
1809 tgl 16 ECB : static SV *
1832 peter_e 17 GIC 81 : JsonbValue_to_SV(JsonbValue *jbv)
1832 peter_e 18 ECB : {
1832 peter_e 19 GIC 81 : dTHX;
1832 peter_e 20 ECB :
1832 peter_e 21 GIC 81 : switch (jbv->type)
1832 peter_e 22 ECB : {
1832 peter_e 23 CBC 6 : case jbvBinary:
1756 tgl 24 GIC 6 : return Jsonb_to_SV(jbv->val.binary.data);
1832 peter_e 25 ECB :
1832 peter_e 26 GIC 49 : case jbvNumeric:
1832 peter_e 27 ECB : {
1832 peter_e 28 GIC 49 : char *str = DatumGetCString(DirectFunctionCall1(numeric_out,
1832 peter_e 29 ECB : NumericGetDatum(jbv->val.numeric)));
1832 peter_e 30 GIC 49 : SV *result = newSVnv(SvNV(cstr2sv(str)));
1809 tgl 31 ECB :
1832 peter_e 32 CBC 49 : pfree(str);
1832 peter_e 33 GIC 49 : return result;
34 : }
1832 peter_e 35 ECB :
1832 peter_e 36 GIC 14 : case jbvString:
1832 peter_e 37 ECB : {
1832 peter_e 38 CBC 14 : char *str = pnstrdup(jbv->val.string.val,
39 14 : jbv->val.string.len);
1832 peter_e 40 GIC 14 : SV *result = cstr2sv(str);
1809 tgl 41 ECB :
1832 peter_e 42 CBC 14 : pfree(str);
1832 peter_e 43 GIC 14 : return result;
44 : }
1832 peter_e 45 ECB :
1832 peter_e 46 CBC 4 : case jbvBool:
1832 peter_e 47 GIC 4 : return newSVnv(SvNV(jbv->val.boolean ? &PL_sv_yes : &PL_sv_no));
1832 peter_e 48 ECB :
1832 peter_e 49 CBC 8 : case jbvNull:
1832 peter_e 50 GIC 8 : return newSV(0);
1832 peter_e 51 EUB :
1832 peter_e 52 UBC 0 : default:
1832 peter_e 53 UIC 0 : elog(ERROR, "unexpected jsonb value type: %d", jbv->type);
54 : return NULL;
55 : }
56 : }
57 :
1832 peter_e 58 ECB : static SV *
1832 peter_e 59 GIC 57 : Jsonb_to_SV(JsonbContainer *jsonb)
1832 peter_e 60 ECB : {
1832 peter_e 61 GIC 57 : dTHX;
62 : JsonbValue v;
63 : JsonbIterator *it;
64 : JsonbIteratorToken r;
1832 peter_e 65 ECB :
1832 peter_e 66 CBC 57 : it = JsonbIteratorInit(jsonb);
1832 peter_e 67 GIC 57 : r = JsonbIteratorNext(&it, &v, true);
1832 peter_e 68 ECB :
1832 peter_e 69 GIC 57 : switch (r)
1832 peter_e 70 ECB : {
1832 peter_e 71 CBC 39 : case WJB_BEGIN_ARRAY:
1832 peter_e 72 GIC 39 : if (v.val.array.rawScalar)
73 : {
74 : JsonbValue tmp;
1832 peter_e 75 ECB :
1832 peter_e 76 CBC 38 : if ((r = JsonbIteratorNext(&it, &v, true)) != WJB_ELEM ||
77 38 : (r = JsonbIteratorNext(&it, &tmp, true)) != WJB_END_ARRAY ||
1832 peter_e 78 GBC 19 : (r = JsonbIteratorNext(&it, &tmp, true)) != WJB_DONE)
1832 peter_e 79 UIC 0 : elog(ERROR, "unexpected jsonb token: %d", r);
1832 peter_e 80 ECB :
1756 tgl 81 GIC 19 : return JsonbValue_to_SV(&v);
82 : }
83 : else
1832 peter_e 84 ECB : {
1832 peter_e 85 GIC 20 : AV *av = newAV();
1832 peter_e 86 ECB :
1832 peter_e 87 GIC 104 : while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
1832 peter_e 88 ECB : {
1832 peter_e 89 CBC 64 : if (r == WJB_ELEM)
1832 peter_e 90 GIC 44 : av_push(av, JsonbValue_to_SV(&v));
91 : }
1832 peter_e 92 ECB :
1756 tgl 93 GIC 20 : return newRV((SV *) av);
94 : }
1832 peter_e 95 ECB :
1832 peter_e 96 GIC 18 : case WJB_BEGIN_OBJECT:
1832 peter_e 97 ECB : {
1832 peter_e 98 GIC 18 : HV *hv = newHV();
1832 peter_e 99 ECB :
1832 peter_e 100 GIC 72 : while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
1832 peter_e 101 ECB : {
1832 peter_e 102 GIC 36 : if (r == WJB_KEY)
103 : {
104 : /* json key in v, json value in val */
105 : JsonbValue val;
1832 peter_e 106 ECB :
1832 peter_e 107 GIC 18 : if (JsonbIteratorNext(&it, &val, true) == WJB_VALUE)
1832 peter_e 108 ECB : {
1832 peter_e 109 GIC 18 : SV *value = JsonbValue_to_SV(&val);
1832 peter_e 110 ECB :
1832 peter_e 111 GIC 18 : (void) hv_store(hv,
112 : v.val.string.val, v.val.string.len,
113 : value, 0);
114 : }
115 : }
116 : }
1832 peter_e 117 ECB :
1756 tgl 118 GIC 18 : return newRV((SV *) hv);
119 : }
1832 peter_e 120 EUB :
1832 peter_e 121 UBC 0 : default:
1832 peter_e 122 UIC 0 : elog(ERROR, "unexpected jsonb token: %d", r);
123 : return NULL;
124 : }
125 : }
126 :
1832 peter_e 127 ECB : static JsonbValue *
1832 peter_e 128 GIC 22 : AV_to_JsonbValue(AV *in, JsonbParseState **jsonb_state)
1832 peter_e 129 ECB : {
1832 peter_e 130 CBC 22 : dTHX;
1832 peter_e 131 GIC 22 : SSize_t pcount = av_len(in) + 1;
132 : SSize_t i;
1832 peter_e 133 ECB :
1832 peter_e 134 GIC 22 : pushJsonbValue(jsonb_state, WJB_BEGIN_ARRAY, NULL);
1832 peter_e 135 ECB :
1832 peter_e 136 GIC 70 : for (i = 0; i < pcount; i++)
1832 peter_e 137 ECB : {
1832 peter_e 138 GIC 48 : SV **value = av_fetch(in, i, FALSE);
1832 peter_e 139 ECB :
1832 peter_e 140 CBC 48 : if (value)
1832 peter_e 141 GIC 48 : (void) SV_to_JsonbValue(*value, jsonb_state, true);
142 : }
1832 peter_e 143 ECB :
1832 peter_e 144 GIC 22 : return pushJsonbValue(jsonb_state, WJB_END_ARRAY, NULL);
145 : }
146 :
1832 peter_e 147 ECB : static JsonbValue *
1832 peter_e 148 GIC 28 : HV_to_JsonbValue(HV *obj, JsonbParseState **jsonb_state)
1832 peter_e 149 ECB : {
1832 peter_e 150 GIC 28 : dTHX;
151 : JsonbValue key;
152 : SV *val;
153 : char *kstr;
154 : I32 klen;
1832 peter_e 155 ECB :
1832 peter_e 156 GIC 28 : key.type = jbvString;
1832 peter_e 157 ECB :
1832 peter_e 158 GIC 28 : pushJsonbValue(jsonb_state, WJB_BEGIN_OBJECT, NULL);
1832 peter_e 159 ECB :
1832 peter_e 160 GIC 28 : (void) hv_iterinit(obj);
1832 peter_e 161 ECB :
1832 tgl 162 GIC 64 : while ((val = hv_iternextsv(obj, &kstr, &klen)))
1832 peter_e 163 ECB : {
1832 tgl 164 CBC 36 : key.val.string.val = pnstrdup(kstr, klen);
165 36 : key.val.string.len = klen;
peter_e 166 36 : pushJsonbValue(jsonb_state, WJB_KEY, &key);
1832 peter_e 167 GIC 36 : (void) SV_to_JsonbValue(val, jsonb_state, false);
168 : }
1832 peter_e 169 ECB :
1832 peter_e 170 GIC 28 : return pushJsonbValue(jsonb_state, WJB_END_OBJECT, NULL);
171 : }
172 :
1832 peter_e 173 ECB : static JsonbValue *
1832 peter_e 174 GIC 147 : SV_to_JsonbValue(SV *in, JsonbParseState **jsonb_state, bool is_elem)
1832 peter_e 175 ECB : {
1832 peter_e 176 GIC 147 : dTHX;
177 : JsonbValue out; /* result */
178 :
1832 peter_e 179 ECB : /* Dereference references recursively. */
1832 peter_e 180 CBC 197 : while (SvROK(in))
1832 peter_e 181 GIC 50 : in = SvRV(in);
1832 peter_e 182 ECB :
1832 peter_e 183 GIC 147 : switch (SvTYPE(in))
1832 peter_e 184 ECB : {
1832 peter_e 185 CBC 22 : case SVt_PVAV:
1832 peter_e 186 GIC 22 : return AV_to_JsonbValue((AV *) in, jsonb_state);
1832 peter_e 187 ECB :
1832 peter_e 188 CBC 28 : case SVt_PVHV:
1832 peter_e 189 GIC 28 : return HV_to_JsonbValue((HV *) in, jsonb_state);
1832 peter_e 190 ECB :
1831 tgl 191 CBC 97 : default:
1344 tgl 192 GIC 97 : if (!SvOK(in))
1344 tgl 193 ECB : {
1344 tgl 194 GIC 12 : out.type = jbvNull;
1344 tgl 195 ECB : }
1344 tgl 196 GIC 85 : 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.
1756 tgl 203 ECB : */
1756 tgl 204 GIC 2 : const char *strval = SvPV_nolen(in);
1756 tgl 205 ECB :
1756 tgl 206 CBC 2 : out.type = jbvNumeric;
207 2 : out.val.numeric =
1756 tgl 208 GIC 2 : DatumGetNumeric(DirectFunctionCall3(numeric_in,
209 : CStringGetDatum(strval),
210 : ObjectIdGetDatum(InvalidOid),
211 : Int32GetDatum(-1)));
1756 tgl 212 ECB : }
1756 tgl 213 GIC 83 : else if (SvIOK(in))
1832 peter_e 214 ECB : {
1831 tgl 215 GIC 10 : IV ival = SvIV(in);
1832 peter_e 216 ECB :
1831 tgl 217 CBC 10 : out.type = jbvNumeric;
942 peter 218 GIC 10 : out.val.numeric = int64_to_numeric(ival);
1831 tgl 219 ECB : }
1831 tgl 220 GIC 73 : else if (SvNOK(in))
1831 tgl 221 ECB : {
1831 tgl 222 GIC 53 : 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.
1805 peter_e 229 ECB : */
1831 tgl 230 CBC 53 : if (isinf(nval))
1832 peter_e 231 GIC 1 : ereport(ERROR,
232 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1165 alvherre 233 ECB : errmsg("cannot convert infinity to jsonb")));
1805 peter_e 234 GBC 52 : if (isnan(nval))
1805 peter_e 235 UIC 0 : ereport(ERROR,
236 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
237 : errmsg("cannot convert NaN to jsonb")));
1832 peter_e 238 ECB :
1832 peter_e 239 CBC 52 : out.type = jbvNumeric;
1831 tgl 240 52 : out.val.numeric =
1831 tgl 241 GIC 52 : DatumGetNumeric(DirectFunctionCall1(float8_numeric,
242 : Float8GetDatum(nval)));
1831 tgl 243 ECB : }
1831 tgl 244 GIC 20 : else if (SvPOK(in))
1831 tgl 245 ECB : {
1831 tgl 246 CBC 20 : out.type = jbvString;
247 20 : out.val.string.val = sv2cstr(in);
1831 tgl 248 GIC 20 : 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.
1831 tgl 255 EUB : */
1831 tgl 256 UIC 0 : ereport(ERROR,
257 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
258 : errmsg("cannot transform this Perl type to jsonb")));
259 : return NULL;
260 : }
261 : }
262 :
1832 peter_e 263 ECB : /* Push result into 'jsonb_state' unless it is a raw scalar. */
1832 peter_e 264 CBC 96 : return *jsonb_state
265 74 : ? pushJsonbValue(jsonb_state, is_elem ? WJB_ELEM : WJB_VALUE, &out)
1832 peter_e 266 GIC 170 : : memcpy(palloc(sizeof(JsonbValue)), &out, sizeof(JsonbValue));
267 : }
268 :
1832 peter_e 269 ECB :
1832 peter_e 270 GIC 4 : PG_FUNCTION_INFO_V1(jsonb_to_plperl);
271 :
1832 peter_e 272 ECB : Datum
1832 peter_e 273 GIC 51 : jsonb_to_plperl(PG_FUNCTION_ARGS)
1832 peter_e 274 ECB : {
1832 peter_e 275 CBC 51 : dTHX;
276 51 : Jsonb *in = PG_GETARG_JSONB_P(0);
1832 peter_e 277 GIC 51 : SV *sv = Jsonb_to_SV(&in->root);
1832 peter_e 278 ECB :
1756 tgl 279 GIC 51 : return PointerGetDatum(sv);
280 : }
281 :
1832 peter_e 282 ECB :
1832 peter_e 283 GIC 4 : PG_FUNCTION_INFO_V1(plperl_to_jsonb);
284 :
1832 peter_e 285 ECB : Datum
1832 peter_e 286 GIC 63 : plperl_to_jsonb(PG_FUNCTION_ARGS)
1832 peter_e 287 ECB : {
1832 peter_e 288 CBC 63 : dTHX;
289 63 : JsonbParseState *jsonb_state = NULL;
290 63 : SV *in = (SV *) PG_GETARG_POINTER(0);
291 63 : JsonbValue *out = SV_to_JsonbValue(in, &jsonb_state, true);
1832 peter_e 292 GIC 62 : Jsonb *result = JsonbValueToJsonb(out);
1832 peter_e 293 ECB :
1832 peter_e 294 GIC 62 : PG_RETURN_JSONB_P(result);
295 : }
|