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

Generated by: LCOV version 2.1-beta2-3-g6141622