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 17:13:01 Functions: 100.0 % 10 10 10 10
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (240..) days: 94.3 % 122 115 5 2 2 76 37 3 78
Legend: Lines: hit not hit Function coverage date bins:
(240..) days: 50.0 % 20 10 10 10

 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                 : }
        

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