LCOV - differential code coverage report
Current view: top level - contrib/jsonb_plperl - jsonb_plperl.c (source / functions) Coverage Total Hit UBC GIC GNC CBC DCB
Current: 7a15cff1f11193467898da1c1fabf06fd2caee04 vs 84a3778c79c2d28b4dc281d03ef2ab019b16483b Lines: 94.4 % 126 119 7 2 18 99 16
Current Date: 2025-12-15 18:36:29 -0500 Functions: 100.0 % 10 10 4 6 3
Baseline: lcov-20251216-010103-baseline Branches: 71.4 % 70 50 20 4 46
Baseline Date: 2025-12-15 13:30:48 -0800 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 100.0 % 18 18 18
(30,360] days: 100.0 % 1 1 1
(360..) days: 93.5 % 107 100 7 2 98
Function coverage date bins:
(7,30] days: 100.0 % 3 3 3
(30,360] days: 100.0 % 1 1 1
(360..) days: 100.0 % 6 6 1 5
Branch coverage date bins:
(7,30] days: 100.0 % 4 4 4
(360..) days: 69.7 % 66 46 20 46

 Age         Owner                    Branch data    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                 :                : 
  265 tgl@sss.pgh.pa.us          10                 :CBC           2 : PG_MODULE_MAGIC_EXT(
                                 11                 :                :                     .name = "jsonb_plperl",
                                 12                 :                :                     .version = PG_VERSION
                                 13                 :                : );
                                 14                 :                : 
                                 15                 :                : static SV  *Jsonb_to_SV(JsonbContainer *jsonb);
                                 16                 :                : static void SV_to_JsonbValue(SV *obj, JsonbInState *ps, bool is_elem);
                                 17                 :                : 
                                 18                 :                : 
                                 19                 :                : static SV  *
 2814 peter_e@gmx.net            20                 :             81 : JsonbValue_to_SV(JsonbValue *jbv)
                                 21                 :                : {
                                 22                 :             81 :     dTHX;
                                 23                 :                : 
                                 24   [ +  +  +  +  :             81 :     switch (jbv->type)
                                              +  - ]
                                 25                 :                :     {
                                 26                 :              6 :         case jbvBinary:
 2738 tgl@sss.pgh.pa.us          27                 :              6 :             return Jsonb_to_SV(jbv->val.binary.data);
                                 28                 :                : 
 2814 peter_e@gmx.net            29                 :             49 :         case jbvNumeric:
                                 30                 :                :             {
                                 31                 :             49 :                 char       *str = DatumGetCString(DirectFunctionCall1(numeric_out,
                                 32                 :                :                                                                       NumericGetDatum(jbv->val.numeric)));
                                 33                 :             49 :                 SV         *result = newSVnv(SvNV(cstr2sv(str)));
                                 34                 :                : 
                                 35                 :             49 :                 pfree(str);
                                 36                 :             49 :                 return result;
                                 37                 :                :             }
                                 38                 :                : 
                                 39                 :             14 :         case jbvString:
                                 40                 :                :             {
                                 41                 :             14 :                 char       *str = pnstrdup(jbv->val.string.val,
                                 42                 :             14 :                                            jbv->val.string.len);
                                 43                 :             14 :                 SV         *result = cstr2sv(str);
                                 44                 :                : 
                                 45                 :             14 :                 pfree(str);
                                 46                 :             14 :                 return result;
                                 47                 :                :             }
                                 48                 :                : 
                                 49                 :              4 :         case jbvBool:
                                 50         [ +  + ]:              4 :             return newSVnv(SvNV(jbv->val.boolean ? &PL_sv_yes : &PL_sv_no));
                                 51                 :                : 
                                 52                 :              8 :         case jbvNull:
                                 53                 :              8 :             return newSV(0);
                                 54                 :                : 
 2814 peter_e@gmx.net            55                 :UBC           0 :         default:
                                 56         [ #  # ]:              0 :             elog(ERROR, "unexpected jsonb value type: %d", jbv->type);
                                 57                 :                :             return NULL;
                                 58                 :                :     }
                                 59                 :                : }
                                 60                 :                : 
                                 61                 :                : static SV  *
 2814 peter_e@gmx.net            62                 :CBC          57 : Jsonb_to_SV(JsonbContainer *jsonb)
                                 63                 :                : {
                                 64                 :             57 :     dTHX;
                                 65                 :                :     JsonbValue  v;
                                 66                 :                :     JsonbIterator *it;
                                 67                 :                :     JsonbIteratorToken r;
                                 68                 :                : 
                                 69                 :             57 :     it = JsonbIteratorInit(jsonb);
                                 70                 :             57 :     r = JsonbIteratorNext(&it, &v, true);
                                 71                 :                : 
                                 72      [ +  +  - ]:             57 :     switch (r)
                                 73                 :                :     {
                                 74                 :             39 :         case WJB_BEGIN_ARRAY:
                                 75         [ +  + ]:             39 :             if (v.val.array.rawScalar)
                                 76                 :                :             {
                                 77                 :                :                 JsonbValue  tmp;
                                 78                 :                : 
                                 79   [ +  -  +  - ]:             38 :                 if ((r = JsonbIteratorNext(&it, &v, true)) != WJB_ELEM ||
                                 80         [ -  + ]:             38 :                     (r = JsonbIteratorNext(&it, &tmp, true)) != WJB_END_ARRAY ||
                                 81                 :             19 :                     (r = JsonbIteratorNext(&it, &tmp, true)) != WJB_DONE)
 2814 peter_e@gmx.net            82         [ #  # ]:UBC           0 :                     elog(ERROR, "unexpected jsonb token: %d", r);
                                 83                 :                : 
 2738 tgl@sss.pgh.pa.us          84                 :CBC          19 :                 return JsonbValue_to_SV(&v);
                                 85                 :                :             }
                                 86                 :                :             else
                                 87                 :                :             {
 2814 peter_e@gmx.net            88                 :             20 :                 AV         *av = newAV();
                                 89                 :                : 
                                 90         [ +  + ]:            104 :                 while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
                                 91                 :                :                 {
                                 92         [ +  + ]:             64 :                     if (r == WJB_ELEM)
                                 93                 :             44 :                         av_push(av, JsonbValue_to_SV(&v));
                                 94                 :                :                 }
                                 95                 :                : 
 2738 tgl@sss.pgh.pa.us          96                 :             20 :                 return newRV((SV *) av);
                                 97                 :                :             }
                                 98                 :                : 
 2814 peter_e@gmx.net            99                 :             18 :         case WJB_BEGIN_OBJECT:
                                100                 :                :             {
                                101                 :             18 :                 HV         *hv = newHV();
                                102                 :                : 
                                103         [ +  + ]:             72 :                 while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
                                104                 :                :                 {
                                105         [ +  + ]:             36 :                     if (r == WJB_KEY)
                                106                 :                :                     {
                                107                 :                :                         /* json key in v, json value in val */
                                108                 :                :                         JsonbValue  val;
                                109                 :                : 
                                110         [ +  - ]:             18 :                         if (JsonbIteratorNext(&it, &val, true) == WJB_VALUE)
                                111                 :                :                         {
                                112                 :             18 :                             SV         *value = JsonbValue_to_SV(&val);
                                113                 :                : 
                                114                 :             18 :                             (void) hv_store(hv,
                                115                 :                :                                             v.val.string.val, v.val.string.len,
                                116                 :                :                                             value, 0);
                                117                 :                :                         }
                                118                 :                :                     }
                                119                 :                :                 }
                                120                 :                : 
 2738 tgl@sss.pgh.pa.us         121                 :             18 :                 return newRV((SV *) hv);
                                122                 :                :             }
                                123                 :                : 
 2814 peter_e@gmx.net           124                 :UBC           0 :         default:
                                125         [ #  # ]:              0 :             elog(ERROR, "unexpected jsonb token: %d", r);
                                126                 :                :             return NULL;
                                127                 :                :     }
                                128                 :                : }
                                129                 :                : 
                                130                 :                : static void
    9 tgl@sss.pgh.pa.us         131                 :GNC          22 : AV_to_JsonbValue(AV *in, JsonbInState *jsonb_state)
                                132                 :                : {
 2814 peter_e@gmx.net           133                 :CBC          22 :     dTHX;
                                134                 :             22 :     SSize_t     pcount = av_len(in) + 1;
                                135                 :                :     SSize_t     i;
                                136                 :                : 
                                137                 :             22 :     pushJsonbValue(jsonb_state, WJB_BEGIN_ARRAY, NULL);
                                138                 :                : 
                                139         [ +  + ]:             70 :     for (i = 0; i < pcount; i++)
                                140                 :                :     {
                                141                 :             48 :         SV        **value = av_fetch(in, i, FALSE);
                                142                 :                : 
                                143         [ +  - ]:             48 :         if (value)
    9 tgl@sss.pgh.pa.us         144                 :GNC          48 :             SV_to_JsonbValue(*value, jsonb_state, true);
                                145                 :                :     }
                                146                 :                : 
                                147                 :             22 :     pushJsonbValue(jsonb_state, WJB_END_ARRAY, NULL);
 2814 peter_e@gmx.net           148                 :GIC          22 : }
                                149                 :                : 
                                150                 :                : static void
    9 tgl@sss.pgh.pa.us         151                 :GNC          28 : HV_to_JsonbValue(HV *obj, JsonbInState *jsonb_state)
                                152                 :                : {
 2814 peter_e@gmx.net           153                 :CBC          28 :     dTHX;
                                154                 :                :     JsonbValue  key;
                                155                 :                :     SV         *val;
                                156                 :                :     char       *kstr;
                                157                 :                :     I32         klen;
                                158                 :                : 
                                159                 :             28 :     key.type = jbvString;
                                160                 :                : 
                                161                 :             28 :     pushJsonbValue(jsonb_state, WJB_BEGIN_OBJECT, NULL);
                                162                 :                : 
                                163                 :             28 :     (void) hv_iterinit(obj);
                                164                 :                : 
      tgl@sss.pgh.pa.us         165         [ +  + ]:             64 :     while ((val = hv_iternextsv(obj, &kstr, &klen)))
                                166                 :                :     {
                                167                 :             36 :         key.val.string.val = pnstrdup(kstr, klen);
                                168                 :             36 :         key.val.string.len = klen;
      peter_e@gmx.net           169                 :             36 :         pushJsonbValue(jsonb_state, WJB_KEY, &key);
    9 tgl@sss.pgh.pa.us         170                 :GNC          36 :         SV_to_JsonbValue(val, jsonb_state, false);
                                171                 :                :     }
                                172                 :                : 
                                173                 :             28 :     pushJsonbValue(jsonb_state, WJB_END_OBJECT, NULL);
 2814 peter_e@gmx.net           174                 :GIC          28 : }
                                175                 :                : 
                                176                 :                : static void
    9 tgl@sss.pgh.pa.us         177                 :GNC         147 : SV_to_JsonbValue(SV *in, JsonbInState *jsonb_state, bool is_elem)
                                178                 :                : {
 2814 peter_e@gmx.net           179                 :CBC         147 :     dTHX;
                                180                 :                :     JsonbValue  out;            /* result */
                                181                 :                : 
                                182                 :                :     /* Dereference references recursively. */
                                183         [ +  + ]:            197 :     while (SvROK(in))
                                184                 :             50 :         in = SvRV(in);
                                185                 :                : 
                                186      [ +  +  + ]:            147 :     switch (SvTYPE(in))
                                187                 :                :     {
                                188                 :             22 :         case SVt_PVAV:
    9 tgl@sss.pgh.pa.us         189                 :GNC          22 :             AV_to_JsonbValue((AV *) in, jsonb_state);
                                190                 :             50 :             return;
                                191                 :                : 
 2814 peter_e@gmx.net           192                 :CBC          28 :         case SVt_PVHV:
    9 tgl@sss.pgh.pa.us         193                 :GNC          28 :             HV_to_JsonbValue((HV *) in, jsonb_state);
                                194                 :             28 :             return;
                                195                 :                : 
 2813 tgl@sss.pgh.pa.us         196                 :CBC          97 :         default:
 2326                           197         [ +  + ]:             97 :             if (!SvOK(in))
                                198                 :                :             {
                                199                 :             12 :                 out.type = jbvNull;
                                200                 :                :             }
                                201         [ +  + ]:             85 :             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                 :                :                  */
 2738                           209                 :              2 :                 const char *strval = SvPV_nolen(in);
                                210                 :                : 
                                211                 :              2 :                 out.type = jbvNumeric;
                                212                 :              2 :                 out.val.numeric =
                                213                 :              2 :                     DatumGetNumeric(DirectFunctionCall3(numeric_in,
                                214                 :                :                                                         CStringGetDatum(strval),
                                215                 :                :                                                         ObjectIdGetDatum(InvalidOid),
                                216                 :                :                                                         Int32GetDatum(-1)));
                                217                 :                :             }
                                218         [ +  + ]:             83 :             else if (SvIOK(in))
                                219                 :                :             {
 2813                           220                 :             10 :                 IV          ival = SvIV(in);
                                221                 :                : 
                                222                 :             10 :                 out.type = jbvNumeric;
 1924 peter@eisentraut.org      223                 :             10 :                 out.val.numeric = int64_to_numeric(ival);
                                224                 :                :             }
 2813 tgl@sss.pgh.pa.us         225         [ +  + ]:             73 :             else if (SvNOK(in))
                                226                 :                :             {
                                227                 :             53 :                 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         [ +  + ]:             53 :                 if (isinf(nval))
 2814 peter_e@gmx.net           236         [ +  - ]:              1 :                     ereport(ERROR,
                                237                 :                :                             (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                                238                 :                :                              errmsg("cannot convert infinity to jsonb")));
 2787                           239         [ -  + ]:             52 :                 if (isnan(nval))
 2787 peter_e@gmx.net           240         [ #  # ]:UBC           0 :                     ereport(ERROR,
                                241                 :                :                             (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                                242                 :                :                              errmsg("cannot convert NaN to jsonb")));
                                243                 :                : 
 2814 peter_e@gmx.net           244                 :CBC          52 :                 out.type = jbvNumeric;
 2813 tgl@sss.pgh.pa.us         245                 :             52 :                 out.val.numeric =
                                246                 :             52 :                     DatumGetNumeric(DirectFunctionCall1(float8_numeric,
                                247                 :                :                                                         Float8GetDatum(nval)));
                                248                 :                :             }
                                249         [ +  - ]:             20 :             else if (SvPOK(in))
                                250                 :                :             {
                                251                 :             20 :                 out.type = jbvString;
                                252                 :             20 :                 out.val.string.val = sv2cstr(in);
                                253                 :             20 :                 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                 :                :                  */
 2813 tgl@sss.pgh.pa.us         261         [ #  # ]:UBC           0 :                 ereport(ERROR,
                                262                 :                :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                263                 :                :                          errmsg("cannot transform this Perl type to jsonb")));
                                264                 :                :             }
                                265                 :                :     }
                                266                 :                : 
    9 tgl@sss.pgh.pa.us         267         [ +  + ]:GNC          96 :     if (jsonb_state->parseState)
                                268                 :                :     {
                                269                 :                :         /* We're in an array or object, so push value as element or field. */
                                270         [ +  + ]:             74 :         pushJsonbValue(jsonb_state, is_elem ? WJB_ELEM : WJB_VALUE, &out);
                                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                 :                :          */
                                279                 :             22 :         jsonb_state->result = palloc_object(JsonbValue);
                                280                 :             22 :         memcpy(jsonb_state->result, &out, sizeof(JsonbValue));
                                281                 :                :     }
                                282                 :                : }
                                283                 :                : 
                                284                 :                : 
 2814 peter_e@gmx.net           285                 :CBC           4 : PG_FUNCTION_INFO_V1(jsonb_to_plperl);
                                286                 :                : 
                                287                 :                : Datum
                                288                 :             51 : jsonb_to_plperl(PG_FUNCTION_ARGS)
                                289                 :                : {
                                290                 :             51 :     dTHX;
                                291                 :             51 :     Jsonb      *in = PG_GETARG_JSONB_P(0);
                                292                 :             51 :     SV         *sv = Jsonb_to_SV(&in->root);
                                293                 :                : 
 2738 tgl@sss.pgh.pa.us         294                 :             51 :     return PointerGetDatum(sv);
                                295                 :                : }
                                296                 :                : 
                                297                 :                : 
 2814 peter_e@gmx.net           298                 :              4 : PG_FUNCTION_INFO_V1(plperl_to_jsonb);
                                299                 :                : 
                                300                 :                : Datum
                                301                 :             63 : plperl_to_jsonb(PG_FUNCTION_ARGS)
                                302                 :                : {
                                303                 :             63 :     dTHX;
                                304                 :             63 :     SV         *in = (SV *) PG_GETARG_POINTER(0);
    9 tgl@sss.pgh.pa.us         305                 :GNC          63 :     JsonbInState jsonb_state = {0};
                                306                 :                : 
                                307                 :             63 :     SV_to_JsonbValue(in, &jsonb_state, true);
                                308                 :             62 :     PG_RETURN_JSONB_P(JsonbValueToJsonb(jsonb_state.result));
                                309                 :                : }
        

Generated by: LCOV version 2.4-beta