LCOV - differential code coverage report
Current view: top level - contrib/jsonb_plperl - jsonb_plperl.c (source / functions) Coverage Total Hit UNC UBC GNC CBC DCB
Current: ba12a202ce1b5581dc0ed149cf3f637d7897ad5d vs 2866d8c7dbfc9d882a7d80fef93fbbe763709932 Lines: 94.1 % 135 127 8 7 120 3
Current Date: 2026-08-27 14:31:44 +0300 Functions: 100.0 % 10 10 2 8
Baseline: lcov-20260827-baseline Branches: 68.8 % 80 55 2 23 4 51
Baseline Date: 2026-08-27 14:31:58 +0300 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 95.5 % 44 42 2 7 35
(30,360] days: 100.0 % 17 17 17
(360..) days: 91.9 % 74 68 6 68
Function coverage date bins:
(30,360] days: 100.0 % 3 3 2 1
(360..) days: 100.0 % 7 7 7
Branch coverage date bins:
(7,30] days: 74.3 % 35 26 2 7 4 22
(30,360] days: 83.3 % 6 5 1 5
(360..) days: 61.5 % 39 24 15 24

 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                 :                : 
  519 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  *
 3068 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:
 2992 tgl@sss.pgh.pa.us          28                 :              6 :             return Jsonb_to_SV(jbv->val.binary.data);
                                 29                 :                : 
 3068 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                 :                : 
 3068 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  *
 3068 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() */
   71 tgl@sss.pgh.pa.us          71                 :             57 :     check_stack_depth();
                                 72                 :                : 
 3068 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)
 3068 peter_e@gmx.net            86         [ #  # ]:UBC           0 :                     elog(ERROR, "unexpected jsonb token: %d", r);
                                 87                 :                : 
 2992 tgl@sss.pgh.pa.us          88                 :CBC          19 :                 return JsonbValue_to_SV(&v);
                                 89                 :                :             }
                                 90                 :                :             else
                                 91                 :                :             {
 3068 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                 :                : 
 2992 tgl@sss.pgh.pa.us         100                 :             20 :                 return newRV((SV *) av);
                                101                 :                :             }
                                102                 :                : 
 3068 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                 :                : 
 2992 tgl@sss.pgh.pa.us         125                 :             18 :                 return newRV((SV *) hv);
                                126                 :                :             }
                                127                 :                : 
 3068 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
  263 tgl@sss.pgh.pa.us         135                 :CBC          23 : AV_to_JsonbValue(AV *in, JsonbInState *jsonb_state)
                                136                 :                : {
 3068 peter_e@gmx.net           137                 :             23 :     dTHX;
   10 tgl@sss.pgh.pa.us         138                 :             23 :     Size_t      pcount = av_count(in);
                                139                 :                : 
 3068 peter_e@gmx.net           140                 :             23 :     pushJsonbValue(jsonb_state, WJB_BEGIN_ARRAY, NULL);
                                141                 :                : 
   10 tgl@sss.pgh.pa.us         142         [ +  + ]:             73 :     for (Size_t i = 0; i < pcount; i++)
                                143                 :                :     {
 3068 peter_e@gmx.net           144                 :             50 :         SV        **value = av_fetch(in, i, FALSE);
                                145                 :                : 
                                146         [ +  - ]:             50 :         if (value)
  263 tgl@sss.pgh.pa.us         147                 :             50 :             SV_to_JsonbValue(*value, jsonb_state, true);
                                148                 :                :     }
                                149                 :                : 
                                150                 :             23 :     pushJsonbValue(jsonb_state, WJB_END_ARRAY, NULL);
 3068 peter_e@gmx.net           151                 :             23 : }
                                152                 :                : 
                                153                 :                : static void
  263 tgl@sss.pgh.pa.us         154                 :             29 : HV_to_JsonbValue(HV *obj, JsonbInState *jsonb_state)
                                155                 :                : {
 3068 peter_e@gmx.net           156                 :             29 :     dTHX;
                                157                 :                :     JsonbValue  key;
                                158                 :                :     HE         *he;
                                159                 :                : 
                                160                 :             29 :     key.type = jbvString;
                                161                 :                : 
                                162                 :             29 :     pushJsonbValue(jsonb_state, WJB_BEGIN_OBJECT, NULL);
                                163                 :                : 
                                164                 :             29 :     (void) hv_iterinit(obj);
                                165                 :                : 
    9 tgl@sss.pgh.pa.us         166         [ +  + ]:GNC          68 :     while ((he = hv_iternext(obj)))
                                167                 :                :     {
                                168                 :             39 :         char       *k = hek2cstr(he);
    8                           169                 :             39 :         SV         *val = hv_iterval(obj, he);
                                170                 :                : 
    9                           171                 :             39 :         key.val.string.val = k;
                                172                 :             39 :         key.val.string.len = strlen(k);
 3068 peter_e@gmx.net           173                 :CBC          39 :         pushJsonbValue(jsonb_state, WJB_KEY, &key);
  263 tgl@sss.pgh.pa.us         174                 :             39 :         SV_to_JsonbValue(val, jsonb_state, false);
                                175                 :                :     }
                                176                 :                : 
                                177                 :             29 :     pushJsonbValue(jsonb_state, WJB_END_OBJECT, NULL);
 3068 peter_e@gmx.net           178                 :             29 : }
                                179                 :                : 
                                180                 :                : static void
  263 tgl@sss.pgh.pa.us         181                 :            154 : SV_to_JsonbValue(SV *in, JsonbInState *jsonb_state, bool is_elem)
                                182                 :                : {
 3068 peter_e@gmx.net           183                 :            154 :     dTHX;
                                184                 :                :     JsonbValue  out;            /* result */
                                185                 :                : 
                                186                 :                :     /* this can recurse via AV_to_JsonbValue() or HV_to_JsonbValue() */
   71 tgl@sss.pgh.pa.us         187                 :            154 :     check_stack_depth();
                                188                 :                : 
                                189                 :                :     /* Dereference references recursively. */
    8 tgl@sss.pgh.pa.us         190         [ +  - ]:GNC         154 :     plperl_materialize_sv(in);
    9 tgl@sss.pgh.pa.us         191   [ +  -  +  + ]:CBC         206 :     while (in && SvROK(in))
                                192                 :                :     {
                                193                 :                :         /*
                                194                 :                :          * It's possible for circular references to make this an infinite
                                195                 :                :          * loop.  Checking for such a situation seems like much more trouble
                                196                 :                :          * than it's worth, but let's provide a way to break out of the loop.
                                197                 :                :          */
   71                           198         [ -  + ]:             52 :         CHECK_FOR_INTERRUPTS();
 3068 peter_e@gmx.net           199                 :             52 :         in = SvRV(in);
    8 tgl@sss.pgh.pa.us         200         [ +  - ]:GNC          52 :         plperl_materialize_sv(in);
                                201                 :                :     }
                                202                 :                : 
    9 tgl@sss.pgh.pa.us         203         [ -  + ]:CBC         154 :     if (!in)
                                204                 :                :     {
    9 tgl@sss.pgh.pa.us         205                 :UBC           0 :         out.type = jbvNull;
                                206                 :                :     }
                                207                 :                :     else
                                208                 :                :     {
    9 tgl@sss.pgh.pa.us         209      [ +  +  + ]:CBC         154 :         switch (SvTYPE(in))
                                210                 :                :         {
                                211                 :             23 :             case SVt_PVAV:
                                212                 :             23 :                 AV_to_JsonbValue((AV *) in, jsonb_state);
                                213                 :             52 :                 return;
                                214                 :                : 
                                215                 :             29 :             case SVt_PVHV:
                                216                 :             29 :                 HV_to_JsonbValue((HV *) in, jsonb_state);
                                217                 :             29 :                 return;
                                218                 :                : 
                                219                 :            102 :             default:
                                220         [ +  + ]:            102 :                 if (!SvOK(in))
                                221                 :                :                 {
                                222                 :             13 :                     out.type = jbvNull;
                                223                 :                :                 }
                                224         [ +  + ]:             89 :                 else if (SvUOK(in))
                                225                 :                :                 {
                                226                 :                :                     /*
                                227                 :                :                      * If UV is >=64 bits, we have no better way to make this
                                228                 :                :                      * happen than converting to text and back.  Given the low
                                229                 :                :                      * usage of UV in Perl code, it's not clear it's worth
                                230                 :                :                      * working hard to provide alternate code paths.
                                231                 :                :                      */
                                232                 :              2 :                     const char *strval = SvPV_nolen(in);
                                233                 :                : 
                                234                 :              2 :                     out.type = jbvNumeric;
                                235                 :              2 :                     out.val.numeric =
                                236                 :              2 :                         DatumGetNumeric(DirectFunctionCall3(numeric_in,
                                237                 :                :                                                             CStringGetDatum(strval),
                                238                 :                :                                                             ObjectIdGetDatum(InvalidOid),
                                239                 :                :                                                             Int32GetDatum(-1)));
                                240                 :                :                 }
                                241         [ +  + ]:             87 :                 else if (SvIOK(in))
                                242                 :                :                 {
                                243                 :             12 :                     IV          ival = SvIV(in);
                                244                 :                : 
                                245                 :             12 :                     out.type = jbvNumeric;
                                246                 :             12 :                     out.val.numeric = int64_to_numeric(ival);
                                247                 :                :                 }
                                248         [ +  + ]:             75 :                 else if (SvNOK(in))
                                249                 :                :                 {
                                250                 :             53 :                     double      nval = SvNV(in);
                                251                 :                : 
                                252                 :                :                     /*
                                253                 :                :                      * jsonb doesn't allow infinity or NaN (per JSON
                                254                 :                :                      * specification), but the numeric type that is used for
                                255                 :                :                      * the storage accepts those, so we have to reject them
                                256                 :                :                      * here explicitly.
                                257                 :                :                      */
                                258         [ +  + ]:             53 :                     if (isinf(nval))
                                259         [ +  - ]:              1 :                         ereport(ERROR,
                                260                 :                :                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                                261                 :                :                                  errmsg("cannot convert infinity to jsonb")));
                                262         [ -  + ]:             52 :                     if (isnan(nval))
    9 tgl@sss.pgh.pa.us         263         [ #  # ]:UBC           0 :                         ereport(ERROR,
                                264                 :                :                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                                265                 :                :                                  errmsg("cannot convert NaN to jsonb")));
                                266                 :                : 
    9 tgl@sss.pgh.pa.us         267                 :CBC          52 :                     out.type = jbvNumeric;
                                268                 :             52 :                     out.val.numeric =
                                269                 :             52 :                         DatumGetNumeric(DirectFunctionCall1(float8_numeric,
                                270                 :                :                                                             Float8GetDatum(nval)));
                                271                 :                :                 }
                                272         [ +  - ]:             22 :                 else if (SvPOK(in))
                                273                 :                :                 {
                                274                 :             22 :                     out.type = jbvString;
                                275                 :             22 :                     out.val.string.val = sv2cstr(in);
                                276                 :             22 :                     out.val.string.len = strlen(out.val.string.val);
                                277                 :                :                 }
                                278                 :                :                 else
                                279                 :                :                 {
                                280                 :                :                     /*
                                281                 :                :                      * XXX It might be nice if we could include the Perl type
                                282                 :                :                      * in the error message.
                                283                 :                :                      */
 3041 peter_e@gmx.net           284         [ #  # ]:UBC           0 :                     ereport(ERROR,
                                285                 :                :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                286                 :                :                              errmsg("cannot transform this Perl type to jsonb")));
                                287                 :                :                 }
                                288                 :                :         }
                                289                 :                :     }
                                290                 :                : 
  263 tgl@sss.pgh.pa.us         291         [ +  + ]:CBC         101 :     if (jsonb_state->parseState)
                                292                 :                :     {
                                293                 :                :         /* We're in an array or object, so push value as element or field. */
                                294         [ +  + ]:             79 :         pushJsonbValue(jsonb_state, is_elem ? WJB_ELEM : WJB_VALUE, &out);
                                295                 :                :     }
                                296                 :                :     else
                                297                 :                :     {
                                298                 :                :         /*
                                299                 :                :          * We are at top level, so it's a raw scalar.  If we just shove the
                                300                 :                :          * scalar value into jsonb_state->result, JsonbValueToJsonb will take
                                301                 :                :          * care of wrapping it into a dummy array.
                                302                 :                :          */
                                303                 :             22 :         jsonb_state->result = palloc_object(JsonbValue);
                                304                 :             22 :         memcpy(jsonb_state->result, &out, sizeof(JsonbValue));
                                305                 :                :     }
                                306                 :                : }
                                307                 :                : 
                                308                 :                : 
 3068 peter_e@gmx.net           309                 :              4 : PG_FUNCTION_INFO_V1(jsonb_to_plperl);
                                310                 :                : 
                                311                 :                : Datum
                                312                 :             51 : jsonb_to_plperl(PG_FUNCTION_ARGS)
                                313                 :                : {
                                314                 :             51 :     dTHX;
                                315                 :             51 :     Jsonb      *in = PG_GETARG_JSONB_P(0);
                                316                 :             51 :     SV         *sv = Jsonb_to_SV(&in->root);
                                317                 :                : 
 2992 tgl@sss.pgh.pa.us         318                 :             51 :     return PointerGetDatum(sv);
                                319                 :                : }
                                320                 :                : 
                                321                 :                : 
 3068 peter_e@gmx.net           322                 :              4 : PG_FUNCTION_INFO_V1(plperl_to_jsonb);
                                323                 :                : 
                                324                 :                : Datum
                                325                 :             65 : plperl_to_jsonb(PG_FUNCTION_ARGS)
                                326                 :                : {
                                327                 :             65 :     dTHX;
                                328                 :             65 :     SV         *in = (SV *) PG_GETARG_POINTER(0);
  263 tgl@sss.pgh.pa.us         329                 :             65 :     JsonbInState jsonb_state = {0};
                                330                 :                : 
                                331                 :             65 :     SV_to_JsonbValue(in, &jsonb_state, true);
                                332                 :             64 :     PG_RETURN_JSONB_P(JsonbValueToJsonb(jsonb_state.result));
                                333                 :                : }
        

Generated by: LCOV version 2.0-1