LCOV - differential code coverage report
Current view: top level - contrib/hstore - hstore_subs.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 94.6 % 92 87 5 87
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 6 6 6
Baseline: 16@8cea358b128 Branches: 56.1 % 114 64 50 64
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.6 % 92 87 5 87
Function coverage date bins:
(240..) days: 100.0 % 6 6 6
Branch coverage date bins:
(240..) days: 56.1 % 114 64 50 64

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * hstore_subs.c
                                  4                 :                :  *    Subscripting support functions for hstore.
                                  5                 :                :  *
                                  6                 :                :  * This is a great deal simpler than array_subs.c, because the result of
                                  7                 :                :  * subscripting an hstore is just a text string (the value for the key).
                                  8                 :                :  * We do not need to support array slicing notation, nor multiple subscripts.
                                  9                 :                :  * Less obviously, because the subscript result is never a SQL container
                                 10                 :                :  * type, there will never be any nested-assignment scenarios, so we do not
                                 11                 :                :  * need a fetch_old function.  In turn, that means we can drop the
                                 12                 :                :  * check_subscripts function and just let the fetch and assign functions
                                 13                 :                :  * do everything.
                                 14                 :                :  *
                                 15                 :                :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
                                 16                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                 17                 :                :  *
                                 18                 :                :  *
                                 19                 :                :  * IDENTIFICATION
                                 20                 :                :  *    contrib/hstore/hstore_subs.c
                                 21                 :                :  *
                                 22                 :                :  *-------------------------------------------------------------------------
                                 23                 :                :  */
                                 24                 :                : #include "postgres.h"
                                 25                 :                : 
                                 26                 :                : #include "executor/execExpr.h"
                                 27                 :                : #include "hstore.h"
                                 28                 :                : #include "nodes/nodeFuncs.h"
                                 29                 :                : #include "nodes/subscripting.h"
                                 30                 :                : #include "parser/parse_coerce.h"
                                 31                 :                : #include "parser/parse_expr.h"
                                 32                 :                : #include "utils/builtins.h"
                                 33                 :                : 
                                 34                 :                : 
                                 35                 :                : /*
                                 36                 :                :  * Finish parse analysis of a SubscriptingRef expression for hstore.
                                 37                 :                :  *
                                 38                 :                :  * Verify there's just one subscript, coerce it to text,
                                 39                 :                :  * and set the result type of the SubscriptingRef node.
                                 40                 :                :  */
                                 41                 :                : static void
 1220 tgl@sss.pgh.pa.us          42                 :CBC           9 : hstore_subscript_transform(SubscriptingRef *sbsref,
                                 43                 :                :                            List *indirection,
                                 44                 :                :                            ParseState *pstate,
                                 45                 :                :                            bool isSlice,
                                 46                 :                :                            bool isAssignment)
                                 47                 :                : {
                                 48                 :                :     A_Indices  *ai;
                                 49                 :                :     Node       *subexpr;
                                 50                 :                : 
                                 51                 :                :     /* We support only single-subscript, non-slice cases */
                                 52   [ +  +  +  + ]:              9 :     if (isSlice || list_length(indirection) != 1)
                                 53         [ +  - ]:              2 :         ereport(ERROR,
                                 54                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                 55                 :                :                  errmsg("hstore allows only one subscript"),
                                 56                 :                :                  parser_errposition(pstate,
                                 57                 :                :                                     exprLocation((Node *) indirection))));
                                 58                 :                : 
                                 59                 :                :     /* Transform the subscript expression to type text */
                                 60                 :              7 :     ai = linitial_node(A_Indices, indirection);
                                 61   [ +  -  +  -  :              7 :     Assert(ai->uidx != NULL && ai->lidx == NULL && !ai->is_slice);
                                              -  + ]
                                 62                 :                : 
                                 63                 :              7 :     subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind);
                                 64                 :                :     /* If it's not text already, try to coerce */
                                 65                 :              7 :     subexpr = coerce_to_target_type(pstate,
                                 66                 :                :                                     subexpr, exprType(subexpr),
                                 67                 :                :                                     TEXTOID, -1,
                                 68                 :                :                                     COERCION_ASSIGNMENT,
                                 69                 :                :                                     COERCE_IMPLICIT_CAST,
                                 70                 :                :                                     -1);
                                 71         [ -  + ]:              7 :     if (subexpr == NULL)
 1220 tgl@sss.pgh.pa.us          72         [ #  # ]:UBC           0 :         ereport(ERROR,
                                 73                 :                :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
                                 74                 :                :                  errmsg("hstore subscript must have type text"),
                                 75                 :                :                  parser_errposition(pstate, exprLocation(ai->uidx))));
                                 76                 :                : 
                                 77                 :                :     /* ... and store the transformed subscript into the SubscriptRef node */
 1220 tgl@sss.pgh.pa.us          78                 :CBC           7 :     sbsref->refupperindexpr = list_make1(subexpr);
                                 79                 :              7 :     sbsref->reflowerindexpr = NIL;
                                 80                 :                : 
                                 81                 :                :     /* Determine the result type of the subscripting operation; always text */
                                 82                 :              7 :     sbsref->refrestype = TEXTOID;
                                 83                 :              7 :     sbsref->reftypmod = -1;
                                 84                 :              7 : }
                                 85                 :                : 
                                 86                 :                : /*
                                 87                 :                :  * Evaluate SubscriptingRef fetch for hstore.
                                 88                 :                :  *
                                 89                 :                :  * Source container is in step's result variable (it's known not NULL, since
                                 90                 :                :  * we set fetch_strict to true), and the subscript expression is in the
                                 91                 :                :  * upperindex[] array.
                                 92                 :                :  */
                                 93                 :                : static void
                                 94                 :              7 : hstore_subscript_fetch(ExprState *state,
                                 95                 :                :                        ExprEvalStep *op,
                                 96                 :                :                        ExprContext *econtext)
                                 97                 :                : {
                                 98                 :              7 :     SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
                                 99                 :                :     HStore     *hs;
                                100                 :                :     text       *key;
                                101                 :                :     HEntry     *entries;
                                102                 :                :     int         idx;
                                103                 :                :     text       *out;
                                104                 :                : 
                                105                 :                :     /* Should not get here if source hstore is null */
                                106         [ -  + ]:              7 :     Assert(!(*op->resnull));
                                107                 :                : 
                                108                 :                :     /* Check for null subscript */
                                109         [ -  + ]:              7 :     if (sbsrefstate->upperindexnull[0])
                                110                 :                :     {
 1220 tgl@sss.pgh.pa.us         111                 :UBC           0 :         *op->resnull = true;
                                112                 :              0 :         return;
                                113                 :                :     }
                                114                 :                : 
                                115                 :                :     /* OK, fetch/detoast the hstore and subscript */
 1220 tgl@sss.pgh.pa.us         116                 :CBC           7 :     hs = DatumGetHStoreP(*op->resvalue);
                                117                 :              7 :     key = DatumGetTextPP(sbsrefstate->upperindex[0]);
                                118                 :                : 
                                119                 :                :     /* The rest is basically the same as hstore_fetchval() */
                                120                 :              7 :     entries = ARRPTR(hs);
 1220 tgl@sss.pgh.pa.us         121                 :UBC           0 :     idx = hstoreFindKey(hs, NULL,
 1220 tgl@sss.pgh.pa.us         122   [ -  +  -  -  :CBC          14 :                         VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
                                     -  -  -  -  -  
                                           +  -  + ]
                                123                 :                : 
                                124   [ +  +  -  + ]:              7 :     if (idx < 0 || HSTORE_VALISNULL(entries, idx))
                                125                 :                :     {
                                126                 :              2 :         *op->resnull = true;
                                127                 :              2 :         return;
                                128                 :                :     }
                                129                 :                : 
                                130         [ +  - ]:              5 :     out = cstring_to_text_with_len(HSTORE_VAL(entries, STRPTR(hs), idx),
                                131         [ -  + ]:              5 :                                    HSTORE_VALLEN(entries, idx));
                                132                 :                : 
                                133                 :              5 :     *op->resvalue = PointerGetDatum(out);
                                134                 :                : }
                                135                 :                : 
                                136                 :                : /*
                                137                 :                :  * Evaluate SubscriptingRef assignment for hstore.
                                138                 :                :  *
                                139                 :                :  * Input container (possibly null) is in result area, replacement value is in
                                140                 :                :  * SubscriptingRefState's replacevalue/replacenull.
                                141                 :                :  */
                                142                 :                : static void
                                143                 :              7 : hstore_subscript_assign(ExprState *state,
                                144                 :                :                         ExprEvalStep *op,
                                145                 :                :                         ExprContext *econtext)
                                146                 :                : {
                                147                 :              7 :     SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
                                148                 :                :     text       *key;
                                149                 :                :     Pairs       p;
                                150                 :                :     HStore     *out;
                                151                 :                : 
                                152                 :                :     /* Check for null subscript */
                                153         [ -  + ]:              7 :     if (sbsrefstate->upperindexnull[0])
 1220 tgl@sss.pgh.pa.us         154         [ #  # ]:UBC           0 :         ereport(ERROR,
                                155                 :                :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
                                156                 :                :                  errmsg("hstore subscript in assignment must not be null")));
                                157                 :                : 
                                158                 :                :     /* OK, fetch/detoast the subscript */
 1220 tgl@sss.pgh.pa.us         159                 :CBC           7 :     key = DatumGetTextPP(sbsrefstate->upperindex[0]);
                                160                 :                : 
                                161                 :                :     /* Create a Pairs entry for subscript + replacement value */
                                162                 :              7 :     p.needfree = false;
                                163         [ -  + ]:              7 :     p.key = VARDATA_ANY(key);
                                164   [ -  +  -  -  :              7 :     p.keylen = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(key));
                                     -  -  -  -  -  
                                                 + ]
                                165                 :                : 
                                166         [ +  + ]:              7 :     if (sbsrefstate->replacenull)
                                167                 :                :     {
                                168                 :              1 :         p.vallen = 0;
                                169                 :              1 :         p.isnull = true;
                                170                 :                :     }
                                171                 :                :     else
                                172                 :                :     {
                                173                 :              6 :         text       *val = DatumGetTextPP(sbsrefstate->replacevalue);
                                174                 :                : 
                                175         [ -  + ]:              6 :         p.val = VARDATA_ANY(val);
                                176   [ -  +  -  -  :              6 :         p.vallen = hstoreCheckValLen(VARSIZE_ANY_EXHDR(val));
                                     -  -  -  -  -  
                                                 + ]
                                177                 :              6 :         p.isnull = false;
                                178                 :                :     }
                                179                 :                : 
                                180         [ +  + ]:              7 :     if (*op->resnull)
                                181                 :                :     {
                                182                 :                :         /* Just build a one-element hstore (cf. hstore_from_text) */
                                183                 :              2 :         out = hstorePairs(&p, 1, p.keylen + p.vallen);
                                184                 :                :     }
                                185                 :                :     else
                                186                 :                :     {
                                187                 :                :         /*
                                188                 :                :          * Otherwise, merge the new key into the hstore.  Based on
                                189                 :                :          * hstore_concat.
                                190                 :                :          */
                                191                 :              5 :         HStore     *hs = DatumGetHStoreP(*op->resvalue);
                                192                 :              5 :         int         s1count = HS_COUNT(hs);
                                193                 :              5 :         int         outcount = 0;
                                194                 :                :         int         vsize;
                                195                 :                :         char       *ps1,
                                196                 :                :                    *bufd,
                                197                 :                :                    *pd;
                                198                 :                :         HEntry     *es1,
                                199                 :                :                    *ed;
                                200                 :                :         int         s1idx;
                                201                 :                :         int         s2idx;
                                202                 :                : 
                                203                 :                :         /* Allocate result without considering possibility of duplicate */
                                204                 :              5 :         vsize = CALCDATASIZE(s1count + 1, VARSIZE(hs) + p.keylen + p.vallen);
                                205                 :              5 :         out = palloc(vsize);
                                206                 :              5 :         SET_VARSIZE(out, vsize);
                                207                 :              5 :         HS_SETCOUNT(out, s1count + 1);
                                208                 :                : 
                                209                 :              5 :         ps1 = STRPTR(hs);
                                210                 :              5 :         bufd = pd = STRPTR(out);
                                211                 :              5 :         es1 = ARRPTR(hs);
                                212                 :              5 :         ed = ARRPTR(out);
                                213                 :                : 
                                214   [ +  +  +  + ]:             37 :         for (s1idx = s2idx = 0; s1idx < s1count || s2idx < 1; ++outcount)
                                215                 :                :         {
                                216                 :                :             int         difference;
                                217                 :                : 
                                218         [ +  + ]:             32 :             if (s1idx >= s1count)
                                219                 :              1 :                 difference = 1;
                                220         [ +  + ]:             31 :             else if (s2idx >= 1)
                                221                 :             10 :                 difference = -1;
                                222                 :                :             else
                                223                 :                :             {
                                224         [ +  + ]:             21 :                 int         s1keylen = HSTORE_KEYLEN(es1, s1idx);
                                225                 :             21 :                 int         s2keylen = p.keylen;
                                226                 :                : 
                                227         [ +  + ]:             21 :                 if (s1keylen == s2keylen)
                                228                 :             19 :                     difference = memcmp(HSTORE_KEY(es1, ps1, s1idx),
                                229         [ +  + ]:             19 :                                         p.key,
                                230                 :                :                                         s1keylen);
                                231                 :                :                 else
                                232         [ +  - ]:              2 :                     difference = (s1keylen > s2keylen) ? 1 : -1;
                                233                 :                :             }
                                234                 :                : 
                                235         [ +  + ]:             32 :             if (difference >= 0)
                                236                 :                :             {
                                237         [ -  + ]:              5 :                 HS_ADDITEM(ed, bufd, pd, p);
                                238                 :              5 :                 ++s2idx;
                                239         [ +  + ]:              5 :                 if (difference == 0)
                                240                 :              2 :                     ++s1idx;
                                241                 :                :             }
                                242                 :                :             else
                                243                 :                :             {
                                244   [ +  +  -  +  :             27 :                 HS_COPYITEM(ed, bufd, pd,
                                     +  +  +  +  -  
                                           +  -  + ]
                                245                 :                :                             HSTORE_KEY(es1, ps1, s1idx),
                                246                 :                :                             HSTORE_KEYLEN(es1, s1idx),
                                247                 :                :                             HSTORE_VALLEN(es1, s1idx),
                                248                 :                :                             HSTORE_VALISNULL(es1, s1idx));
                                249                 :             27 :                 ++s1idx;
                                250                 :                :             }
                                251                 :                :         }
                                252                 :                : 
                                253   [ +  -  +  + ]:              5 :         HS_FINALIZE(out, outcount, bufd, pd);
                                254                 :                :     }
                                255                 :                : 
                                256                 :              7 :     *op->resvalue = PointerGetDatum(out);
                                257                 :              7 :     *op->resnull = false;
                                258                 :              7 : }
                                259                 :                : 
                                260                 :                : /*
                                261                 :                :  * Set up execution state for an hstore subscript operation.
                                262                 :                :  */
                                263                 :                : static void
                                264                 :              7 : hstore_exec_setup(const SubscriptingRef *sbsref,
                                265                 :                :                   SubscriptingRefState *sbsrefstate,
                                266                 :                :                   SubscriptExecSteps *methods)
                                267                 :                : {
                                268                 :                :     /* Assert we are dealing with one subscript */
                                269         [ -  + ]:              7 :     Assert(sbsrefstate->numlower == 0);
                                270         [ -  + ]:              7 :     Assert(sbsrefstate->numupper == 1);
                                271                 :                :     /* We can't check upperprovided[0] here, but it must be true */
                                272                 :                : 
                                273                 :                :     /* Pass back pointers to appropriate step execution functions */
                                274                 :              7 :     methods->sbs_check_subscripts = NULL;
                                275                 :              7 :     methods->sbs_fetch = hstore_subscript_fetch;
                                276                 :              7 :     methods->sbs_assign = hstore_subscript_assign;
                                277                 :              7 :     methods->sbs_fetch_old = NULL;
                                278                 :              7 : }
                                279                 :                : 
                                280                 :                : /*
                                281                 :                :  * hstore_subscript_handler
                                282                 :                :  *      Subscripting handler for hstore.
                                283                 :                :  */
                                284                 :              8 : PG_FUNCTION_INFO_V1(hstore_subscript_handler);
                                285                 :                : Datum
                                286                 :             16 : hstore_subscript_handler(PG_FUNCTION_ARGS)
                                287                 :                : {
                                288                 :                :     static const SubscriptRoutines sbsroutines = {
                                289                 :                :         .transform = hstore_subscript_transform,
                                290                 :                :         .exec_setup = hstore_exec_setup,
                                291                 :                :         .fetch_strict = true,   /* fetch returns NULL for NULL inputs */
                                292                 :                :         .fetch_leakproof = true,    /* fetch returns NULL for bad subscript */
                                293                 :                :         .store_leakproof = false    /* ... but assignment throws error */
                                294                 :                :     };
                                295                 :                : 
                                296                 :             16 :     PG_RETURN_POINTER(&sbsroutines);
                                297                 :                : }
        

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