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: d36b728949bf4e37ada1cd23e0f2aaa94f609a70 vs 52e118fe2f7e3381bdaa479816a7f72eda2ae517 Lines: 94.6 % 129 122 7 2 18 102 16
Current Date: 2026-06-29 16:15:13 +0200 Functions: 100.0 % 10 10 4 6 3
Baseline: lcov-20260630-baseline Branches: 70.8 % 72 51 21 4 47
Baseline Date: 2026-06-29 13:01:57 +0200 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 100.0 % 3 3 3
(30,360] days: 100.0 % 18 18 18
(360..) days: 93.5 % 108 101 7 2 99
Function coverage date bins:
(30,360] days: 100.0 % 3 3 3
(360..) days: 100.0 % 7 7 1 6
Branch coverage date bins:
(7,30] days: 50.0 % 2 1 1 1
(30,360] 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 "miscadmin.h"
                                  7                 :                : #include "plperl.h"
                                  8                 :                : #include "utils/fmgrprotos.h"
                                  9                 :                : #include "utils/jsonb.h"
                                 10                 :                : 
  461 tgl@sss.pgh.pa.us          11                 :CBC           2 : PG_MODULE_MAGIC_EXT(
                                 12                 :                :                     .name = "jsonb_plperl",
                                 13                 :                :                     .version = PG_VERSION
                                 14                 :                : );
                                 15                 :                : 
                                 16                 :                : static SV  *Jsonb_to_SV(JsonbContainer *jsonb);
                                 17                 :                : static void SV_to_JsonbValue(SV *in, JsonbInState *jsonb_state, bool is_elem);
                                 18                 :                : 
                                 19                 :                : 
                                 20                 :                : static SV  *
 3010 peter_e@gmx.net            21                 :             81 : JsonbValue_to_SV(JsonbValue *jbv)
                                 22                 :                : {
                                 23                 :             81 :     dTHX;
                                 24                 :                : 
                                 25   [ +  +  +  +  :             81 :     switch (jbv->type)
                                              +  - ]
                                 26                 :                :     {
                                 27                 :              6 :         case jbvBinary:
 2934 tgl@sss.pgh.pa.us          28                 :              6 :             return Jsonb_to_SV(jbv->val.binary.data);
                                 29                 :                : 
 3010 peter_e@gmx.net            30                 :             49 :         case jbvNumeric:
                                 31                 :                :             {
                                 32                 :             49 :                 char       *str = DatumGetCString(DirectFunctionCall1(numeric_out,
                                 33                 :                :                                                                       NumericGetDatum(jbv->val.numeric)));
                                 34                 :             49 :                 SV         *result = newSVnv(SvNV(cstr2sv(str)));
                                 35                 :                : 
                                 36                 :             49 :                 pfree(str);
                                 37                 :             49 :                 return result;
                                 38                 :                :             }
                                 39                 :                : 
                                 40                 :             14 :         case jbvString:
                                 41                 :                :             {
                                 42                 :             14 :                 char       *str = pnstrdup(jbv->val.string.val,
                                 43                 :             14 :                                            jbv->val.string.len);
                                 44                 :             14 :                 SV         *result = cstr2sv(str);
                                 45                 :                : 
                                 46                 :             14 :                 pfree(str);
                                 47                 :             14 :                 return result;
                                 48                 :                :             }
                                 49                 :                : 
                                 50                 :              4 :         case jbvBool:
                                 51         [ +  + ]:              4 :             return newSVnv(SvNV(jbv->val.boolean ? &PL_sv_yes : &PL_sv_no));
                                 52                 :                : 
                                 53                 :              8 :         case jbvNull:
                                 54                 :              8 :             return newSV(0);
                                 55                 :                : 
 3010 peter_e@gmx.net            56                 :UBC           0 :         default:
                                 57         [ #  # ]:              0 :             elog(ERROR, "unexpected jsonb value type: %d", jbv->type);
                                 58                 :                :             return NULL;
                                 59                 :                :     }
                                 60                 :                : }
                                 61                 :                : 
                                 62                 :                : static SV  *
 3010 peter_e@gmx.net            63                 :CBC          57 : Jsonb_to_SV(JsonbContainer *jsonb)
                                 64                 :                : {
                                 65                 :             57 :     dTHX;
                                 66                 :                :     JsonbValue  v;
                                 67                 :                :     JsonbIterator *it;
                                 68                 :                :     JsonbIteratorToken r;
                                 69                 :                : 
                                 70                 :                :     /* this can recurse via JsonbValue_to_SV() */
   13 tgl@sss.pgh.pa.us          71                 :             57 :     check_stack_depth();
                                 72                 :                : 
 3010 peter_e@gmx.net            73                 :             57 :     it = JsonbIteratorInit(jsonb);
                                 74                 :             57 :     r = JsonbIteratorNext(&it, &v, true);
                                 75                 :                : 
                                 76      [ +  +  - ]:             57 :     switch (r)
                                 77                 :                :     {
                                 78                 :             39 :         case WJB_BEGIN_ARRAY:
                                 79         [ +  + ]:             39 :             if (v.val.array.rawScalar)
                                 80                 :                :             {
                                 81                 :                :                 JsonbValue  tmp;
                                 82                 :                : 
                                 83   [ +  -  +  - ]:             38 :                 if ((r = JsonbIteratorNext(&it, &v, true)) != WJB_ELEM ||
                                 84         [ -  + ]:             38 :                     (r = JsonbIteratorNext(&it, &tmp, true)) != WJB_END_ARRAY ||
                                 85                 :             19 :                     (r = JsonbIteratorNext(&it, &tmp, true)) != WJB_DONE)
 3010 peter_e@gmx.net            86         [ #  # ]:UBC           0 :                     elog(ERROR, "unexpected jsonb token: %d", r);
                                 87                 :                : 
 2934 tgl@sss.pgh.pa.us          88                 :CBC          19 :                 return JsonbValue_to_SV(&v);
                                 89                 :                :             }
                                 90                 :                :             else
                                 91                 :                :             {
 3010 peter_e@gmx.net            92                 :             20 :                 AV         *av = newAV();
                                 93                 :                : 
                                 94         [ +  + ]:            104 :                 while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
                                 95                 :                :                 {
                                 96         [ +  + ]:             64 :                     if (r == WJB_ELEM)
                                 97                 :             44 :                         av_push(av, JsonbValue_to_SV(&v));
                                 98                 :                :                 }
                                 99                 :                : 
 2934 tgl@sss.pgh.pa.us         100                 :             20 :                 return newRV((SV *) av);
                                101                 :                :             }
                                102                 :                : 
 3010 peter_e@gmx.net           103                 :             18 :         case WJB_BEGIN_OBJECT:
                                104                 :                :             {
                                105                 :             18 :                 HV         *hv = newHV();
                                106                 :                : 
                                107         [ +  + ]:             72 :                 while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
                                108                 :                :                 {
                                109         [ +  + ]:             36 :                     if (r == WJB_KEY)
                                110                 :                :                     {
                                111                 :                :                         /* json key in v, json value in val */
                                112                 :                :                         JsonbValue  val;
                                113                 :                : 
                                114         [ +  - ]:             18 :                         if (JsonbIteratorNext(&it, &val, true) == WJB_VALUE)
                                115                 :                :                         {
                                116                 :             18 :                             SV         *value = JsonbValue_to_SV(&val);
                                117                 :                : 
                                118                 :             18 :                             (void) hv_store(hv,
                                119                 :                :                                             v.val.string.val, v.val.string.len,
                                120                 :                :                                             value, 0);
                                121                 :                :                         }
                                122                 :                :                     }
                                123                 :                :                 }
                                124                 :                : 
 2934 tgl@sss.pgh.pa.us         125                 :             18 :                 return newRV((SV *) hv);
                                126                 :                :             }
                                127                 :                : 
 3010 peter_e@gmx.net           128                 :UBC           0 :         default:
                                129         [ #  # ]:              0 :             elog(ERROR, "unexpected jsonb token: %d", r);
                                130                 :                :             return NULL;
                                131                 :                :     }
                                132                 :                : }
                                133                 :                : 
                                134                 :                : static void
  205 tgl@sss.pgh.pa.us         135                 :GNC          22 : AV_to_JsonbValue(AV *in, JsonbInState *jsonb_state)
                                136                 :                : {
 3010 peter_e@gmx.net           137                 :CBC          22 :     dTHX;
                                138                 :             22 :     SSize_t     pcount = av_len(in) + 1;
                                139                 :                :     SSize_t     i;
                                140                 :                : 
                                141                 :             22 :     pushJsonbValue(jsonb_state, WJB_BEGIN_ARRAY, NULL);
                                142                 :                : 
                                143         [ +  + ]:             70 :     for (i = 0; i < pcount; i++)
                                144                 :                :     {
                                145                 :             48 :         SV        **value = av_fetch(in, i, FALSE);
                                146                 :                : 
                                147         [ +  - ]:             48 :         if (value)
  205 tgl@sss.pgh.pa.us         148                 :GNC          48 :             SV_to_JsonbValue(*value, jsonb_state, true);
                                149                 :                :     }
                                150                 :                : 
                                151                 :             22 :     pushJsonbValue(jsonb_state, WJB_END_ARRAY, NULL);
 3010 peter_e@gmx.net           152                 :GIC          22 : }
                                153                 :                : 
                                154                 :                : static void
  205 tgl@sss.pgh.pa.us         155                 :GNC          28 : HV_to_JsonbValue(HV *obj, JsonbInState *jsonb_state)
                                156                 :                : {
 3010 peter_e@gmx.net           157                 :CBC          28 :     dTHX;
                                158                 :                :     JsonbValue  key;
                                159                 :                :     SV         *val;
                                160                 :                :     char       *kstr;
                                161                 :                :     I32         klen;
                                162                 :                : 
                                163                 :             28 :     key.type = jbvString;
                                164                 :                : 
                                165                 :             28 :     pushJsonbValue(jsonb_state, WJB_BEGIN_OBJECT, NULL);
                                166                 :                : 
                                167                 :             28 :     (void) hv_iterinit(obj);
                                168                 :                : 
      tgl@sss.pgh.pa.us         169         [ +  + ]:             64 :     while ((val = hv_iternextsv(obj, &kstr, &klen)))
                                170                 :                :     {
                                171                 :             36 :         key.val.string.val = pnstrdup(kstr, klen);
                                172                 :             36 :         key.val.string.len = klen;
      peter_e@gmx.net           173                 :             36 :         pushJsonbValue(jsonb_state, WJB_KEY, &key);
  205 tgl@sss.pgh.pa.us         174                 :GNC          36 :         SV_to_JsonbValue(val, jsonb_state, false);
                                175                 :                :     }
                                176                 :                : 
                                177                 :             28 :     pushJsonbValue(jsonb_state, WJB_END_OBJECT, NULL);
 3010 peter_e@gmx.net           178                 :GIC          28 : }
                                179                 :                : 
                                180                 :                : static void
  205 tgl@sss.pgh.pa.us         181                 :GNC         147 : SV_to_JsonbValue(SV *in, JsonbInState *jsonb_state, bool is_elem)
                                182                 :                : {
 3010 peter_e@gmx.net           183                 :CBC         147 :     dTHX;
                                184                 :                :     JsonbValue  out;            /* result */
                                185                 :                : 
                                186                 :                :     /* this can recurse via AV_to_JsonbValue() or HV_to_JsonbValue() */
   13 tgl@sss.pgh.pa.us         187                 :            147 :     check_stack_depth();
                                188                 :                : 
                                189                 :                :     /* Dereference references recursively. */
 3010 peter_e@gmx.net           190         [ +  + ]:            197 :     while (SvROK(in))
                                191                 :                :     {
                                192                 :                :         /*
                                193                 :                :          * It's possible for circular references to make this an infinite
                                194                 :                :          * loop.  Checking for such a situation seems like much more trouble
                                195                 :                :          * than it's worth, but let's provide a way to break out of the loop.
                                196                 :                :          */
   13 tgl@sss.pgh.pa.us         197         [ -  + ]:             50 :         CHECK_FOR_INTERRUPTS();
 3010 peter_e@gmx.net           198                 :             50 :         in = SvRV(in);
                                199                 :                :     }
                                200                 :                : 
                                201      [ +  +  + ]:            147 :     switch (SvTYPE(in))
                                202                 :                :     {
                                203                 :             22 :         case SVt_PVAV:
  205 tgl@sss.pgh.pa.us         204                 :GNC          22 :             AV_to_JsonbValue((AV *) in, jsonb_state);
                                205                 :             50 :             return;
                                206                 :                : 
 3010 peter_e@gmx.net           207                 :CBC          28 :         case SVt_PVHV:
  205 tgl@sss.pgh.pa.us         208                 :GNC          28 :             HV_to_JsonbValue((HV *) in, jsonb_state);
                                209                 :             28 :             return;
                                210                 :                : 
 3009 tgl@sss.pgh.pa.us         211                 :CBC          97 :         default:
 2522                           212         [ +  + ]:             97 :             if (!SvOK(in))
                                213                 :                :             {
                                214                 :             12 :                 out.type = jbvNull;
                                215                 :                :             }
                                216         [ +  + ]:             85 :             else if (SvUOK(in))
                                217                 :                :             {
                                218                 :                :                 /*
                                219                 :                :                  * If UV is >=64 bits, we have no better way to make this
                                220                 :                :                  * happen than converting to text and back.  Given the low
                                221                 :                :                  * usage of UV in Perl code, it's not clear it's worth working
                                222                 :                :                  * hard to provide alternate code paths.
                                223                 :                :                  */
 2934                           224                 :              2 :                 const char *strval = SvPV_nolen(in);
                                225                 :                : 
                                226                 :              2 :                 out.type = jbvNumeric;
                                227                 :              2 :                 out.val.numeric =
                                228                 :              2 :                     DatumGetNumeric(DirectFunctionCall3(numeric_in,
                                229                 :                :                                                         CStringGetDatum(strval),
                                230                 :                :                                                         ObjectIdGetDatum(InvalidOid),
                                231                 :                :                                                         Int32GetDatum(-1)));
                                232                 :                :             }
                                233         [ +  + ]:             83 :             else if (SvIOK(in))
                                234                 :                :             {
 3009                           235                 :             10 :                 IV          ival = SvIV(in);
                                236                 :                : 
                                237                 :             10 :                 out.type = jbvNumeric;
 2120 peter@eisentraut.org      238                 :             10 :                 out.val.numeric = int64_to_numeric(ival);
                                239                 :                :             }
 3009 tgl@sss.pgh.pa.us         240         [ +  + ]:             73 :             else if (SvNOK(in))
                                241                 :                :             {
                                242                 :             53 :                 double      nval = SvNV(in);
                                243                 :                : 
                                244                 :                :                 /*
                                245                 :                :                  * jsonb doesn't allow infinity or NaN (per JSON
                                246                 :                :                  * specification), but the numeric type that is used for the
                                247                 :                :                  * storage accepts those, so we have to reject them here
                                248                 :                :                  * explicitly.
                                249                 :                :                  */
                                250         [ +  + ]:             53 :                 if (isinf(nval))
 3010 peter_e@gmx.net           251         [ +  - ]:              1 :                     ereport(ERROR,
                                252                 :                :                             (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                                253                 :                :                              errmsg("cannot convert infinity to jsonb")));
 2983                           254         [ -  + ]:             52 :                 if (isnan(nval))
 2983 peter_e@gmx.net           255         [ #  # ]:UBC           0 :                     ereport(ERROR,
                                256                 :                :                             (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                                257                 :                :                              errmsg("cannot convert NaN to jsonb")));
                                258                 :                : 
 3010 peter_e@gmx.net           259                 :CBC          52 :                 out.type = jbvNumeric;
 3009 tgl@sss.pgh.pa.us         260                 :             52 :                 out.val.numeric =
                                261                 :             52 :                     DatumGetNumeric(DirectFunctionCall1(float8_numeric,
                                262                 :                :                                                         Float8GetDatum(nval)));
                                263                 :                :             }
                                264         [ +  - ]:             20 :             else if (SvPOK(in))
                                265                 :                :             {
                                266                 :             20 :                 out.type = jbvString;
                                267                 :             20 :                 out.val.string.val = sv2cstr(in);
                                268                 :             20 :                 out.val.string.len = strlen(out.val.string.val);
                                269                 :                :             }
                                270                 :                :             else
                                271                 :                :             {
                                272                 :                :                 /*
                                273                 :                :                  * XXX It might be nice if we could include the Perl type in
                                274                 :                :                  * the error message.
                                275                 :                :                  */
 3009 tgl@sss.pgh.pa.us         276         [ #  # ]:UBC           0 :                 ereport(ERROR,
                                277                 :                :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                278                 :                :                          errmsg("cannot transform this Perl type to jsonb")));
                                279                 :                :             }
                                280                 :                :     }
                                281                 :                : 
  205 tgl@sss.pgh.pa.us         282         [ +  + ]:GNC          96 :     if (jsonb_state->parseState)
                                283                 :                :     {
                                284                 :                :         /* We're in an array or object, so push value as element or field. */
                                285         [ +  + ]:             74 :         pushJsonbValue(jsonb_state, is_elem ? WJB_ELEM : WJB_VALUE, &out);
                                286                 :                :     }
                                287                 :                :     else
                                288                 :                :     {
                                289                 :                :         /*
                                290                 :                :          * We are at top level, so it's a raw scalar.  If we just shove the
                                291                 :                :          * scalar value into jsonb_state->result, JsonbValueToJsonb will take
                                292                 :                :          * care of wrapping it into a dummy array.
                                293                 :                :          */
                                294                 :             22 :         jsonb_state->result = palloc_object(JsonbValue);
                                295                 :             22 :         memcpy(jsonb_state->result, &out, sizeof(JsonbValue));
                                296                 :                :     }
                                297                 :                : }
                                298                 :                : 
                                299                 :                : 
 3010 peter_e@gmx.net           300                 :CBC           4 : PG_FUNCTION_INFO_V1(jsonb_to_plperl);
                                301                 :                : 
                                302                 :                : Datum
                                303                 :             51 : jsonb_to_plperl(PG_FUNCTION_ARGS)
                                304                 :                : {
                                305                 :             51 :     dTHX;
                                306                 :             51 :     Jsonb      *in = PG_GETARG_JSONB_P(0);
                                307                 :             51 :     SV         *sv = Jsonb_to_SV(&in->root);
                                308                 :                : 
 2934 tgl@sss.pgh.pa.us         309                 :             51 :     return PointerGetDatum(sv);
                                310                 :                : }
                                311                 :                : 
                                312                 :                : 
 3010 peter_e@gmx.net           313                 :              4 : PG_FUNCTION_INFO_V1(plperl_to_jsonb);
                                314                 :                : 
                                315                 :                : Datum
                                316                 :             63 : plperl_to_jsonb(PG_FUNCTION_ARGS)
                                317                 :                : {
                                318                 :             63 :     dTHX;
                                319                 :             63 :     SV         *in = (SV *) PG_GETARG_POINTER(0);
  205 tgl@sss.pgh.pa.us         320                 :GNC          63 :     JsonbInState jsonb_state = {0};
                                321                 :                : 
                                322                 :             63 :     SV_to_JsonbValue(in, &jsonb_state, true);
                                323                 :             62 :     PG_RETURN_JSONB_P(JsonbValueToJsonb(jsonb_state.result));
                                324                 :                : }
        

Generated by: LCOV version 2.0-1