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 HEAD vs 15 Lines: 95.7 % 92 88 4 88
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 6 6 6
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (240..) days: 95.7 % 92 88 4 88
Legend: Lines: hit not hit Function coverage date bins:
(240..) days: 100.0 % 6 6 6

 Age         Owner                  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-2023, 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
  849 tgl                        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)
  849 tgl                        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 */
  849 tgl                        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                 :     {
  849 tgl                       111 UBC           0 :         *op->resnull = true;
                                112               0 :         return;
                                113                 :     }
                                114                 : 
                                115                 :     /* OK, fetch/detoast the hstore and subscript */
  849 tgl                       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);
                                121              14 :     idx = hstoreFindKey(hs, NULL,
                                122              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])
  849 tgl                       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 */
  849 tgl                       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 v1.16-55-g56c0a2a