LCOV - differential code coverage report
Current view: top level - contrib/jsonb_plperl - jsonb_plperl.c (source / functions) Coverage Total Hit UBC CBC
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 94.3 % 122 115 7 115
Current Date: 2025-09-06 07:49:51 +0900 Functions: 100.0 % 10 10 10
Baseline: lcov-20250906-005545-baseline Branches: 71.4 % 70 50 20 50
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 100.0 % 1 1 1
(360..) days: 94.2 % 121 114 7 114
Function coverage date bins:
(30,360] days: 100.0 % 1 1 1
(360..) days: 100.0 % 9 9 9
Branch coverage date bins:
(360..) days: 71.4 % 70 50 20 50

 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                 :                : 
  164 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 JsonbValue *SV_to_JsonbValue(SV *obj, JsonbParseState **ps, bool is_elem);
                                 17                 :                : 
                                 18                 :                : 
                                 19                 :                : static SV  *
 2713 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:
 2637 tgl@sss.pgh.pa.us          27                 :              6 :             return Jsonb_to_SV(jbv->val.binary.data);
                                 28                 :                : 
 2713 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                 :                : 
 2713 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  *
 2713 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)
 2713 peter_e@gmx.net            82         [ #  # ]:UBC           0 :                     elog(ERROR, "unexpected jsonb token: %d", r);
                                 83                 :                : 
 2637 tgl@sss.pgh.pa.us          84                 :CBC          19 :                 return JsonbValue_to_SV(&v);
                                 85                 :                :             }
                                 86                 :                :             else
                                 87                 :                :             {
 2713 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                 :                : 
 2637 tgl@sss.pgh.pa.us          96                 :             20 :                 return newRV((SV *) av);
                                 97                 :                :             }
                                 98                 :                : 
 2713 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                 :                : 
 2637 tgl@sss.pgh.pa.us         121                 :             18 :                 return newRV((SV *) hv);
                                122                 :                :             }
                                123                 :                : 
 2713 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 JsonbValue *
 2713 peter_e@gmx.net           131                 :CBC          22 : AV_to_JsonbValue(AV *in, JsonbParseState **jsonb_state)
                                132                 :                : {
                                133                 :             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)
                                144                 :             48 :             (void) SV_to_JsonbValue(*value, jsonb_state, true);
                                145                 :                :     }
                                146                 :                : 
                                147                 :             22 :     return pushJsonbValue(jsonb_state, WJB_END_ARRAY, NULL);
                                148                 :                : }
                                149                 :                : 
                                150                 :                : static JsonbValue *
                                151                 :             28 : HV_to_JsonbValue(HV *obj, JsonbParseState **jsonb_state)
                                152                 :                : {
                                153                 :             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);
                                170                 :             36 :         (void) SV_to_JsonbValue(val, jsonb_state, false);
                                171                 :                :     }
                                172                 :                : 
                                173                 :             28 :     return pushJsonbValue(jsonb_state, WJB_END_OBJECT, NULL);
                                174                 :                : }
                                175                 :                : 
                                176                 :                : static JsonbValue *
                                177                 :            147 : SV_to_JsonbValue(SV *in, JsonbParseState **jsonb_state, bool is_elem)
                                178                 :                : {
                                179                 :            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:
                                189                 :             22 :             return AV_to_JsonbValue((AV *) in, jsonb_state);
                                190                 :                : 
                                191                 :             28 :         case SVt_PVHV:
                                192                 :             28 :             return HV_to_JsonbValue((HV *) in, jsonb_state);
                                193                 :                : 
 2712 tgl@sss.pgh.pa.us         194                 :             97 :         default:
 2225                           195         [ +  + ]:             97 :             if (!SvOK(in))
                                196                 :                :             {
                                197                 :             12 :                 out.type = jbvNull;
                                198                 :                :             }
                                199         [ +  + ]:             85 :             else if (SvUOK(in))
                                200                 :                :             {
                                201                 :                :                 /*
                                202                 :                :                  * If UV is >=64 bits, we have no better way to make this
                                203                 :                :                  * happen than converting to text and back.  Given the low
                                204                 :                :                  * usage of UV in Perl code, it's not clear it's worth working
                                205                 :                :                  * hard to provide alternate code paths.
                                206                 :                :                  */
 2637                           207                 :              2 :                 const char *strval = SvPV_nolen(in);
                                208                 :                : 
                                209                 :              2 :                 out.type = jbvNumeric;
                                210                 :              2 :                 out.val.numeric =
                                211                 :              2 :                     DatumGetNumeric(DirectFunctionCall3(numeric_in,
                                212                 :                :                                                         CStringGetDatum(strval),
                                213                 :                :                                                         ObjectIdGetDatum(InvalidOid),
                                214                 :                :                                                         Int32GetDatum(-1)));
                                215                 :                :             }
                                216         [ +  + ]:             83 :             else if (SvIOK(in))
                                217                 :                :             {
 2712                           218                 :             10 :                 IV          ival = SvIV(in);
                                219                 :                : 
                                220                 :             10 :                 out.type = jbvNumeric;
 1823 peter@eisentraut.org      221                 :             10 :                 out.val.numeric = int64_to_numeric(ival);
                                222                 :                :             }
 2712 tgl@sss.pgh.pa.us         223         [ +  + ]:             73 :             else if (SvNOK(in))
                                224                 :                :             {
                                225                 :             53 :                 double      nval = SvNV(in);
                                226                 :                : 
                                227                 :                :                 /*
                                228                 :                :                  * jsonb doesn't allow infinity or NaN (per JSON
                                229                 :                :                  * specification), but the numeric type that is used for the
                                230                 :                :                  * storage accepts those, so we have to reject them here
                                231                 :                :                  * explicitly.
                                232                 :                :                  */
                                233         [ +  + ]:             53 :                 if (isinf(nval))
 2713 peter_e@gmx.net           234         [ +  - ]:              1 :                     ereport(ERROR,
                                235                 :                :                             (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                                236                 :                :                              errmsg("cannot convert infinity to jsonb")));
 2686                           237         [ -  + ]:             52 :                 if (isnan(nval))
 2686 peter_e@gmx.net           238         [ #  # ]:UBC           0 :                     ereport(ERROR,
                                239                 :                :                             (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                                240                 :                :                              errmsg("cannot convert NaN to jsonb")));
                                241                 :                : 
 2713 peter_e@gmx.net           242                 :CBC          52 :                 out.type = jbvNumeric;
 2712 tgl@sss.pgh.pa.us         243                 :             52 :                 out.val.numeric =
                                244                 :             52 :                     DatumGetNumeric(DirectFunctionCall1(float8_numeric,
                                245                 :                :                                                         Float8GetDatum(nval)));
                                246                 :                :             }
                                247         [ +  - ]:             20 :             else if (SvPOK(in))
                                248                 :                :             {
                                249                 :             20 :                 out.type = jbvString;
                                250                 :             20 :                 out.val.string.val = sv2cstr(in);
                                251                 :             20 :                 out.val.string.len = strlen(out.val.string.val);
                                252                 :                :             }
                                253                 :                :             else
                                254                 :                :             {
                                255                 :                :                 /*
                                256                 :                :                  * XXX It might be nice if we could include the Perl type in
                                257                 :                :                  * the error message.
                                258                 :                :                  */
 2712 tgl@sss.pgh.pa.us         259         [ #  # ]:UBC           0 :                 ereport(ERROR,
                                260                 :                :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                261                 :                :                          errmsg("cannot transform this Perl type to jsonb")));
                                262                 :                :                 return NULL;
                                263                 :                :             }
                                264                 :                :     }
                                265                 :                : 
                                266                 :                :     /* Push result into 'jsonb_state' unless it is a raw scalar. */
 2713 peter_e@gmx.net           267                 :CBC          96 :     return *jsonb_state
                                268         [ +  + ]:             74 :         ? pushJsonbValue(jsonb_state, is_elem ? WJB_ELEM : WJB_VALUE, &out)
                                269         [ +  + ]:            170 :         : memcpy(palloc(sizeof(JsonbValue)), &out, sizeof(JsonbValue));
                                270                 :                : }
                                271                 :                : 
                                272                 :                : 
                                273                 :              4 : PG_FUNCTION_INFO_V1(jsonb_to_plperl);
                                274                 :                : 
                                275                 :                : Datum
                                276                 :             51 : jsonb_to_plperl(PG_FUNCTION_ARGS)
                                277                 :                : {
                                278                 :             51 :     dTHX;
                                279                 :             51 :     Jsonb      *in = PG_GETARG_JSONB_P(0);
                                280                 :             51 :     SV         *sv = Jsonb_to_SV(&in->root);
                                281                 :                : 
 2637 tgl@sss.pgh.pa.us         282                 :             51 :     return PointerGetDatum(sv);
                                283                 :                : }
                                284                 :                : 
                                285                 :                : 
 2713 peter_e@gmx.net           286                 :              4 : PG_FUNCTION_INFO_V1(plperl_to_jsonb);
                                287                 :                : 
                                288                 :                : Datum
                                289                 :             63 : plperl_to_jsonb(PG_FUNCTION_ARGS)
                                290                 :                : {
                                291                 :             63 :     dTHX;
                                292                 :             63 :     JsonbParseState *jsonb_state = NULL;
                                293                 :             63 :     SV         *in = (SV *) PG_GETARG_POINTER(0);
                                294                 :             63 :     JsonbValue *out = SV_to_JsonbValue(in, &jsonb_state, true);
                                295                 :             62 :     Jsonb      *result = JsonbValueToJsonb(out);
                                296                 :                : 
                                297                 :             62 :     PG_RETURN_JSONB_P(result);
                                298                 :                : }
        

Generated by: LCOV version 2.4-beta