LCOV - code coverage report
Current view: top level - contrib/hstore - hstore_op.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 91.4 % 570 521
Test Date: 2026-07-03 19:57:34 Functions: 66.3 % 86 57
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 79.2 % 394 312

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * contrib/hstore/hstore_op.c
       3                 :             :  */
       4                 :             : #include "postgres.h"
       5                 :             : 
       6                 :             : #include "access/htup_details.h"
       7                 :             : #include "catalog/pg_type.h"
       8                 :             : #include "common/hashfn.h"
       9                 :             : #include "funcapi.h"
      10                 :             : #include "hstore.h"
      11                 :             : #include "utils/builtins.h"
      12                 :             : #include "utils/memutils.h"
      13                 :             : 
      14                 :             : /* old names for C functions */
      15                 :           0 : HSTORE_POLLUTE(hstore_fetchval, fetchval);
      16                 :           0 : HSTORE_POLLUTE(hstore_exists, exists);
      17                 :           0 : HSTORE_POLLUTE(hstore_defined, defined);
      18                 :           0 : HSTORE_POLLUTE(hstore_delete, delete);
      19                 :           0 : HSTORE_POLLUTE(hstore_concat, hs_concat);
      20                 :           0 : HSTORE_POLLUTE(hstore_contains, hs_contains);
      21                 :           0 : HSTORE_POLLUTE(hstore_contained, hs_contained);
      22                 :           0 : HSTORE_POLLUTE(hstore_akeys, akeys);
      23                 :           0 : HSTORE_POLLUTE(hstore_avals, avals);
      24                 :           0 : HSTORE_POLLUTE(hstore_skeys, skeys);
      25                 :           0 : HSTORE_POLLUTE(hstore_svals, svals);
      26                 :           0 : HSTORE_POLLUTE(hstore_each, each);
      27                 :             : 
      28                 :             : 
      29                 :             : /*
      30                 :             :  * We're often finding a sequence of keys in ascending order. The
      31                 :             :  * "lowbound" parameter is used to cache lower bounds of searches
      32                 :             :  * between calls, based on this assumption. Pass NULL for it for
      33                 :             :  * one-off or unordered searches.
      34                 :             :  */
      35                 :             : int
      36                 :        9456 : hstoreFindKey(HStore *hs, int *lowbound, char *key, int keylen)
      37                 :             : {
      38                 :        9456 :     HEntry     *entries = ARRPTR(hs);
      39         [ +  + ]:        9456 :     int         stopLow = lowbound ? *lowbound : 0;
      40                 :        9456 :     int         stopHigh = HS_COUNT(hs);
      41                 :             :     int         stopMiddle;
      42                 :        9456 :     char       *base = STRPTR(hs);
      43                 :             : 
      44         [ +  + ]:       24849 :     while (stopLow < stopHigh)
      45                 :             :     {
      46                 :             :         int         difference;
      47                 :             : 
      48                 :       18556 :         stopMiddle = stopLow + (stopHigh - stopLow) / 2;
      49                 :             : 
      50   [ +  +  +  + ]:       18556 :         if (HSTORE_KEYLEN(entries, stopMiddle) == keylen)
      51         [ +  + ]:        7413 :             difference = memcmp(HSTORE_KEY(entries, base, stopMiddle), key, keylen);
      52                 :             :         else
      53   [ +  +  +  + ]:       11143 :             difference = (HSTORE_KEYLEN(entries, stopMiddle) > keylen) ? 1 : -1;
      54                 :             : 
      55         [ +  + ]:       18556 :         if (difference == 0)
      56                 :             :         {
      57         [ +  + ]:        3163 :             if (lowbound)
      58                 :        2519 :                 *lowbound = stopMiddle + 1;
      59                 :        3163 :             return stopMiddle;
      60                 :             :         }
      61         [ +  + ]:       15393 :         else if (difference < 0)
      62                 :        8228 :             stopLow = stopMiddle + 1;
      63                 :             :         else
      64                 :        7165 :             stopHigh = stopMiddle;
      65                 :             :     }
      66                 :             : 
      67         [ +  + ]:        6293 :     if (lowbound)
      68                 :        5329 :         *lowbound = stopLow;
      69                 :        6293 :     return -1;
      70                 :             : }
      71                 :             : 
      72                 :             : Pairs *
      73                 :        2842 : hstoreArrayToPairs(ArrayType *a, int *npairs)
      74                 :             : {
      75                 :             :     Datum      *key_datums;
      76                 :             :     bool       *key_nulls;
      77                 :             :     int         key_count;
      78                 :             :     Pairs      *key_pairs;
      79                 :             :     int         bufsiz;
      80                 :             :     int         i,
      81                 :             :                 j;
      82                 :             : 
      83                 :        2842 :     deconstruct_array_builtin(a, TEXTOID, &key_datums, &key_nulls, &key_count);
      84                 :             : 
      85         [ +  + ]:        2842 :     if (key_count == 0)
      86                 :             :     {
      87                 :           5 :         *npairs = 0;
      88                 :           5 :         return NULL;
      89                 :             :     }
      90                 :             : 
      91                 :             :     /*
      92                 :             :      * A text array uses at least eight bytes per element, so any overflow in
      93                 :             :      * "key_count * sizeof(Pairs)" is small enough for palloc() to catch.
      94                 :             :      * However, credible improvements to the array format could invalidate
      95                 :             :      * that assumption.  Therefore, use an explicit check rather than relying
      96                 :             :      * on palloc() to complain.
      97                 :             :      */
      98         [ -  + ]:        2837 :     if (key_count > MaxAllocSize / sizeof(Pairs))
      99         [ #  # ]:           0 :         ereport(ERROR,
     100                 :             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     101                 :             :                  errmsg("number of pairs (%d) exceeds the maximum allowed (%d)",
     102                 :             :                         key_count, (int) (MaxAllocSize / sizeof(Pairs)))));
     103                 :             : 
     104                 :        2837 :     key_pairs = palloc(sizeof(Pairs) * key_count);
     105                 :             : 
     106         [ +  + ]:        8516 :     for (i = 0, j = 0; i < key_count; i++)
     107                 :             :     {
     108         [ +  - ]:        5679 :         if (!key_nulls[i])
     109                 :             :         {
     110                 :        5679 :             key_pairs[j].key = VARDATA(DatumGetPointer(key_datums[i]));
     111                 :        5679 :             key_pairs[j].keylen = VARSIZE(DatumGetPointer(key_datums[i])) - VARHDRSZ;
     112                 :        5679 :             key_pairs[j].val = NULL;
     113                 :        5679 :             key_pairs[j].vallen = 0;
     114                 :        5679 :             key_pairs[j].needfree = 0;
     115                 :        5679 :             key_pairs[j].isnull = 1;
     116                 :        5679 :             j++;
     117                 :             :         }
     118                 :             :     }
     119                 :             : 
     120                 :        2837 :     *npairs = hstoreUniquePairs(key_pairs, j, &bufsiz);
     121                 :             : 
     122                 :        2837 :     return key_pairs;
     123                 :             : }
     124                 :             : 
     125                 :             : 
     126                 :           8 : PG_FUNCTION_INFO_V1(hstore_fetchval);
     127                 :             : Datum
     128                 :           6 : hstore_fetchval(PG_FUNCTION_ARGS)
     129                 :             : {
     130                 :           6 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     131                 :           6 :     text       *key = PG_GETARG_TEXT_PP(1);
     132                 :           6 :     HEntry     *entries = ARRPTR(hs);
     133                 :             :     text       *out;
     134                 :           6 :     int         idx = hstoreFindKey(hs, NULL,
     135                 :           6 :                                     VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
     136                 :             : 
     137   [ +  +  +  + ]:           6 :     if (idx < 0 || HSTORE_VALISNULL(entries, idx))
     138                 :           2 :         PG_RETURN_NULL();
     139                 :             : 
     140         [ +  - ]:           4 :     out = cstring_to_text_with_len(HSTORE_VAL(entries, STRPTR(hs), idx),
     141         [ -  + ]:           4 :                                    HSTORE_VALLEN(entries, idx));
     142                 :             : 
     143                 :           4 :     PG_RETURN_TEXT_P(out);
     144                 :             : }
     145                 :             : 
     146                 :             : 
     147                 :          16 : PG_FUNCTION_INFO_V1(hstore_exists);
     148                 :             : Datum
     149                 :        1440 : hstore_exists(PG_FUNCTION_ARGS)
     150                 :             : {
     151                 :        1440 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     152                 :        1440 :     text       *key = PG_GETARG_TEXT_PP(1);
     153                 :        1440 :     int         idx = hstoreFindKey(hs, NULL,
     154                 :        1440 :                                     VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
     155                 :             : 
     156                 :        1440 :     PG_RETURN_BOOL(idx >= 0);
     157                 :             : }
     158                 :             : 
     159                 :             : 
     160                 :           8 : PG_FUNCTION_INFO_V1(hstore_exists_any);
     161                 :             : Datum
     162                 :        1727 : hstore_exists_any(PG_FUNCTION_ARGS)
     163                 :             : {
     164                 :        1727 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     165                 :        1727 :     ArrayType  *keys = PG_GETARG_ARRAYTYPE_P(1);
     166                 :             :     int         nkeys;
     167                 :        1727 :     Pairs      *key_pairs = hstoreArrayToPairs(keys, &nkeys);
     168                 :             :     int         i;
     169                 :        1727 :     int         lowbound = 0;
     170                 :        1727 :     bool        res = false;
     171                 :             : 
     172                 :             :     /*
     173                 :             :      * we exploit the fact that the pairs list is already sorted into strictly
     174                 :             :      * increasing order to narrow the hstoreFindKey search; each search can
     175                 :             :      * start one entry past the previous "found" entry, or at the lower bound
     176                 :             :      * of the last search.
     177                 :             :      */
     178         [ +  + ]:        3580 :     for (i = 0; i < nkeys; i++)
     179                 :             :     {
     180                 :        2867 :         int         idx = hstoreFindKey(hs, &lowbound,
     181                 :        2867 :                                         key_pairs[i].key, key_pairs[i].keylen);
     182                 :             : 
     183         [ +  + ]:        2867 :         if (idx >= 0)
     184                 :             :         {
     185                 :        1014 :             res = true;
     186                 :        1014 :             break;
     187                 :             :         }
     188                 :             :     }
     189                 :             : 
     190                 :        1727 :     PG_RETURN_BOOL(res);
     191                 :             : }
     192                 :             : 
     193                 :             : 
     194                 :           8 : PG_FUNCTION_INFO_V1(hstore_exists_all);
     195                 :             : Datum
     196                 :        1097 : hstore_exists_all(PG_FUNCTION_ARGS)
     197                 :             : {
     198                 :        1097 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     199                 :        1097 :     ArrayType  *keys = PG_GETARG_ARRAYTYPE_P(1);
     200                 :             :     int         nkeys;
     201                 :        1097 :     Pairs      *key_pairs = hstoreArrayToPairs(keys, &nkeys);
     202                 :             :     int         i;
     203                 :        1097 :     int         lowbound = 0;
     204                 :        1097 :     bool        res = true;
     205                 :             : 
     206                 :             :     /*
     207                 :             :      * we exploit the fact that the pairs list is already sorted into strictly
     208                 :             :      * increasing order to narrow the hstoreFindKey search; each search can
     209                 :             :      * start one entry past the previous "found" entry, or at the lower bound
     210                 :             :      * of the last search.
     211                 :             :      */
     212         [ +  + ]:        1507 :     for (i = 0; i < nkeys; i++)
     213                 :             :     {
     214                 :        1378 :         int         idx = hstoreFindKey(hs, &lowbound,
     215                 :        1378 :                                         key_pairs[i].key, key_pairs[i].keylen);
     216                 :             : 
     217         [ +  + ]:        1378 :         if (idx < 0)
     218                 :             :         {
     219                 :         968 :             res = false;
     220                 :         968 :             break;
     221                 :             :         }
     222                 :             :     }
     223                 :             : 
     224                 :        1097 :     PG_RETURN_BOOL(res);
     225                 :             : }
     226                 :             : 
     227                 :             : 
     228                 :          15 : PG_FUNCTION_INFO_V1(hstore_defined);
     229                 :             : Datum
     230                 :           4 : hstore_defined(PG_FUNCTION_ARGS)
     231                 :             : {
     232                 :           4 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     233                 :           4 :     text       *key = PG_GETARG_TEXT_PP(1);
     234                 :           4 :     HEntry     *entries = ARRPTR(hs);
     235                 :           4 :     int         idx = hstoreFindKey(hs, NULL,
     236                 :           4 :                                     VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
     237   [ +  +  +  + ]:           4 :     bool        res = (idx >= 0 && !HSTORE_VALISNULL(entries, idx));
     238                 :             : 
     239                 :           4 :     PG_RETURN_BOOL(res);
     240                 :             : }
     241                 :             : 
     242                 :             : 
     243                 :           8 : PG_FUNCTION_INFO_V1(hstore_delete);
     244                 :             : Datum
     245                 :          11 : hstore_delete(PG_FUNCTION_ARGS)
     246                 :             : {
     247                 :          11 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     248                 :          11 :     text       *key = PG_GETARG_TEXT_PP(1);
     249                 :          11 :     char       *keyptr = VARDATA_ANY(key);
     250                 :          11 :     int         keylen = VARSIZE_ANY_EXHDR(key);
     251                 :          11 :     HStore     *out = palloc(VARSIZE(hs));
     252                 :             :     char       *bufs,
     253                 :             :                *bufd,
     254                 :             :                *ptrd;
     255                 :             :     HEntry     *es,
     256                 :             :                *ed;
     257                 :             :     int         i;
     258                 :          11 :     int         count = HS_COUNT(hs);
     259                 :          11 :     int         outcount = 0;
     260                 :             : 
     261                 :          11 :     SET_VARSIZE(out, VARSIZE(hs));
     262                 :          11 :     HS_SETCOUNT(out, count);    /* temporary! */
     263                 :             : 
     264                 :          11 :     bufs = STRPTR(hs);
     265                 :          11 :     es = ARRPTR(hs);
     266                 :          11 :     bufd = ptrd = STRPTR(out);
     267                 :          11 :     ed = ARRPTR(out);
     268                 :             : 
     269         [ +  + ]:          44 :     for (i = 0; i < count; ++i)
     270                 :             :     {
     271         [ +  + ]:          33 :         int         len = HSTORE_KEYLEN(es, i);
     272         [ +  + ]:          33 :         char       *ptrs = HSTORE_KEY(es, bufs, i);
     273                 :             : 
     274   [ +  -  +  + ]:          33 :         if (!(len == keylen && memcmp(ptrs, keyptr, keylen) == 0))
     275                 :             :         {
     276         [ -  + ]:          24 :             int         vallen = HSTORE_VALLEN(es, i);
     277                 :             : 
     278                 :          24 :             HS_COPYITEM(ed, bufd, ptrd, ptrs, len, vallen,
     279                 :             :                         HSTORE_VALISNULL(es, i));
     280                 :          24 :             ++outcount;
     281                 :             :         }
     282                 :             :     }
     283                 :             : 
     284   [ +  -  +  + ]:          11 :     HS_FINALIZE(out, outcount, bufd, ptrd);
     285                 :             : 
     286                 :          11 :     PG_RETURN_POINTER(out);
     287                 :             : }
     288                 :             : 
     289                 :             : 
     290                 :           8 : PG_FUNCTION_INFO_V1(hstore_delete_array);
     291                 :             : Datum
     292                 :          12 : hstore_delete_array(PG_FUNCTION_ARGS)
     293                 :             : {
     294                 :          12 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     295                 :          12 :     HStore     *out = palloc(VARSIZE(hs));
     296                 :          12 :     int         hs_count = HS_COUNT(hs);
     297                 :             :     char       *ps,
     298                 :             :                *bufd,
     299                 :             :                *pd;
     300                 :             :     HEntry     *es,
     301                 :             :                *ed;
     302                 :             :     int         i,
     303                 :             :                 j;
     304                 :          12 :     int         outcount = 0;
     305                 :          12 :     ArrayType  *key_array = PG_GETARG_ARRAYTYPE_P(1);
     306                 :             :     int         nkeys;
     307                 :          12 :     Pairs      *key_pairs = hstoreArrayToPairs(key_array, &nkeys);
     308                 :             : 
     309                 :          12 :     SET_VARSIZE(out, VARSIZE(hs));
     310                 :          12 :     HS_SETCOUNT(out, hs_count); /* temporary! */
     311                 :             : 
     312                 :          12 :     ps = STRPTR(hs);
     313                 :          12 :     es = ARRPTR(hs);
     314                 :          12 :     bufd = pd = STRPTR(out);
     315                 :          12 :     ed = ARRPTR(out);
     316                 :             : 
     317         [ +  + ]:          12 :     if (nkeys == 0)
     318                 :             :     {
     319                 :             :         /* return a copy of the input, unchanged */
     320                 :           3 :         memcpy(out, hs, VARSIZE(hs));
     321         [ +  - ]:           3 :         HS_FIXSIZE(out, hs_count);
     322                 :           3 :         HS_SETCOUNT(out, hs_count);
     323                 :           3 :         PG_RETURN_POINTER(out);
     324                 :             :     }
     325                 :             : 
     326                 :             :     /*
     327                 :             :      * this is in effect a merge between hs and key_pairs, both of which are
     328                 :             :      * already sorted by (keylen,key); we take keys from hs only
     329                 :             :      */
     330                 :             : 
     331         [ +  + ]:          36 :     for (i = j = 0; i < hs_count;)
     332                 :             :     {
     333                 :             :         int         difference;
     334                 :             : 
     335         [ -  + ]:          27 :         if (j >= nkeys)
     336                 :           0 :             difference = -1;
     337                 :             :         else
     338                 :             :         {
     339         [ +  + ]:          27 :             int         skeylen = HSTORE_KEYLEN(es, i);
     340                 :             : 
     341         [ +  - ]:          27 :             if (skeylen == key_pairs[j].keylen)
     342                 :          27 :                 difference = memcmp(HSTORE_KEY(es, ps, i),
     343                 :          27 :                                     key_pairs[j].key,
     344         [ +  + ]:          27 :                                     key_pairs[j].keylen);
     345                 :             :             else
     346         [ #  # ]:           0 :                 difference = (skeylen > key_pairs[j].keylen) ? 1 : -1;
     347                 :             :         }
     348                 :             : 
     349         [ -  + ]:          27 :         if (difference > 0)
     350                 :           0 :             ++j;
     351         [ +  + ]:          27 :         else if (difference == 0)
     352                 :          14 :             ++i, ++j;
     353                 :             :         else
     354                 :             :         {
     355   [ +  +  -  +  :          13 :             HS_COPYITEM(ed, bufd, pd,
          +  +  +  +  -  
                +  -  + ]
     356                 :             :                         HSTORE_KEY(es, ps, i), HSTORE_KEYLEN(es, i),
     357                 :             :                         HSTORE_VALLEN(es, i), HSTORE_VALISNULL(es, i));
     358                 :          13 :             ++outcount;
     359                 :          13 :             ++i;
     360                 :             :         }
     361                 :             :     }
     362                 :             : 
     363   [ +  +  +  + ]:           9 :     HS_FINALIZE(out, outcount, bufd, pd);
     364                 :             : 
     365                 :           9 :     PG_RETURN_POINTER(out);
     366                 :             : }
     367                 :             : 
     368                 :             : 
     369                 :           8 : PG_FUNCTION_INFO_V1(hstore_delete_hstore);
     370                 :             : Datum
     371                 :          12 : hstore_delete_hstore(PG_FUNCTION_ARGS)
     372                 :             : {
     373                 :          12 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     374                 :          12 :     HStore     *hs2 = PG_GETARG_HSTORE_P(1);
     375                 :          12 :     HStore     *out = palloc(VARSIZE(hs));
     376                 :          12 :     int         hs_count = HS_COUNT(hs);
     377                 :          12 :     int         hs2_count = HS_COUNT(hs2);
     378                 :             :     char       *ps,
     379                 :             :                *ps2,
     380                 :             :                *bufd,
     381                 :             :                *pd;
     382                 :             :     HEntry     *es,
     383                 :             :                *es2,
     384                 :             :                *ed;
     385                 :             :     int         i,
     386                 :             :                 j;
     387                 :          12 :     int         outcount = 0;
     388                 :             : 
     389                 :          12 :     SET_VARSIZE(out, VARSIZE(hs));
     390                 :          12 :     HS_SETCOUNT(out, hs_count); /* temporary! */
     391                 :             : 
     392                 :          12 :     ps = STRPTR(hs);
     393                 :          12 :     es = ARRPTR(hs);
     394                 :          12 :     ps2 = STRPTR(hs2);
     395                 :          12 :     es2 = ARRPTR(hs2);
     396                 :          12 :     bufd = pd = STRPTR(out);
     397                 :          12 :     ed = ARRPTR(out);
     398                 :             : 
     399         [ +  + ]:          12 :     if (hs2_count == 0)
     400                 :             :     {
     401                 :             :         /* return a copy of the input, unchanged */
     402                 :           3 :         memcpy(out, hs, VARSIZE(hs));
     403         [ +  - ]:           3 :         HS_FIXSIZE(out, hs_count);
     404                 :           3 :         HS_SETCOUNT(out, hs_count);
     405                 :           3 :         PG_RETURN_POINTER(out);
     406                 :             :     }
     407                 :             : 
     408                 :             :     /*
     409                 :             :      * this is in effect a merge between hs and hs2, both of which are already
     410                 :             :      * sorted by (keylen,key); we take keys from hs only; for equal keys, we
     411                 :             :      * take the value from hs unless the values are equal
     412                 :             :      */
     413                 :             : 
     414         [ +  + ]:          36 :     for (i = j = 0; i < hs_count;)
     415                 :             :     {
     416                 :             :         int         difference;
     417                 :             : 
     418         [ +  + ]:          27 :         if (j >= hs2_count)
     419                 :           5 :             difference = -1;
     420                 :             :         else
     421                 :             :         {
     422         [ +  + ]:          22 :             int         skeylen = HSTORE_KEYLEN(es, i);
     423         [ +  + ]:          22 :             int         s2keylen = HSTORE_KEYLEN(es2, j);
     424                 :             : 
     425         [ +  + ]:          22 :             if (skeylen == s2keylen)
     426                 :          20 :                 difference = memcmp(HSTORE_KEY(es, ps, i),
     427   [ +  +  +  + ]:          20 :                                     HSTORE_KEY(es2, ps2, j),
     428                 :             :                                     skeylen);
     429                 :             :             else
     430         [ -  + ]:           2 :                 difference = (skeylen > s2keylen) ? 1 : -1;
     431                 :             :         }
     432                 :             : 
     433         [ -  + ]:          27 :         if (difference > 0)
     434                 :           0 :             ++j;
     435         [ +  + ]:          27 :         else if (difference == 0)
     436                 :             :         {
     437         [ -  + ]:          17 :             int         svallen = HSTORE_VALLEN(es, i);
     438                 :          17 :             int         snullval = HSTORE_VALISNULL(es, i);
     439                 :             : 
     440   [ +  +  +  - ]:          17 :             if (snullval != HSTORE_VALISNULL(es2, j) ||
     441   [ -  +  +  - ]:          15 :                 (!snullval && (svallen != HSTORE_VALLEN(es2, j) ||
     442         [ +  + ]:          15 :                                memcmp(HSTORE_VAL(es, ps, i),
     443   [ +  -  +  - ]:          15 :                                       HSTORE_VAL(es2, ps2, j),
     444                 :             :                                       svallen) != 0)))
     445                 :             :             {
     446   [ -  +  +  -  :           4 :                 HS_COPYITEM(ed, bufd, pd,
             -  +  -  + ]
     447                 :             :                             HSTORE_KEY(es, ps, i), HSTORE_KEYLEN(es, i),
     448                 :             :                             svallen, snullval);
     449                 :           4 :                 ++outcount;
     450                 :             :             }
     451                 :          17 :             ++i, ++j;
     452                 :             :         }
     453                 :             :         else
     454                 :             :         {
     455   [ +  +  -  +  :          10 :             HS_COPYITEM(ed, bufd, pd,
          +  +  +  +  -  
                +  -  + ]
     456                 :             :                         HSTORE_KEY(es, ps, i), HSTORE_KEYLEN(es, i),
     457                 :             :                         HSTORE_VALLEN(es, i), HSTORE_VALISNULL(es, i));
     458                 :          10 :             ++outcount;
     459                 :          10 :             ++i;
     460                 :             :         }
     461                 :             :     }
     462                 :             : 
     463   [ +  +  +  - ]:           9 :     HS_FINALIZE(out, outcount, bufd, pd);
     464                 :             : 
     465                 :           9 :     PG_RETURN_POINTER(out);
     466                 :             : }
     467                 :             : 
     468                 :             : 
     469                 :           8 : PG_FUNCTION_INFO_V1(hstore_concat);
     470                 :             : Datum
     471                 :          30 : hstore_concat(PG_FUNCTION_ARGS)
     472                 :             : {
     473                 :          30 :     HStore     *s1 = PG_GETARG_HSTORE_P(0);
     474                 :          30 :     HStore     *s2 = PG_GETARG_HSTORE_P(1);
     475                 :          30 :     HStore     *out = palloc(VARSIZE(s1) + VARSIZE(s2));
     476                 :             :     char       *ps1,
     477                 :             :                *ps2,
     478                 :             :                *bufd,
     479                 :             :                *pd;
     480                 :             :     HEntry     *es1,
     481                 :             :                *es2,
     482                 :             :                *ed;
     483                 :             :     int         s1idx;
     484                 :             :     int         s2idx;
     485                 :          30 :     int         s1count = HS_COUNT(s1);
     486                 :          30 :     int         s2count = HS_COUNT(s2);
     487                 :          30 :     int         outcount = 0;
     488                 :             : 
     489                 :          30 :     SET_VARSIZE(out, VARSIZE(s1) + VARSIZE(s2) - HSHRDSIZE);
     490                 :          30 :     HS_SETCOUNT(out, s1count + s2count);
     491                 :             : 
     492         [ +  + ]:          30 :     if (s1count == 0)
     493                 :             :     {
     494                 :             :         /* return a copy of the input, unchanged */
     495                 :           4 :         memcpy(out, s2, VARSIZE(s2));
     496         [ +  + ]:           4 :         HS_FIXSIZE(out, s2count);
     497                 :           4 :         HS_SETCOUNT(out, s2count);
     498                 :           4 :         PG_RETURN_POINTER(out);
     499                 :             :     }
     500                 :             : 
     501         [ +  + ]:          26 :     if (s2count == 0)
     502                 :             :     {
     503                 :             :         /* return a copy of the input, unchanged */
     504                 :           2 :         memcpy(out, s1, VARSIZE(s1));
     505         [ +  - ]:           2 :         HS_FIXSIZE(out, s1count);
     506                 :           2 :         HS_SETCOUNT(out, s1count);
     507                 :           2 :         PG_RETURN_POINTER(out);
     508                 :             :     }
     509                 :             : 
     510                 :          24 :     ps1 = STRPTR(s1);
     511                 :          24 :     ps2 = STRPTR(s2);
     512                 :          24 :     bufd = pd = STRPTR(out);
     513                 :          24 :     es1 = ARRPTR(s1);
     514                 :          24 :     es2 = ARRPTR(s2);
     515                 :          24 :     ed = ARRPTR(out);
     516                 :             : 
     517                 :             :     /*
     518                 :             :      * this is in effect a merge between s1 and s2, both of which are already
     519                 :             :      * sorted by (keylen,key); we take s2 for equal keys
     520                 :             :      */
     521                 :             : 
     522   [ +  +  +  + ]:          90 :     for (s1idx = s2idx = 0; s1idx < s1count || s2idx < s2count; ++outcount)
     523                 :             :     {
     524                 :             :         int         difference;
     525                 :             : 
     526         [ +  + ]:          66 :         if (s1idx >= s1count)
     527                 :          13 :             difference = 1;
     528         [ +  + ]:          53 :         else if (s2idx >= s2count)
     529                 :           7 :             difference = -1;
     530                 :             :         else
     531                 :             :         {
     532         [ +  + ]:          46 :             int         s1keylen = HSTORE_KEYLEN(es1, s1idx);
     533         [ +  + ]:          46 :             int         s2keylen = HSTORE_KEYLEN(es2, s2idx);
     534                 :             : 
     535         [ +  + ]:          46 :             if (s1keylen == s2keylen)
     536                 :          41 :                 difference = memcmp(HSTORE_KEY(es1, ps1, s1idx),
     537   [ +  +  +  + ]:          41 :                                     HSTORE_KEY(es2, ps2, s2idx),
     538                 :             :                                     s1keylen);
     539                 :             :             else
     540         [ +  + ]:           5 :                 difference = (s1keylen > s2keylen) ? 1 : -1;
     541                 :             :         }
     542                 :             : 
     543         [ +  + ]:          66 :         if (difference >= 0)
     544                 :             :         {
     545   [ +  +  -  +  :          38 :             HS_COPYITEM(ed, bufd, pd,
          +  +  +  +  -  
                +  -  + ]
     546                 :             :                         HSTORE_KEY(es2, ps2, s2idx), HSTORE_KEYLEN(es2, s2idx),
     547                 :             :                         HSTORE_VALLEN(es2, s2idx), HSTORE_VALISNULL(es2, s2idx));
     548                 :          38 :             ++s2idx;
     549         [ +  + ]:          38 :             if (difference == 0)
     550                 :          19 :                 ++s1idx;
     551                 :             :         }
     552                 :             :         else
     553                 :             :         {
     554   [ +  +  -  +  :          28 :             HS_COPYITEM(ed, bufd, pd,
          +  +  +  +  -  
                +  -  + ]
     555                 :             :                         HSTORE_KEY(es1, ps1, s1idx), HSTORE_KEYLEN(es1, s1idx),
     556                 :             :                         HSTORE_VALLEN(es1, s1idx), HSTORE_VALISNULL(es1, s1idx));
     557                 :          28 :             ++s1idx;
     558                 :             :         }
     559                 :             :     }
     560                 :             : 
     561   [ +  -  +  + ]:          24 :     HS_FINALIZE(out, outcount, bufd, pd);
     562                 :             : 
     563                 :          24 :     PG_RETURN_POINTER(out);
     564                 :             : }
     565                 :             : 
     566                 :             : 
     567                 :           8 : PG_FUNCTION_INFO_V1(hstore_slice_to_array);
     568                 :             : Datum
     569                 :           4 : hstore_slice_to_array(PG_FUNCTION_ARGS)
     570                 :             : {
     571                 :           4 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     572                 :           4 :     HEntry     *entries = ARRPTR(hs);
     573                 :           4 :     char       *ptr = STRPTR(hs);
     574                 :           4 :     ArrayType  *key_array = PG_GETARG_ARRAYTYPE_P(1);
     575                 :             :     ArrayType  *aout;
     576                 :             :     Datum      *key_datums;
     577                 :             :     bool       *key_nulls;
     578                 :             :     Datum      *out_datums;
     579                 :             :     bool       *out_nulls;
     580                 :             :     int         key_count;
     581                 :             :     int         i;
     582                 :             : 
     583                 :           4 :     deconstruct_array_builtin(key_array, TEXTOID, &key_datums, &key_nulls, &key_count);
     584                 :             : 
     585         [ -  + ]:           4 :     if (key_count == 0)
     586                 :             :     {
     587                 :           0 :         aout = construct_empty_array(TEXTOID);
     588                 :           0 :         PG_RETURN_POINTER(aout);
     589                 :             :     }
     590                 :             : 
     591                 :           4 :     out_datums = palloc(sizeof(Datum) * key_count);
     592                 :           4 :     out_nulls = palloc(sizeof(bool) * key_count);
     593                 :             : 
     594         [ +  + ]:          15 :     for (i = 0; i < key_count; ++i)
     595                 :             :     {
     596                 :          11 :         text       *key = (text *) DatumGetPointer(key_datums[i]);
     597                 :             :         int         idx;
     598                 :             : 
     599         [ +  + ]:          11 :         if (key_nulls[i])
     600                 :           1 :             idx = -1;
     601                 :             :         else
     602                 :          10 :             idx = hstoreFindKey(hs, NULL, VARDATA(key), VARSIZE(key) - VARHDRSZ);
     603                 :             : 
     604   [ +  +  +  + ]:          11 :         if (idx < 0 || HSTORE_VALISNULL(entries, idx))
     605                 :             :         {
     606                 :           2 :             out_nulls[i] = true;
     607                 :           2 :             out_datums[i] = (Datum) 0;
     608                 :             :         }
     609                 :             :         else
     610                 :             :         {
     611                 :           9 :             out_datums[i] =
     612   [ -  +  +  - ]:           9 :                 PointerGetDatum(cstring_to_text_with_len(HSTORE_VAL(entries, ptr, idx),
     613                 :             :                                                          HSTORE_VALLEN(entries, idx)));
     614                 :           9 :             out_nulls[i] = false;
     615                 :             :         }
     616                 :             :     }
     617                 :             : 
     618                 :           4 :     aout = construct_md_array(out_datums, out_nulls,
     619                 :             :                               ARR_NDIM(key_array),
     620                 :             :                               ARR_DIMS(key_array),
     621                 :           4 :                               ARR_LBOUND(key_array),
     622                 :             :                               TEXTOID, -1, false, TYPALIGN_INT);
     623                 :             : 
     624                 :           4 :     PG_RETURN_POINTER(aout);
     625                 :             : }
     626                 :             : 
     627                 :             : 
     628                 :           8 : PG_FUNCTION_INFO_V1(hstore_slice_to_hstore);
     629                 :             : Datum
     630                 :           6 : hstore_slice_to_hstore(PG_FUNCTION_ARGS)
     631                 :             : {
     632                 :           6 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     633                 :           6 :     HEntry     *entries = ARRPTR(hs);
     634                 :           6 :     char       *ptr = STRPTR(hs);
     635                 :           6 :     ArrayType  *key_array = PG_GETARG_ARRAYTYPE_P(1);
     636                 :             :     HStore     *out;
     637                 :             :     int         nkeys;
     638                 :           6 :     Pairs      *key_pairs = hstoreArrayToPairs(key_array, &nkeys);
     639                 :             :     Pairs      *out_pairs;
     640                 :             :     int         bufsiz;
     641                 :           6 :     int         lastidx = 0;
     642                 :             :     int         i;
     643                 :           6 :     int         out_count = 0;
     644                 :             : 
     645         [ -  + ]:           6 :     if (nkeys == 0)
     646                 :             :     {
     647                 :           0 :         out = hstorePairs(NULL, 0, 0);
     648                 :           0 :         PG_RETURN_POINTER(out);
     649                 :             :     }
     650                 :             : 
     651                 :             :     /* hstoreArrayToPairs() checked overflow */
     652                 :           6 :     out_pairs = palloc(sizeof(Pairs) * nkeys);
     653                 :           6 :     bufsiz = 0;
     654                 :             : 
     655                 :             :     /*
     656                 :             :      * we exploit the fact that the pairs list is already sorted into strictly
     657                 :             :      * increasing order to narrow the hstoreFindKey search; each search can
     658                 :             :      * start one entry past the previous "found" entry, or at the lower bound
     659                 :             :      * of the last search.
     660                 :             :      */
     661                 :             : 
     662         [ +  + ]:          21 :     for (i = 0; i < nkeys; ++i)
     663                 :             :     {
     664                 :          15 :         int         idx = hstoreFindKey(hs, &lastidx,
     665                 :          15 :                                         key_pairs[i].key, key_pairs[i].keylen);
     666                 :             : 
     667         [ +  + ]:          15 :         if (idx >= 0)
     668                 :             :         {
     669                 :          12 :             out_pairs[out_count].key = key_pairs[i].key;
     670                 :          12 :             bufsiz += (out_pairs[out_count].keylen = key_pairs[i].keylen);
     671         [ +  - ]:          12 :             out_pairs[out_count].val = HSTORE_VAL(entries, ptr, idx);
     672         [ -  + ]:          12 :             bufsiz += (out_pairs[out_count].vallen = HSTORE_VALLEN(entries, idx));
     673                 :          12 :             out_pairs[out_count].isnull = HSTORE_VALISNULL(entries, idx);
     674                 :          12 :             out_pairs[out_count].needfree = false;
     675                 :          12 :             ++out_count;
     676                 :             :         }
     677                 :             :     }
     678                 :             : 
     679                 :             :     /*
     680                 :             :      * we don't use hstoreUniquePairs here because we know that the pairs list
     681                 :             :      * is already sorted and uniq'ed.
     682                 :             :      */
     683                 :             : 
     684                 :           6 :     out = hstorePairs(out_pairs, out_count, bufsiz);
     685                 :             : 
     686                 :           6 :     PG_RETURN_POINTER(out);
     687                 :             : }
     688                 :             : 
     689                 :             : 
     690                 :           8 : PG_FUNCTION_INFO_V1(hstore_akeys);
     691                 :             : Datum
     692                 :           3 : hstore_akeys(PG_FUNCTION_ARGS)
     693                 :             : {
     694                 :           3 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     695                 :             :     Datum      *d;
     696                 :             :     ArrayType  *a;
     697                 :           3 :     HEntry     *entries = ARRPTR(hs);
     698                 :           3 :     char       *base = STRPTR(hs);
     699                 :           3 :     int         count = HS_COUNT(hs);
     700                 :             :     int         i;
     701                 :             : 
     702         [ +  + ]:           3 :     if (count == 0)
     703                 :             :     {
     704                 :           1 :         a = construct_empty_array(TEXTOID);
     705                 :           1 :         PG_RETURN_POINTER(a);
     706                 :             :     }
     707                 :             : 
     708                 :           2 :     d = (Datum *) palloc(sizeof(Datum) * count);
     709                 :             : 
     710         [ +  + ]:           7 :     for (i = 0; i < count; ++i)
     711                 :             :     {
     712         [ +  + ]:           5 :         text       *t = cstring_to_text_with_len(HSTORE_KEY(entries, base, i),
     713         [ +  + ]:           5 :                                                  HSTORE_KEYLEN(entries, i));
     714                 :             : 
     715                 :           5 :         d[i] = PointerGetDatum(t);
     716                 :             :     }
     717                 :             : 
     718                 :           2 :     a = construct_array_builtin(d, count, TEXTOID);
     719                 :             : 
     720                 :           2 :     PG_RETURN_POINTER(a);
     721                 :             : }
     722                 :             : 
     723                 :             : 
     724                 :           8 : PG_FUNCTION_INFO_V1(hstore_avals);
     725                 :             : Datum
     726                 :           4 : hstore_avals(PG_FUNCTION_ARGS)
     727                 :             : {
     728                 :           4 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     729                 :             :     Datum      *d;
     730                 :             :     bool       *nulls;
     731                 :             :     ArrayType  *a;
     732                 :           4 :     HEntry     *entries = ARRPTR(hs);
     733                 :           4 :     char       *base = STRPTR(hs);
     734                 :           4 :     int         count = HS_COUNT(hs);
     735                 :           4 :     int         lb = 1;
     736                 :             :     int         i;
     737                 :             : 
     738         [ +  + ]:           4 :     if (count == 0)
     739                 :             :     {
     740                 :           1 :         a = construct_empty_array(TEXTOID);
     741                 :           1 :         PG_RETURN_POINTER(a);
     742                 :             :     }
     743                 :             : 
     744                 :           3 :     d = (Datum *) palloc(sizeof(Datum) * count);
     745                 :           3 :     nulls = (bool *) palloc(sizeof(bool) * count);
     746                 :             : 
     747         [ +  + ]:          12 :     for (i = 0; i < count; ++i)
     748                 :             :     {
     749         [ +  + ]:           9 :         if (HSTORE_VALISNULL(entries, i))
     750                 :             :         {
     751                 :           1 :             d[i] = (Datum) 0;
     752                 :           1 :             nulls[i] = true;
     753                 :             :         }
     754                 :             :         else
     755                 :             :         {
     756         [ +  - ]:           8 :             text       *item = cstring_to_text_with_len(HSTORE_VAL(entries, base, i),
     757         [ -  + ]:           8 :                                                         HSTORE_VALLEN(entries, i));
     758                 :             : 
     759                 :           8 :             d[i] = PointerGetDatum(item);
     760                 :           8 :             nulls[i] = false;
     761                 :             :         }
     762                 :             :     }
     763                 :             : 
     764                 :           3 :     a = construct_md_array(d, nulls, 1, &count, &lb,
     765                 :             :                            TEXTOID, -1, false, TYPALIGN_INT);
     766                 :             : 
     767                 :           3 :     PG_RETURN_POINTER(a);
     768                 :             : }
     769                 :             : 
     770                 :             : 
     771                 :             : static ArrayType *
     772                 :           4 : hstore_to_array_internal(HStore *hs, int ndims)
     773                 :             : {
     774                 :           4 :     HEntry     *entries = ARRPTR(hs);
     775                 :           4 :     char       *base = STRPTR(hs);
     776                 :           4 :     int         count = HS_COUNT(hs);
     777                 :           4 :     int         out_size[2] = {0, 2};
     778                 :           4 :     int         lb[2] = {1, 1};
     779                 :             :     Datum      *out_datums;
     780                 :             :     bool       *out_nulls;
     781                 :             :     int         i;
     782                 :             : 
     783                 :             :     Assert(ndims < 3);
     784                 :             : 
     785   [ +  -  -  + ]:           4 :     if (count == 0 || ndims == 0)
     786                 :           0 :         return construct_empty_array(TEXTOID);
     787                 :             : 
     788                 :           4 :     out_size[0] = count * 2 / ndims;
     789                 :           4 :     out_datums = palloc(sizeof(Datum) * count * 2);
     790                 :           4 :     out_nulls = palloc(sizeof(bool) * count * 2);
     791                 :             : 
     792         [ +  + ]:          20 :     for (i = 0; i < count; ++i)
     793                 :             :     {
     794         [ +  + ]:          16 :         text       *key = cstring_to_text_with_len(HSTORE_KEY(entries, base, i),
     795         [ +  + ]:          16 :                                                    HSTORE_KEYLEN(entries, i));
     796                 :             : 
     797                 :          16 :         out_datums[i * 2] = PointerGetDatum(key);
     798                 :          16 :         out_nulls[i * 2] = false;
     799                 :             : 
     800         [ +  + ]:          16 :         if (HSTORE_VALISNULL(entries, i))
     801                 :             :         {
     802                 :           4 :             out_datums[i * 2 + 1] = (Datum) 0;
     803                 :           4 :             out_nulls[i * 2 + 1] = true;
     804                 :             :         }
     805                 :             :         else
     806                 :             :         {
     807         [ +  - ]:          12 :             text       *item = cstring_to_text_with_len(HSTORE_VAL(entries, base, i),
     808         [ -  + ]:          12 :                                                         HSTORE_VALLEN(entries, i));
     809                 :             : 
     810                 :          12 :             out_datums[i * 2 + 1] = PointerGetDatum(item);
     811                 :          12 :             out_nulls[i * 2 + 1] = false;
     812                 :             :         }
     813                 :             :     }
     814                 :             : 
     815                 :           4 :     return construct_md_array(out_datums, out_nulls,
     816                 :             :                               ndims, out_size, lb,
     817                 :             :                               TEXTOID, -1, false, TYPALIGN_INT);
     818                 :             : }
     819                 :             : 
     820                 :           8 : PG_FUNCTION_INFO_V1(hstore_to_array);
     821                 :             : Datum
     822                 :           2 : hstore_to_array(PG_FUNCTION_ARGS)
     823                 :             : {
     824                 :           2 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     825                 :           2 :     ArrayType  *out = hstore_to_array_internal(hs, 1);
     826                 :             : 
     827                 :           2 :     PG_RETURN_POINTER(out);
     828                 :             : }
     829                 :             : 
     830                 :           8 : PG_FUNCTION_INFO_V1(hstore_to_matrix);
     831                 :             : Datum
     832                 :           2 : hstore_to_matrix(PG_FUNCTION_ARGS)
     833                 :             : {
     834                 :           2 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     835                 :           2 :     ArrayType  *out = hstore_to_array_internal(hs, 2);
     836                 :             : 
     837                 :           2 :     PG_RETURN_POINTER(out);
     838                 :             : }
     839                 :             : 
     840                 :             : /*
     841                 :             :  * Common initialization function for the various set-returning
     842                 :             :  * funcs. fcinfo is only passed if the function is to return a
     843                 :             :  * composite; it will be used to look up the return tupledesc.
     844                 :             :  * we stash a copy of the hstore in the multi-call context in
     845                 :             :  * case it was originally toasted. (At least I assume that's why;
     846                 :             :  * there was no explanatory comment in the original code. --AG)
     847                 :             :  */
     848                 :             : 
     849                 :             : static void
     850                 :        2010 : setup_firstcall(FuncCallContext *funcctx, HStore *hs,
     851                 :             :                 FunctionCallInfo fcinfo)
     852                 :             : {
     853                 :             :     MemoryContext oldcontext;
     854                 :             :     HStore     *st;
     855                 :             : 
     856                 :        2010 :     oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
     857                 :             : 
     858                 :        2010 :     st = (HStore *) palloc(VARSIZE(hs));
     859                 :        2010 :     memcpy(st, hs, VARSIZE(hs));
     860                 :             : 
     861                 :        2010 :     funcctx->user_fctx = st;
     862                 :             : 
     863         [ +  + ]:        2010 :     if (fcinfo)
     864                 :             :     {
     865                 :             :         TupleDesc   tupdesc;
     866                 :             : 
     867                 :             :         /* Build a tuple descriptor for our result type */
     868         [ -  + ]:        2003 :         if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
     869         [ #  # ]:           0 :             elog(ERROR, "return type must be a row type");
     870                 :             : 
     871                 :        2003 :         funcctx->tuple_desc = BlessTupleDesc(tupdesc);
     872                 :             :     }
     873                 :             : 
     874                 :        2010 :     MemoryContextSwitchTo(oldcontext);
     875                 :        2010 : }
     876                 :             : 
     877                 :             : 
     878                 :           8 : PG_FUNCTION_INFO_V1(hstore_skeys);
     879                 :             : Datum
     880                 :           8 : hstore_skeys(PG_FUNCTION_ARGS)
     881                 :             : {
     882                 :             :     FuncCallContext *funcctx;
     883                 :             :     HStore     *hs;
     884                 :             :     int         i;
     885                 :             : 
     886         [ +  + ]:           8 :     if (SRF_IS_FIRSTCALL())
     887                 :             :     {
     888                 :           3 :         hs = PG_GETARG_HSTORE_P(0);
     889                 :           3 :         funcctx = SRF_FIRSTCALL_INIT();
     890                 :           3 :         setup_firstcall(funcctx, hs, NULL);
     891                 :             :     }
     892                 :             : 
     893                 :           8 :     funcctx = SRF_PERCALL_SETUP();
     894                 :           8 :     hs = (HStore *) funcctx->user_fctx;
     895                 :           8 :     i = funcctx->call_cntr;
     896                 :             : 
     897         [ +  + ]:           8 :     if (i < HS_COUNT(hs))
     898                 :             :     {
     899                 :           5 :         HEntry     *entries = ARRPTR(hs);
     900                 :             :         text       *item;
     901                 :             : 
     902         [ +  + ]:           5 :         item = cstring_to_text_with_len(HSTORE_KEY(entries, STRPTR(hs), i),
     903         [ +  + ]:           5 :                                         HSTORE_KEYLEN(entries, i));
     904                 :             : 
     905                 :           5 :         SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
     906                 :             :     }
     907                 :             : 
     908                 :           3 :     SRF_RETURN_DONE(funcctx);
     909                 :             : }
     910                 :             : 
     911                 :             : 
     912                 :           8 : PG_FUNCTION_INFO_V1(hstore_svals);
     913                 :             : Datum
     914                 :          13 : hstore_svals(PG_FUNCTION_ARGS)
     915                 :             : {
     916                 :             :     FuncCallContext *funcctx;
     917                 :             :     HStore     *hs;
     918                 :             :     int         i;
     919                 :             : 
     920         [ +  + ]:          13 :     if (SRF_IS_FIRSTCALL())
     921                 :             :     {
     922                 :           4 :         hs = PG_GETARG_HSTORE_P(0);
     923                 :           4 :         funcctx = SRF_FIRSTCALL_INIT();
     924                 :           4 :         setup_firstcall(funcctx, hs, NULL);
     925                 :             :     }
     926                 :             : 
     927                 :          13 :     funcctx = SRF_PERCALL_SETUP();
     928                 :          13 :     hs = (HStore *) funcctx->user_fctx;
     929                 :          13 :     i = funcctx->call_cntr;
     930                 :             : 
     931         [ +  + ]:          13 :     if (i < HS_COUNT(hs))
     932                 :             :     {
     933                 :           9 :         HEntry     *entries = ARRPTR(hs);
     934                 :             : 
     935         [ +  + ]:           9 :         if (HSTORE_VALISNULL(entries, i))
     936                 :             :         {
     937                 :             :             ReturnSetInfo *rsi;
     938                 :             : 
     939                 :             :             /* ugly ugly ugly. why no macro for this? */
     940                 :           1 :             (funcctx)->call_cntr++;
     941                 :           1 :             rsi = (ReturnSetInfo *) fcinfo->resultinfo;
     942                 :           1 :             rsi->isDone = ExprMultipleResult;
     943                 :           1 :             PG_RETURN_NULL();
     944                 :             :         }
     945                 :             :         else
     946                 :             :         {
     947                 :             :             text       *item;
     948                 :             : 
     949         [ +  - ]:           8 :             item = cstring_to_text_with_len(HSTORE_VAL(entries, STRPTR(hs), i),
     950         [ -  + ]:           8 :                                             HSTORE_VALLEN(entries, i));
     951                 :             : 
     952                 :           8 :             SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
     953                 :             :         }
     954                 :             :     }
     955                 :             : 
     956                 :           4 :     SRF_RETURN_DONE(funcctx);
     957                 :             : }
     958                 :             : 
     959                 :             : 
     960                 :           8 : PG_FUNCTION_INFO_V1(hstore_contains);
     961                 :             : Datum
     962                 :        3560 : hstore_contains(PG_FUNCTION_ARGS)
     963                 :             : {
     964                 :        3560 :     HStore     *val = PG_GETARG_HSTORE_P(0);
     965                 :        3560 :     HStore     *tmpl = PG_GETARG_HSTORE_P(1);
     966                 :        3560 :     bool        res = true;
     967                 :        3560 :     HEntry     *te = ARRPTR(tmpl);
     968                 :        3560 :     char       *tstr = STRPTR(tmpl);
     969                 :        3560 :     HEntry     *ve = ARRPTR(val);
     970                 :        3560 :     char       *vstr = STRPTR(val);
     971                 :        3560 :     int         tcount = HS_COUNT(tmpl);
     972                 :        3560 :     int         lastidx = 0;
     973                 :             :     int         i;
     974                 :             : 
     975                 :             :     /*
     976                 :             :      * we exploit the fact that keys in "tmpl" are in strictly increasing
     977                 :             :      * order to narrow the hstoreFindKey search; each search can start one
     978                 :             :      * entry past the previous "found" entry, or at the lower bound of the
     979                 :             :      * search
     980                 :             :      */
     981                 :             : 
     982   [ +  +  +  + ]:        7148 :     for (i = 0; res && i < tcount; ++i)
     983                 :             :     {
     984                 :        3588 :         int         idx = hstoreFindKey(val, &lastidx,
     985         [ +  + ]:        3588 :                                         HSTORE_KEY(te, tstr, i),
     986         [ +  + ]:        3588 :                                         HSTORE_KEYLEN(te, i));
     987                 :             : 
     988         [ +  + ]:        3588 :         if (idx >= 0)
     989                 :             :         {
     990                 :        1083 :             bool        nullval = HSTORE_VALISNULL(te, i);
     991         [ -  + ]:        1083 :             int         vallen = HSTORE_VALLEN(te, i);
     992                 :             : 
     993         [ +  + ]:        1083 :             if (nullval != HSTORE_VALISNULL(ve, idx) ||
     994   [ +  +  -  +  :         513 :                 (!nullval && (vallen != HSTORE_VALLEN(ve, idx) ||
                   +  + ]
     995         [ +  + ]:         305 :                               memcmp(HSTORE_VAL(te, tstr, i),
     996   [ +  -  +  - ]:         305 :                                      HSTORE_VAL(ve, vstr, idx),
     997                 :             :                                      vallen) != 0)))
     998                 :         980 :                 res = false;
     999                 :             :         }
    1000                 :             :         else
    1001                 :        2505 :             res = false;
    1002                 :             :     }
    1003                 :             : 
    1004                 :        3560 :     PG_RETURN_BOOL(res);
    1005                 :             : }
    1006                 :             : 
    1007                 :             : 
    1008                 :           7 : PG_FUNCTION_INFO_V1(hstore_contained);
    1009                 :             : Datum
    1010                 :           0 : hstore_contained(PG_FUNCTION_ARGS)
    1011                 :             : {
    1012                 :           0 :     PG_RETURN_DATUM(DirectFunctionCall2(hstore_contains,
    1013                 :             :                                         PG_GETARG_DATUM(1),
    1014                 :             :                                         PG_GETARG_DATUM(0)
    1015                 :             :                                         ));
    1016                 :             : }
    1017                 :             : 
    1018                 :             : 
    1019                 :           8 : PG_FUNCTION_INFO_V1(hstore_each);
    1020                 :             : Datum
    1021                 :       11568 : hstore_each(PG_FUNCTION_ARGS)
    1022                 :             : {
    1023                 :             :     FuncCallContext *funcctx;
    1024                 :             :     HStore     *hs;
    1025                 :             :     int         i;
    1026                 :             : 
    1027         [ +  + ]:       11568 :     if (SRF_IS_FIRSTCALL())
    1028                 :             :     {
    1029                 :        2003 :         hs = PG_GETARG_HSTORE_P(0);
    1030                 :        2003 :         funcctx = SRF_FIRSTCALL_INIT();
    1031                 :        2003 :         setup_firstcall(funcctx, hs, fcinfo);
    1032                 :             :     }
    1033                 :             : 
    1034                 :       11568 :     funcctx = SRF_PERCALL_SETUP();
    1035                 :       11568 :     hs = (HStore *) funcctx->user_fctx;
    1036                 :       11568 :     i = funcctx->call_cntr;
    1037                 :             : 
    1038         [ +  + ]:       11568 :     if (i < HS_COUNT(hs))
    1039                 :             :     {
    1040                 :        9565 :         HEntry     *entries = ARRPTR(hs);
    1041                 :        9565 :         char       *ptr = STRPTR(hs);
    1042                 :             :         Datum       res,
    1043                 :             :                     dvalues[2];
    1044                 :        9565 :         bool        nulls[2] = {false, false};
    1045                 :             :         text       *item;
    1046                 :             :         HeapTuple   tuple;
    1047                 :             : 
    1048         [ +  + ]:        9565 :         item = cstring_to_text_with_len(HSTORE_KEY(entries, ptr, i),
    1049         [ +  + ]:        9565 :                                         HSTORE_KEYLEN(entries, i));
    1050                 :        9565 :         dvalues[0] = PointerGetDatum(item);
    1051                 :             : 
    1052         [ +  + ]:        9565 :         if (HSTORE_VALISNULL(entries, i))
    1053                 :             :         {
    1054                 :           3 :             dvalues[1] = (Datum) 0;
    1055                 :           3 :             nulls[1] = true;
    1056                 :             :         }
    1057                 :             :         else
    1058                 :             :         {
    1059         [ +  - ]:        9562 :             item = cstring_to_text_with_len(HSTORE_VAL(entries, ptr, i),
    1060         [ -  + ]:        9562 :                                             HSTORE_VALLEN(entries, i));
    1061                 :        9562 :             dvalues[1] = PointerGetDatum(item);
    1062                 :             :         }
    1063                 :             : 
    1064                 :        9565 :         tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
    1065                 :        9565 :         res = HeapTupleGetDatum(tuple);
    1066                 :             : 
    1067                 :        9565 :         SRF_RETURN_NEXT(funcctx, res);
    1068                 :             :     }
    1069                 :             : 
    1070                 :        2003 :     SRF_RETURN_DONE(funcctx);
    1071                 :             : }
    1072                 :             : 
    1073                 :             : 
    1074                 :             : /*
    1075                 :             :  * btree sort order for hstores isn't intended to be useful; we really only
    1076                 :             :  * care about equality versus non-equality.  we compare the entire string
    1077                 :             :  * buffer first, then the entry pos array.
    1078                 :             :  */
    1079                 :             : 
    1080                 :           8 : PG_FUNCTION_INFO_V1(hstore_cmp);
    1081                 :             : Datum
    1082                 :       43142 : hstore_cmp(PG_FUNCTION_ARGS)
    1083                 :             : {
    1084                 :       43142 :     HStore     *hs1 = PG_GETARG_HSTORE_P(0);
    1085                 :       43142 :     HStore     *hs2 = PG_GETARG_HSTORE_P(1);
    1086                 :       43142 :     int         hcount1 = HS_COUNT(hs1);
    1087                 :       43142 :     int         hcount2 = HS_COUNT(hs2);
    1088                 :       43142 :     int         res = 0;
    1089                 :             : 
    1090   [ +  +  +  + ]:       43142 :     if (hcount1 == 0 || hcount2 == 0)
    1091                 :             :     {
    1092                 :             :         /*
    1093                 :             :          * if either operand is empty, and the other is nonempty, the nonempty
    1094                 :             :          * one is larger. If both are empty they are equal.
    1095                 :             :          */
    1096         [ +  + ]:        3676 :         if (hcount1 > 0)
    1097                 :         253 :             res = 1;
    1098         [ +  + ]:        3423 :         else if (hcount2 > 0)
    1099                 :        1635 :             res = -1;
    1100                 :             :     }
    1101                 :             :     else
    1102                 :             :     {
    1103                 :             :         /* here we know both operands are nonempty */
    1104                 :       39466 :         char       *str1 = STRPTR(hs1);
    1105                 :       39466 :         char       *str2 = STRPTR(hs2);
    1106                 :       39466 :         HEntry     *ent1 = ARRPTR(hs1);
    1107                 :       39466 :         HEntry     *ent2 = ARRPTR(hs2);
    1108                 :       39466 :         size_t      len1 = HSE_ENDPOS(ent1[2 * hcount1 - 1]);
    1109                 :       39466 :         size_t      len2 = HSE_ENDPOS(ent2[2 * hcount2 - 1]);
    1110                 :             : 
    1111                 :       39466 :         res = memcmp(str1, str2, Min(len1, len2));
    1112                 :             : 
    1113         [ +  + ]:       39466 :         if (res == 0)
    1114                 :             :         {
    1115         [ -  + ]:        2770 :             if (len1 > len2)
    1116                 :           0 :                 res = 1;
    1117         [ -  + ]:        2770 :             else if (len1 < len2)
    1118                 :           0 :                 res = -1;
    1119         [ -  + ]:        2770 :             else if (hcount1 > hcount2)
    1120                 :           0 :                 res = 1;
    1121         [ -  + ]:        2770 :             else if (hcount2 > hcount1)
    1122                 :           0 :                 res = -1;
    1123                 :             :             else
    1124                 :             :             {
    1125                 :        2770 :                 int         count = hcount1 * 2;
    1126                 :             :                 int         i;
    1127                 :             : 
    1128         [ +  + ]:       32770 :                 for (i = 0; i < count; ++i)
    1129         [ +  - ]:       30000 :                     if (HSE_ENDPOS(ent1[i]) != HSE_ENDPOS(ent2[i]) ||
    1130         [ +  - ]:       30000 :                         HSE_ISNULL(ent1[i]) != HSE_ISNULL(ent2[i]))
    1131                 :             :                         break;
    1132         [ -  + ]:        2770 :                 if (i < count)
    1133                 :             :                 {
    1134         [ #  # ]:           0 :                     if (HSE_ENDPOS(ent1[i]) < HSE_ENDPOS(ent2[i]))
    1135                 :           0 :                         res = -1;
    1136         [ #  # ]:           0 :                     else if (HSE_ENDPOS(ent1[i]) > HSE_ENDPOS(ent2[i]))
    1137                 :           0 :                         res = 1;
    1138         [ #  # ]:           0 :                     else if (HSE_ISNULL(ent1[i]))
    1139                 :           0 :                         res = 1;
    1140         [ #  # ]:           0 :                     else if (HSE_ISNULL(ent2[i]))
    1141                 :           0 :                         res = -1;
    1142                 :             :                 }
    1143                 :             :             }
    1144                 :             :         }
    1145                 :             :         else
    1146                 :             :         {
    1147         [ +  + ]:       36696 :             res = (res > 0) ? 1 : -1;
    1148                 :             :         }
    1149                 :             :     }
    1150                 :             : 
    1151                 :             :     /*
    1152                 :             :      * this is a btree support function; this is one of the few places where
    1153                 :             :      * memory needs to be explicitly freed.
    1154                 :             :      */
    1155         [ +  + ]:       43142 :     PG_FREE_IF_COPY(hs1, 0);
    1156         [ +  + ]:       43142 :     PG_FREE_IF_COPY(hs2, 1);
    1157                 :       43142 :     PG_RETURN_INT32(res);
    1158                 :             : }
    1159                 :             : 
    1160                 :             : 
    1161                 :           8 : PG_FUNCTION_INFO_V1(hstore_eq);
    1162                 :             : Datum
    1163                 :        4121 : hstore_eq(PG_FUNCTION_ARGS)
    1164                 :             : {
    1165                 :        4121 :     int         res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
    1166                 :             :                                                         PG_GETARG_DATUM(0),
    1167                 :             :                                                         PG_GETARG_DATUM(1)));
    1168                 :             : 
    1169                 :        4121 :     PG_RETURN_BOOL(res == 0);
    1170                 :             : }
    1171                 :             : 
    1172                 :           7 : PG_FUNCTION_INFO_V1(hstore_ne);
    1173                 :             : Datum
    1174                 :           0 : hstore_ne(PG_FUNCTION_ARGS)
    1175                 :             : {
    1176                 :           0 :     int         res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
    1177                 :             :                                                         PG_GETARG_DATUM(0),
    1178                 :             :                                                         PG_GETARG_DATUM(1)));
    1179                 :             : 
    1180                 :           0 :     PG_RETURN_BOOL(res != 0);
    1181                 :             : }
    1182                 :             : 
    1183                 :           8 : PG_FUNCTION_INFO_V1(hstore_gt);
    1184                 :             : Datum
    1185                 :           8 : hstore_gt(PG_FUNCTION_ARGS)
    1186                 :             : {
    1187                 :           8 :     int         res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
    1188                 :             :                                                         PG_GETARG_DATUM(0),
    1189                 :             :                                                         PG_GETARG_DATUM(1)));
    1190                 :             : 
    1191                 :           8 :     PG_RETURN_BOOL(res > 0);
    1192                 :             : }
    1193                 :             : 
    1194                 :           7 : PG_FUNCTION_INFO_V1(hstore_ge);
    1195                 :             : Datum
    1196                 :           0 : hstore_ge(PG_FUNCTION_ARGS)
    1197                 :             : {
    1198                 :           0 :     int         res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
    1199                 :             :                                                         PG_GETARG_DATUM(0),
    1200                 :             :                                                         PG_GETARG_DATUM(1)));
    1201                 :             : 
    1202                 :           0 :     PG_RETURN_BOOL(res >= 0);
    1203                 :             : }
    1204                 :             : 
    1205                 :           7 : PG_FUNCTION_INFO_V1(hstore_lt);
    1206                 :             : Datum
    1207                 :           0 : hstore_lt(PG_FUNCTION_ARGS)
    1208                 :             : {
    1209                 :           0 :     int         res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
    1210                 :             :                                                         PG_GETARG_DATUM(0),
    1211                 :             :                                                         PG_GETARG_DATUM(1)));
    1212                 :             : 
    1213                 :           0 :     PG_RETURN_BOOL(res < 0);
    1214                 :             : }
    1215                 :             : 
    1216                 :           7 : PG_FUNCTION_INFO_V1(hstore_le);
    1217                 :             : Datum
    1218                 :           0 : hstore_le(PG_FUNCTION_ARGS)
    1219                 :             : {
    1220                 :           0 :     int         res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
    1221                 :             :                                                         PG_GETARG_DATUM(0),
    1222                 :             :                                                         PG_GETARG_DATUM(1)));
    1223                 :             : 
    1224                 :           0 :     PG_RETURN_BOOL(res <= 0);
    1225                 :             : }
    1226                 :             : 
    1227                 :             : 
    1228                 :           8 : PG_FUNCTION_INFO_V1(hstore_hash);
    1229                 :             : Datum
    1230                 :        2014 : hstore_hash(PG_FUNCTION_ARGS)
    1231                 :             : {
    1232                 :        2014 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
    1233                 :        2014 :     Datum       hval = hash_any((unsigned char *) VARDATA(hs),
    1234                 :        2014 :                                 VARSIZE(hs) - VARHDRSZ);
    1235                 :             : 
    1236                 :             :     /*
    1237                 :             :      * This (along with hstore_hash_extended) is the only place in the code
    1238                 :             :      * that cares whether the overall varlena size exactly matches the true
    1239                 :             :      * data size; this assertion should be maintained by all the other code,
    1240                 :             :      * but we make it explicit here.
    1241                 :             :      */
    1242                 :             :     Assert(VARSIZE(hs) ==
    1243                 :             :            (HS_COUNT(hs) != 0 ?
    1244                 :             :             CALCDATASIZE(HS_COUNT(hs),
    1245                 :             :                          HSE_ENDPOS(ARRPTR(hs)[2 * HS_COUNT(hs) - 1])) :
    1246                 :             :             HSHRDSIZE));
    1247                 :             : 
    1248         [ +  + ]:        2014 :     PG_FREE_IF_COPY(hs, 0);
    1249                 :        2014 :     PG_RETURN_DATUM(hval);
    1250                 :             : }
    1251                 :             : 
    1252                 :           8 : PG_FUNCTION_INFO_V1(hstore_hash_extended);
    1253                 :             : Datum
    1254                 :          10 : hstore_hash_extended(PG_FUNCTION_ARGS)
    1255                 :             : {
    1256                 :          10 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
    1257                 :          10 :     uint64      seed = PG_GETARG_INT64(1);
    1258                 :             :     Datum       hval;
    1259                 :             : 
    1260                 :          10 :     hval = hash_any_extended((unsigned char *) VARDATA(hs),
    1261                 :          10 :                              VARSIZE(hs) - VARHDRSZ,
    1262                 :             :                              seed);
    1263                 :             : 
    1264                 :             :     /* See comment in hstore_hash */
    1265                 :             :     Assert(VARSIZE(hs) ==
    1266                 :             :            (HS_COUNT(hs) != 0 ?
    1267                 :             :             CALCDATASIZE(HS_COUNT(hs),
    1268                 :             :                          HSE_ENDPOS(ARRPTR(hs)[2 * HS_COUNT(hs) - 1])) :
    1269                 :             :             HSHRDSIZE));
    1270                 :             : 
    1271         [ -  + ]:          10 :     PG_FREE_IF_COPY(hs, 0);
    1272                 :          10 :     PG_RETURN_DATUM(hval);
    1273                 :             : }
        

Generated by: LCOV version 2.0-1