LCOV - differential code coverage report
Current view: top level - contrib/jsonb_plperl - jsonb_plperl.c (source / functions) Coverage Total Hit UIC UBC GBC GIC CBC EUB ECB
Current: Differential Code Coverage HEAD vs 15 Lines: 94.3 % 122 115 5 2 2 76 37 3 78
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 10 10 10 10
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a