LCOV - differential code coverage report
Current view: top level - contrib/hstore - hstore_op.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 91.5 % 574 525 8 24 17 11 259 4 251 20 263 1 3
Current Date: 2023-04-08 15:15:32 Functions: 66.3 % 86 57 5 24 55 1 1 5 55
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  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 UBC           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 CBC        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 GNC        2842 :     deconstruct_array_builtin(a, TEXTOID, &key_datums, &key_nulls, &key_count);
      84                 : 
      85 CBC        2842 :     if (key_count == 0)
      86 ECB             :     {
      87 GIC           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 ECB             :      * on palloc() to complain.
      97 EUB             :      */
      98 GIC        2837 :     if (key_count > MaxAllocSize / sizeof(Pairs))
      99 UIC           0 :         ereport(ERROR,
     100                 :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     101                 :                  errmsg("number of pairs (%d) exceeds the maximum allowed (%d)",
     102 ECB             :                         key_count, (int) (MaxAllocSize / sizeof(Pairs)))));
     103                 : 
     104 CBC        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 ECB             :         {
     110 CBC        5679 :             key_pairs[j].key = VARDATA(key_datums[i]);
     111            5679 :             key_pairs[j].keylen = VARSIZE(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 GIC        5679 :             key_pairs[j].isnull = 1;
     116            5679 :             j++;
     117                 :         }
     118 ECB             :     }
     119                 : 
     120 CBC        2837 :     *npairs = hstoreUniquePairs(key_pairs, j, &bufsiz);
     121                 : 
     122 GIC        2837 :     return key_pairs;
     123                 : }
     124 ECB             : 
     125                 : 
     126 CBC           8 : PG_FUNCTION_INFO_V1(hstore_fetchval);
     127                 : Datum
     128               6 : hstore_fetchval(PG_FUNCTION_ARGS)
     129 ECB             : {
     130 CBC           6 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     131 GIC           6 :     text       *key = PG_GETARG_TEXT_PP(1);
     132 CBC           6 :     HEntry     *entries = ARRPTR(hs);
     133 ECB             :     text       *out;
     134 GIC          12 :     int         idx = hstoreFindKey(hs, NULL,
     135 CBC          12 :                                     VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
     136 ECB             : 
     137 GIC           6 :     if (idx < 0 || HSTORE_VALISNULL(entries, idx))
     138 CBC           2 :         PG_RETURN_NULL();
     139 ECB             : 
     140 GIC           4 :     out = cstring_to_text_with_len(HSTORE_VAL(entries, STRPTR(hs), idx),
     141 CBC           4 :                                    HSTORE_VALLEN(entries, idx));
     142                 : 
     143 GIC           4 :     PG_RETURN_TEXT_P(out);
     144                 : }
     145 ECB             : 
     146                 : 
     147 CBC          16 : PG_FUNCTION_INFO_V1(hstore_exists);
     148                 : Datum
     149            1440 : hstore_exists(PG_FUNCTION_ARGS)
     150 ECB             : {
     151 CBC        1440 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     152            1440 :     text       *key = PG_GETARG_TEXT_PP(1);
     153 GIC        2880 :     int         idx = hstoreFindKey(hs, NULL,
     154 CBC        2880 :                                     VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
     155                 : 
     156 GIC        1440 :     PG_RETURN_BOOL(idx >= 0);
     157                 : }
     158 ECB             : 
     159                 : 
     160 CBC           8 : PG_FUNCTION_INFO_V1(hstore_exists_any);
     161                 : Datum
     162            1727 : hstore_exists_any(PG_FUNCTION_ARGS)
     163 ECB             : {
     164 GIC        1727 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     165 CBC        1727 :     ArrayType  *keys = PG_GETARG_ARRAYTYPE_P(1);
     166                 :     int         nkeys;
     167            1727 :     Pairs      *key_pairs = hstoreArrayToPairs(keys, &nkeys);
     168 ECB             :     int         i;
     169 GIC        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 ECB             :      * of the last search.
     177                 :      */
     178 CBC        3580 :     for (i = 0; i < nkeys; i++)
     179 ECB             :     {
     180 GIC        2867 :         int         idx = hstoreFindKey(hs, &lowbound,
     181 CBC        2867 :                                         key_pairs[i].key, key_pairs[i].keylen);
     182                 : 
     183            2867 :         if (idx >= 0)
     184 ECB             :         {
     185 GIC        1014 :             res = true;
     186            1014 :             break;
     187                 :         }
     188 ECB             :     }
     189                 : 
     190 GIC        1727 :     PG_RETURN_BOOL(res);
     191                 : }
     192 ECB             : 
     193                 : 
     194 CBC           8 : PG_FUNCTION_INFO_V1(hstore_exists_all);
     195                 : Datum
     196            1097 : hstore_exists_all(PG_FUNCTION_ARGS)
     197 ECB             : {
     198 GIC        1097 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     199 CBC        1097 :     ArrayType  *keys = PG_GETARG_ARRAYTYPE_P(1);
     200                 :     int         nkeys;
     201            1097 :     Pairs      *key_pairs = hstoreArrayToPairs(keys, &nkeys);
     202 ECB             :     int         i;
     203 GIC        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 ECB             :      * of the last search.
     211                 :      */
     212 CBC        1507 :     for (i = 0; i < nkeys; i++)
     213 ECB             :     {
     214 GIC        1378 :         int         idx = hstoreFindKey(hs, &lowbound,
     215 CBC        1378 :                                         key_pairs[i].key, key_pairs[i].keylen);
     216                 : 
     217            1378 :         if (idx < 0)
     218 ECB             :         {
     219 GIC         968 :             res = false;
     220             968 :             break;
     221                 :         }
     222 ECB             :     }
     223                 : 
     224 GIC        1097 :     PG_RETURN_BOOL(res);
     225                 : }
     226 ECB             : 
     227                 : 
     228 CBC          15 : PG_FUNCTION_INFO_V1(hstore_defined);
     229                 : Datum
     230               4 : hstore_defined(PG_FUNCTION_ARGS)
     231 ECB             : {
     232 CBC           4 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     233               4 :     text       *key = PG_GETARG_TEXT_PP(1);
     234               4 :     HEntry     *entries = ARRPTR(hs);
     235               8 :     int         idx = hstoreFindKey(hs, NULL,
     236 GIC           8 :                                     VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
     237 CBC           4 :     bool        res = (idx >= 0 && !HSTORE_VALISNULL(entries, idx));
     238                 : 
     239 GIC           4 :     PG_RETURN_BOOL(res);
     240                 : }
     241 ECB             : 
     242                 : 
     243 CBC           8 : PG_FUNCTION_INFO_V1(hstore_delete);
     244                 : Datum
     245              11 : hstore_delete(PG_FUNCTION_ARGS)
     246 ECB             : {
     247 CBC          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 GIC          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 ECB             :                *ed;
     257                 :     int         i;
     258 GIC          11 :     int         count = HS_COUNT(hs);
     259 CBC          11 :     int         outcount = 0;
     260 ECB             : 
     261 GIC          11 :     SET_VARSIZE(out, VARSIZE(hs));
     262 CBC          11 :     HS_SETCOUNT(out, count);    /* temporary! */
     263 ECB             : 
     264 CBC          11 :     bufs = STRPTR(hs);
     265              11 :     es = ARRPTR(hs);
     266 GIC          11 :     bufd = ptrd = STRPTR(out);
     267 CBC          11 :     ed = ARRPTR(out);
     268                 : 
     269              44 :     for (i = 0; i < count; ++i)
     270 ECB             :     {
     271 GIC          33 :         int         len = HSTORE_KEYLEN(es, i);
     272 CBC          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 GIC          24 :             ++outcount;
     281                 :         }
     282 ECB             :     }
     283                 : 
     284 CBC          11 :     HS_FINALIZE(out, outcount, bufd, ptrd);
     285                 : 
     286 GIC          11 :     PG_RETURN_POINTER(out);
     287                 : }
     288 ECB             : 
     289                 : 
     290 CBC           8 : PG_FUNCTION_INFO_V1(hstore_delete_array);
     291                 : Datum
     292              12 : hstore_delete_array(PG_FUNCTION_ARGS)
     293 ECB             : {
     294 CBC          12 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     295 GIC          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 ECB             :     int         i,
     303                 :                 j;
     304 GIC          12 :     int         outcount = 0;
     305 CBC          12 :     ArrayType  *key_array = PG_GETARG_ARRAYTYPE_P(1);
     306                 :     int         nkeys;
     307              12 :     Pairs      *key_pairs = hstoreArrayToPairs(key_array, &nkeys);
     308 ECB             : 
     309 GIC          12 :     SET_VARSIZE(out, VARSIZE(hs));
     310 CBC          12 :     HS_SETCOUNT(out, hs_count); /* temporary! */
     311 ECB             : 
     312 CBC          12 :     ps = STRPTR(hs);
     313              12 :     es = ARRPTR(hs);
     314 GIC          12 :     bufd = pd = STRPTR(out);
     315 CBC          12 :     ed = ARRPTR(out);
     316                 : 
     317 GIC          12 :     if (nkeys == 0)
     318 ECB             :     {
     319                 :         /* return a copy of the input, unchanged */
     320 CBC           3 :         memcpy(out, hs, VARSIZE(hs));
     321               3 :         HS_FIXSIZE(out, hs_count);
     322 GIC           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 ECB             :      */
     330                 : 
     331 GIC          36 :     for (i = j = 0; i < hs_count;)
     332                 :     {
     333 ECB             :         int         difference;
     334 EUB             : 
     335 GIC          27 :         if (j >= nkeys)
     336 UIC           0 :             difference = -1;
     337 ECB             :         else
     338                 :         {
     339 CBC          27 :             int         skeylen = HSTORE_KEYLEN(es, i);
     340 ECB             : 
     341 CBC          27 :             if (skeylen == key_pairs[j].keylen)
     342              27 :                 difference = memcmp(HSTORE_KEY(es, ps, i),
     343 GIC          27 :                                     key_pairs[j].key,
     344 GBC          27 :                                     key_pairs[j].keylen);
     345                 :             else
     346 UIC           0 :                 difference = (skeylen > key_pairs[j].keylen) ? 1 : -1;
     347 ECB             :         }
     348 EUB             : 
     349 CBC          27 :         if (difference > 0)
     350 LBC           0 :             ++j;
     351 GIC          27 :         else if (difference == 0)
     352              14 :             ++i, ++j;
     353 ECB             :         else
     354                 :         {
     355 GIC          13 :             HS_COPYITEM(ed, bufd, pd,
     356 ECB             :                         HSTORE_KEY(es, ps, i), HSTORE_KEYLEN(es, i),
     357                 :                         HSTORE_VALLEN(es, i), HSTORE_VALISNULL(es, i));
     358 GIC          13 :             ++outcount;
     359              13 :             ++i;
     360                 :         }
     361 ECB             :     }
     362                 : 
     363 CBC           9 :     HS_FINALIZE(out, outcount, bufd, pd);
     364                 : 
     365 GIC           9 :     PG_RETURN_POINTER(out);
     366                 : }
     367 ECB             : 
     368                 : 
     369 CBC           8 : PG_FUNCTION_INFO_V1(hstore_delete_hstore);
     370                 : Datum
     371              12 : hstore_delete_hstore(PG_FUNCTION_ARGS)
     372 ECB             : {
     373 CBC          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 GIC          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 ECB             :     int         i,
     386                 :                 j;
     387 CBC          12 :     int         outcount = 0;
     388 ECB             : 
     389 GIC          12 :     SET_VARSIZE(out, VARSIZE(hs));
     390 CBC          12 :     HS_SETCOUNT(out, hs_count); /* temporary! */
     391 ECB             : 
     392 CBC          12 :     ps = STRPTR(hs);
     393              12 :     es = ARRPTR(hs);
     394              12 :     ps2 = STRPTR(hs2);
     395              12 :     es2 = ARRPTR(hs2);
     396 GIC          12 :     bufd = pd = STRPTR(out);
     397 CBC          12 :     ed = ARRPTR(out);
     398                 : 
     399 GIC          12 :     if (hs2_count == 0)
     400 ECB             :     {
     401                 :         /* return a copy of the input, unchanged */
     402 CBC           3 :         memcpy(out, hs, VARSIZE(hs));
     403               3 :         HS_FIXSIZE(out, hs_count);
     404 GIC           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 ECB             :      */
     413                 : 
     414 GIC          36 :     for (i = j = 0; i < hs_count;)
     415                 :     {
     416 ECB             :         int         difference;
     417                 : 
     418 GIC          27 :         if (j >= hs2_count)
     419               5 :             difference = -1;
     420 ECB             :         else
     421                 :         {
     422 GIC          22 :             int         skeylen = HSTORE_KEYLEN(es, i);
     423 CBC          22 :             int         s2keylen = HSTORE_KEYLEN(es2, j);
     424 ECB             : 
     425 CBC          22 :             if (skeylen == s2keylen)
     426 GIC          20 :                 difference = memcmp(HSTORE_KEY(es, ps, i),
     427              20 :                                     HSTORE_KEY(es2, ps2, j),
     428 ECB             :                                     skeylen);
     429                 :             else
     430 GIC           2 :                 difference = (skeylen > s2keylen) ? 1 : -1;
     431 ECB             :         }
     432 EUB             : 
     433 CBC          27 :         if (difference > 0)
     434 UIC           0 :             ++j;
     435 CBC          27 :         else if (difference == 0)
     436 ECB             :         {
     437 GIC          17 :             int         svallen = HSTORE_VALLEN(es, i);
     438 CBC          17 :             int         snullval = HSTORE_VALISNULL(es, i);
     439 ECB             : 
     440 CBC          17 :             if (snullval != HSTORE_VALISNULL(es2, j) ||
     441              15 :                 (!snullval && (svallen != HSTORE_VALLEN(es2, j) ||
     442 GIC          15 :                                memcmp(HSTORE_VAL(es, ps, i),
     443              15 :                                       HSTORE_VAL(es2, ps2, j),
     444 ECB             :                                       svallen) != 0)))
     445                 :             {
     446 GIC           4 :                 HS_COPYITEM(ed, bufd, pd,
     447 ECB             :                             HSTORE_KEY(es, ps, i), HSTORE_KEYLEN(es, i),
     448                 :                             svallen, snullval);
     449 CBC           4 :                 ++outcount;
     450                 :             }
     451 GIC          17 :             ++i, ++j;
     452                 :         }
     453 ECB             :         else
     454                 :         {
     455 GIC          10 :             HS_COPYITEM(ed, bufd, pd,
     456 ECB             :                         HSTORE_KEY(es, ps, i), HSTORE_KEYLEN(es, i),
     457                 :                         HSTORE_VALLEN(es, i), HSTORE_VALISNULL(es, i));
     458 GIC          10 :             ++outcount;
     459              10 :             ++i;
     460                 :         }
     461 ECB             :     }
     462                 : 
     463 CBC           9 :     HS_FINALIZE(out, outcount, bufd, pd);
     464                 : 
     465 GIC           9 :     PG_RETURN_POINTER(out);
     466                 : }
     467 ECB             : 
     468                 : 
     469 CBC           8 : PG_FUNCTION_INFO_V1(hstore_concat);
     470                 : Datum
     471              30 : hstore_concat(PG_FUNCTION_ARGS)
     472 ECB             : {
     473 CBC          30 :     HStore     *s1 = PG_GETARG_HSTORE_P(0);
     474 GIC          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 ECB             :     int         s1idx;
     484                 :     int         s2idx;
     485 CBC          30 :     int         s1count = HS_COUNT(s1);
     486 GIC          30 :     int         s2count = HS_COUNT(s2);
     487 CBC          30 :     int         outcount = 0;
     488 ECB             : 
     489 GIC          30 :     SET_VARSIZE(out, VARSIZE(s1) + VARSIZE(s2) - HSHRDSIZE);
     490 CBC          30 :     HS_SETCOUNT(out, s1count + s2count);
     491                 : 
     492 GIC          30 :     if (s1count == 0)
     493 ECB             :     {
     494                 :         /* return a copy of the input, unchanged */
     495 CBC           4 :         memcpy(out, s2, VARSIZE(s2));
     496               4 :         HS_FIXSIZE(out, s2count);
     497 GIC           4 :         HS_SETCOUNT(out, s2count);
     498               4 :         PG_RETURN_POINTER(out);
     499 ECB             :     }
     500                 : 
     501 GIC          26 :     if (s2count == 0)
     502 ECB             :     {
     503                 :         /* return a copy of the input, unchanged */
     504 CBC           2 :         memcpy(out, s1, VARSIZE(s1));
     505               2 :         HS_FIXSIZE(out, s1count);
     506 GIC           2 :         HS_SETCOUNT(out, s1count);
     507               2 :         PG_RETURN_POINTER(out);
     508 ECB             :     }
     509                 : 
     510 CBC          24 :     ps1 = STRPTR(s1);
     511              24 :     ps2 = STRPTR(s2);
     512              24 :     bufd = pd = STRPTR(out);
     513              24 :     es1 = ARRPTR(s1);
     514 GIC          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 ECB             :      */
     521                 : 
     522 GIC          90 :     for (s1idx = s2idx = 0; s1idx < s1count || s2idx < s2count; ++outcount)
     523                 :     {
     524 ECB             :         int         difference;
     525                 : 
     526 CBC          66 :         if (s1idx >= s1count)
     527              13 :             difference = 1;
     528 GIC          53 :         else if (s2idx >= s2count)
     529               7 :             difference = -1;
     530 ECB             :         else
     531                 :         {
     532 GIC          46 :             int         s1keylen = HSTORE_KEYLEN(es1, s1idx);
     533 CBC          46 :             int         s2keylen = HSTORE_KEYLEN(es2, s2idx);
     534 ECB             : 
     535 CBC          46 :             if (s1keylen == s2keylen)
     536 GIC          41 :                 difference = memcmp(HSTORE_KEY(es1, ps1, s1idx),
     537              41 :                                     HSTORE_KEY(es2, ps2, s2idx),
     538 ECB             :                                     s1keylen);
     539                 :             else
     540 GIC           5 :                 difference = (s1keylen > s2keylen) ? 1 : -1;
     541 ECB             :         }
     542                 : 
     543 CBC          66 :         if (difference >= 0)
     544                 :         {
     545 GIC          38 :             HS_COPYITEM(ed, bufd, pd,
     546 ECB             :                         HSTORE_KEY(es2, ps2, s2idx), HSTORE_KEYLEN(es2, s2idx),
     547                 :                         HSTORE_VALLEN(es2, s2idx), HSTORE_VALISNULL(es2, s2idx));
     548 CBC          38 :             ++s2idx;
     549 GIC          38 :             if (difference == 0)
     550              19 :                 ++s1idx;
     551                 :         }
     552 ECB             :         else
     553                 :         {
     554 GIC          28 :             HS_COPYITEM(ed, bufd, pd,
     555 ECB             :                         HSTORE_KEY(es1, ps1, s1idx), HSTORE_KEYLEN(es1, s1idx),
     556                 :                         HSTORE_VALLEN(es1, s1idx), HSTORE_VALISNULL(es1, s1idx));
     557 GIC          28 :             ++s1idx;
     558                 :         }
     559 ECB             :     }
     560                 : 
     561 CBC          24 :     HS_FINALIZE(out, outcount, bufd, pd);
     562                 : 
     563 GIC          24 :     PG_RETURN_POINTER(out);
     564                 : }
     565 ECB             : 
     566                 : 
     567 CBC           8 : PG_FUNCTION_INFO_V1(hstore_slice_to_array);
     568                 : Datum
     569               4 : hstore_slice_to_array(PG_FUNCTION_ARGS)
     570 ECB             : {
     571 CBC           4 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     572               4 :     HEntry     *entries = ARRPTR(hs);
     573 GIC           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 ECB             :     int         i;
     582                 : 
     583 GNC           4 :     deconstruct_array_builtin(key_array, TEXTOID, &key_datums, &key_nulls, &key_count);
     584 EUB             : 
     585 GIC           4 :     if (key_count == 0)
     586                 :     {
     587 LBC           0 :         aout = construct_empty_array(TEXTOID);
     588               0 :         PG_RETURN_POINTER(aout);
     589                 :     }
     590 ECB             : 
     591 GIC           4 :     out_datums = palloc(sizeof(Datum) * key_count);
     592 CBC           4 :     out_nulls = palloc(sizeof(bool) * key_count);
     593                 : 
     594 GIC          15 :     for (i = 0; i < key_count; ++i)
     595 ECB             :     {
     596 CBC          11 :         text       *key = (text *) DatumGetPointer(key_datums[i]);
     597                 :         int         idx;
     598 ECB             : 
     599 GIC          11 :         if (key_nulls[i])
     600 CBC           1 :             idx = -1;
     601                 :         else
     602              10 :             idx = hstoreFindKey(hs, NULL, VARDATA(key), VARSIZE(key) - VARHDRSZ);
     603 ECB             : 
     604 GIC          11 :         if (idx < 0 || HSTORE_VALISNULL(entries, idx))
     605                 :         {
     606               2 :             out_nulls[i] = true;
     607 CBC           2 :             out_datums[i] = (Datum) 0;
     608 ECB             :         }
     609                 :         else
     610                 :         {
     611 GIC          18 :             out_datums[i] =
     612               9 :                 PointerGetDatum(cstring_to_text_with_len(HSTORE_VAL(entries, ptr, idx),
     613               9 :                                                          HSTORE_VALLEN(entries, idx)));
     614 CBC           9 :             out_nulls[i] = false;
     615                 :         }
     616                 :     }
     617 ECB             : 
     618 GIC           4 :     aout = construct_md_array(out_datums, out_nulls,
     619                 :                               ARR_NDIM(key_array),
     620 ECB             :                               ARR_DIMS(key_array),
     621 GIC           4 :                               ARR_LBOUND(key_array),
     622                 :                               TEXTOID, -1, false, TYPALIGN_INT);
     623                 : 
     624 CBC           4 :     PG_RETURN_POINTER(aout);
     625                 : }
     626 ECB             : 
     627                 : 
     628 CBC           8 : PG_FUNCTION_INFO_V1(hstore_slice_to_hstore);
     629 ECB             : Datum
     630 CBC           6 : hstore_slice_to_hstore(PG_FUNCTION_ARGS)
     631 ECB             : {
     632 GIC           6 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     633               6 :     HEntry     *entries = ARRPTR(hs);
     634 CBC           6 :     char       *ptr = STRPTR(hs);
     635 GIC           6 :     ArrayType  *key_array = PG_GETARG_ARRAYTYPE_P(1);
     636                 :     HStore     *out;
     637 ECB             :     int         nkeys;
     638 GIC           6 :     Pairs      *key_pairs = hstoreArrayToPairs(key_array, &nkeys);
     639 ECB             :     Pairs      *out_pairs;
     640                 :     int         bufsiz;
     641 CBC           6 :     int         lastidx = 0;
     642                 :     int         i;
     643 GBC           6 :     int         out_count = 0;
     644 EUB             : 
     645 GIC           6 :     if (nkeys == 0)
     646                 :     {
     647 UIC           0 :         out = hstorePairs(NULL, 0, 0);
     648 LBC           0 :         PG_RETURN_POINTER(out);
     649 ECB             :     }
     650                 : 
     651                 :     /* hstoreArrayToPairs() checked overflow */
     652 GIC           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 ECB             :      * start one entry past the previous "found" entry, or at the lower bound
     659                 :      * of the last search.
     660                 :      */
     661                 : 
     662 GIC          21 :     for (i = 0; i < nkeys; ++i)
     663 ECB             :     {
     664 GIC          15 :         int         idx = hstoreFindKey(hs, &lastidx,
     665 CBC          15 :                                         key_pairs[i].key, key_pairs[i].keylen);
     666 ECB             : 
     667 CBC          15 :         if (idx >= 0)
     668 ECB             :         {
     669 CBC          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 GIC          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 ECB             :      * we don't use hstoreUniquePairs here because we know that the pairs list
     681                 :      * is already sorted and uniq'ed.
     682                 :      */
     683                 : 
     684 GIC           6 :     out = hstorePairs(out_pairs, out_count, bufsiz);
     685                 : 
     686 CBC           6 :     PG_RETURN_POINTER(out);
     687                 : }
     688 ECB             : 
     689                 : 
     690 CBC           8 : PG_FUNCTION_INFO_V1(hstore_akeys);
     691                 : Datum
     692 GIC           3 : hstore_akeys(PG_FUNCTION_ARGS)
     693 ECB             : {
     694 CBC           3 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     695 ECB             :     Datum      *d;
     696                 :     ArrayType  *a;
     697 GIC           3 :     HEntry     *entries = ARRPTR(hs);
     698 CBC           3 :     char       *base = STRPTR(hs);
     699 GIC           3 :     int         count = HS_COUNT(hs);
     700 ECB             :     int         i;
     701                 : 
     702 GIC           3 :     if (count == 0)
     703                 :     {
     704 CBC           1 :         a = construct_empty_array(TEXTOID);
     705 GIC           1 :         PG_RETURN_POINTER(a);
     706 ECB             :     }
     707                 : 
     708 CBC           2 :     d = (Datum *) palloc(sizeof(Datum) * count);
     709 ECB             : 
     710 GIC           7 :     for (i = 0; i < count; ++i)
     711 ECB             :     {
     712 GIC           5 :         text       *t = cstring_to_text_with_len(HSTORE_KEY(entries, base, i),
     713               5 :                                                  HSTORE_KEYLEN(entries, i));
     714 ECB             : 
     715 GIC           5 :         d[i] = PointerGetDatum(t);
     716 ECB             :     }
     717                 : 
     718 GNC           2 :     a = construct_array_builtin(d, count, TEXTOID);
     719 ECB             : 
     720 GIC           2 :     PG_RETURN_POINTER(a);
     721 ECB             : }
     722                 : 
     723                 : 
     724 GIC           8 : PG_FUNCTION_INFO_V1(hstore_avals);
     725                 : Datum
     726               4 : hstore_avals(PG_FUNCTION_ARGS)
     727 ECB             : {
     728 CBC           4 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     729 ECB             :     Datum      *d;
     730                 :     bool       *nulls;
     731                 :     ArrayType  *a;
     732 GIC           4 :     HEntry     *entries = ARRPTR(hs);
     733 CBC           4 :     char       *base = STRPTR(hs);
     734 GIC           4 :     int         count = HS_COUNT(hs);
     735 CBC           4 :     int         lb = 1;
     736 ECB             :     int         i;
     737                 : 
     738 GIC           4 :     if (count == 0)
     739 ECB             :     {
     740 CBC           1 :         a = construct_empty_array(TEXTOID);
     741 GIC           1 :         PG_RETURN_POINTER(a);
     742 ECB             :     }
     743                 : 
     744 CBC           3 :     d = (Datum *) palloc(sizeof(Datum) * count);
     745 GIC           3 :     nulls = (bool *) palloc(sizeof(bool) * count);
     746 ECB             : 
     747 CBC          12 :     for (i = 0; i < count; ++i)
     748                 :     {
     749 GIC           9 :         if (HSTORE_VALISNULL(entries, i))
     750                 :         {
     751 CBC           1 :             d[i] = (Datum) 0;
     752               1 :             nulls[i] = true;
     753                 :         }
     754 ECB             :         else
     755                 :         {
     756 GIC           8 :             text       *item = cstring_to_text_with_len(HSTORE_VAL(entries, base, i),
     757               8 :                                                         HSTORE_VALLEN(entries, i));
     758                 : 
     759 CBC           8 :             d[i] = PointerGetDatum(item);
     760 GIC           8 :             nulls[i] = false;
     761                 :         }
     762 ECB             :     }
     763                 : 
     764 GIC           3 :     a = construct_md_array(d, nulls, 1, &count, &lb,
     765                 :                            TEXTOID, -1, false, TYPALIGN_INT);
     766                 : 
     767 CBC           3 :     PG_RETURN_POINTER(a);
     768                 : }
     769 ECB             : 
     770                 : 
     771                 : static ArrayType *
     772 CBC           4 : hstore_to_array_internal(HStore *hs, int ndims)
     773 ECB             : {
     774 GIC           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 CBC           4 :     int         lb[2] = {1, 1};
     779                 :     Datum      *out_datums;
     780 ECB             :     bool       *out_nulls;
     781 EUB             :     int         i;
     782                 : 
     783 CBC           4 :     Assert(ndims < 3);
     784 ECB             : 
     785 CBC           4 :     if (count == 0 || ndims == 0)
     786 UIC           0 :         return construct_empty_array(TEXTOID);
     787 ECB             : 
     788 GIC           4 :     out_size[0] = count * 2 / ndims;
     789 CBC           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 ECB             :     {
     794 GIC          16 :         text       *key = cstring_to_text_with_len(HSTORE_KEY(entries, base, i),
     795 CBC          16 :                                                    HSTORE_KEYLEN(entries, i));
     796                 : 
     797              16 :         out_datums[i * 2] = PointerGetDatum(key);
     798              16 :         out_nulls[i * 2] = false;
     799                 : 
     800 GIC          16 :         if (HSTORE_VALISNULL(entries, i))
     801                 :         {
     802 CBC           4 :             out_datums[i * 2 + 1] = (Datum) 0;
     803               4 :             out_nulls[i * 2 + 1] = true;
     804                 :         }
     805 ECB             :         else
     806                 :         {
     807 GIC          12 :             text       *item = cstring_to_text_with_len(HSTORE_VAL(entries, base, i),
     808              12 :                                                         HSTORE_VALLEN(entries, i));
     809                 : 
     810 CBC          12 :             out_datums[i * 2 + 1] = PointerGetDatum(item);
     811 GIC          12 :             out_nulls[i * 2 + 1] = false;
     812                 :         }
     813                 :     }
     814                 : 
     815 CBC           4 :     return construct_md_array(out_datums, out_nulls,
     816                 :                               ndims, out_size, lb,
     817 ECB             :                               TEXTOID, -1, false, TYPALIGN_INT);
     818                 : }
     819                 : 
     820 CBC           8 : PG_FUNCTION_INFO_V1(hstore_to_array);
     821                 : Datum
     822               2 : hstore_to_array(PG_FUNCTION_ARGS)
     823                 : {
     824 GIC           2 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     825 CBC           2 :     ArrayType  *out = hstore_to_array_internal(hs, 1);
     826                 : 
     827               2 :     PG_RETURN_POINTER(out);
     828                 : }
     829 ECB             : 
     830 CBC           8 : PG_FUNCTION_INFO_V1(hstore_to_matrix);
     831                 : Datum
     832               2 : hstore_to_matrix(PG_FUNCTION_ARGS)
     833                 : {
     834 GIC           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 ECB             :  * 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 GIC        2010 : setup_firstcall(FuncCallContext *funcctx, HStore *hs,
     851 ECB             :                 FunctionCallInfo fcinfo)
     852                 : {
     853                 :     MemoryContext oldcontext;
     854                 :     HStore     *st;
     855                 : 
     856 CBC        2010 :     oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
     857                 : 
     858            2010 :     st = (HStore *) palloc(VARSIZE(hs));
     859 GIC        2010 :     memcpy(st, hs, VARSIZE(hs));
     860                 : 
     861            2010 :     funcctx->user_fctx = (void *) st;
     862                 : 
     863 CBC        2010 :     if (fcinfo)
     864 EUB             :     {
     865                 :         TupleDesc   tupdesc;
     866 ECB             : 
     867                 :         /* Build a tuple descriptor for our result type */
     868 GIC        2003 :         if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
     869 LBC           0 :             elog(ERROR, "return type must be a row type");
     870 ECB             : 
     871 GIC        2003 :         funcctx->tuple_desc = BlessTupleDesc(tupdesc);
     872                 :     }
     873 ECB             : 
     874 GIC        2010 :     MemoryContextSwitchTo(oldcontext);
     875 CBC        2010 : }
     876                 : 
     877                 : 
     878 GIC           8 : PG_FUNCTION_INFO_V1(hstore_skeys);
     879                 : Datum
     880               8 : hstore_skeys(PG_FUNCTION_ARGS)
     881 ECB             : {
     882                 :     FuncCallContext *funcctx;
     883                 :     HStore     *hs;
     884                 :     int         i;
     885                 : 
     886 GIC           8 :     if (SRF_IS_FIRSTCALL())
     887                 :     {
     888 CBC           3 :         hs = PG_GETARG_HSTORE_P(0);
     889               3 :         funcctx = SRF_FIRSTCALL_INIT();
     890               3 :         setup_firstcall(funcctx, hs, NULL);
     891                 :     }
     892 ECB             : 
     893 GIC           8 :     funcctx = SRF_PERCALL_SETUP();
     894 CBC           8 :     hs = (HStore *) funcctx->user_fctx;
     895 GIC           8 :     i = funcctx->call_cntr;
     896                 : 
     897 CBC           8 :     if (i < HS_COUNT(hs))
     898 ECB             :     {
     899 GIC           5 :         HEntry     *entries = ARRPTR(hs);
     900 ECB             :         text       *item;
     901                 : 
     902 GIC           5 :         item = cstring_to_text_with_len(HSTORE_KEY(entries, STRPTR(hs), i),
     903 CBC           5 :                                         HSTORE_KEYLEN(entries, i));
     904                 : 
     905 GIC           5 :         SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
     906                 :     }
     907 ECB             : 
     908 GIC           3 :     SRF_RETURN_DONE(funcctx);
     909 ECB             : }
     910                 : 
     911                 : 
     912 GIC           8 : PG_FUNCTION_INFO_V1(hstore_svals);
     913                 : Datum
     914              13 : hstore_svals(PG_FUNCTION_ARGS)
     915 ECB             : {
     916                 :     FuncCallContext *funcctx;
     917                 :     HStore     *hs;
     918                 :     int         i;
     919                 : 
     920 GIC          13 :     if (SRF_IS_FIRSTCALL())
     921                 :     {
     922 CBC           4 :         hs = PG_GETARG_HSTORE_P(0);
     923               4 :         funcctx = SRF_FIRSTCALL_INIT();
     924               4 :         setup_firstcall(funcctx, hs, NULL);
     925                 :     }
     926 ECB             : 
     927 GIC          13 :     funcctx = SRF_PERCALL_SETUP();
     928 CBC          13 :     hs = (HStore *) funcctx->user_fctx;
     929 GIC          13 :     i = funcctx->call_cntr;
     930 ECB             : 
     931 GIC          13 :     if (i < HS_COUNT(hs))
     932                 :     {
     933               9 :         HEntry     *entries = ARRPTR(hs);
     934                 : 
     935 CBC           9 :         if (HSTORE_VALISNULL(entries, i))
     936 ECB             :         {
     937                 :             ReturnSetInfo *rsi;
     938                 : 
     939                 :             /* ugly ugly ugly. why no macro for this? */
     940 GIC           1 :             (funcctx)->call_cntr++;
     941               1 :             rsi = (ReturnSetInfo *) fcinfo->resultinfo;
     942               1 :             rsi->isDone = ExprMultipleResult;
     943               1 :             PG_RETURN_NULL();
     944 ECB             :         }
     945                 :         else
     946                 :         {
     947                 :             text       *item;
     948                 : 
     949 GIC           8 :             item = cstring_to_text_with_len(HSTORE_VAL(entries, STRPTR(hs), i),
     950               8 :                                             HSTORE_VALLEN(entries, i));
     951 ECB             : 
     952 GIC           8 :             SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
     953                 :         }
     954                 :     }
     955 ECB             : 
     956 GIC           4 :     SRF_RETURN_DONE(funcctx);
     957 ECB             : }
     958                 : 
     959                 : 
     960 CBC           8 : PG_FUNCTION_INFO_V1(hstore_contains);
     961 ECB             : Datum
     962 CBC        3560 : hstore_contains(PG_FUNCTION_ARGS)
     963 ECB             : {
     964 CBC        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 GIC        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 ECB             :      * 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 GIC        7148 :     for (i = 0; res && i < tcount; ++i)
     983 ECB             :     {
     984 GIC        3588 :         int         idx = hstoreFindKey(val, &lastidx,
     985 CBC        3588 :                                         HSTORE_KEY(te, tstr, i),
     986            3588 :                                         HSTORE_KEYLEN(te, i));
     987                 : 
     988            3588 :         if (idx >= 0)
     989 ECB             :         {
     990 CBC        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 GIC         513 :                 (!nullval && (vallen != HSTORE_VALLEN(ve, idx) ||
     995             305 :                               memcmp(HSTORE_VAL(te, tstr, i),
     996 CBC         305 :                                      HSTORE_VAL(ve, vstr, idx),
     997                 :                                      vallen) != 0)))
     998 GIC         980 :                 res = false;
     999 ECB             :         }
    1000                 :         else
    1001 GIC        2505 :             res = false;
    1002                 :     }
    1003 ECB             : 
    1004 GIC        3560 :     PG_RETURN_BOOL(res);
    1005 EUB             : }
    1006                 : 
    1007                 : 
    1008 GIC           7 : PG_FUNCTION_INFO_V1(hstore_contained);
    1009                 : Datum
    1010 UIC           0 : hstore_contained(PG_FUNCTION_ARGS)
    1011                 : {
    1012               0 :     PG_RETURN_DATUM(DirectFunctionCall2(hstore_contains,
    1013                 :                                         PG_GETARG_DATUM(1),
    1014 ECB             :                                         PG_GETARG_DATUM(0)
    1015                 :                                         ));
    1016                 : }
    1017                 : 
    1018                 : 
    1019 GIC           8 : PG_FUNCTION_INFO_V1(hstore_each);
    1020                 : Datum
    1021           11568 : hstore_each(PG_FUNCTION_ARGS)
    1022 ECB             : {
    1023                 :     FuncCallContext *funcctx;
    1024                 :     HStore     *hs;
    1025                 :     int         i;
    1026                 : 
    1027 GIC       11568 :     if (SRF_IS_FIRSTCALL())
    1028                 :     {
    1029 CBC        2003 :         hs = PG_GETARG_HSTORE_P(0);
    1030            2003 :         funcctx = SRF_FIRSTCALL_INIT();
    1031            2003 :         setup_firstcall(funcctx, hs, fcinfo);
    1032                 :     }
    1033 ECB             : 
    1034 GIC       11568 :     funcctx = SRF_PERCALL_SETUP();
    1035 CBC       11568 :     hs = (HStore *) funcctx->user_fctx;
    1036           11568 :     i = funcctx->call_cntr;
    1037                 : 
    1038 GIC       11568 :     if (i < HS_COUNT(hs))
    1039 ECB             :     {
    1040 GIC        9565 :         HEntry     *entries = ARRPTR(hs);
    1041            9565 :         char       *ptr = STRPTR(hs);
    1042                 :         Datum       res,
    1043 ECB             :                     dvalues[2];
    1044 CBC        9565 :         bool        nulls[2] = {false, false};
    1045 ECB             :         text       *item;
    1046                 :         HeapTuple   tuple;
    1047                 : 
    1048 GIC        9565 :         item = cstring_to_text_with_len(HSTORE_KEY(entries, ptr, i),
    1049 CBC        9565 :                                         HSTORE_KEYLEN(entries, i));
    1050            9565 :         dvalues[0] = PointerGetDatum(item);
    1051                 : 
    1052 GIC        9565 :         if (HSTORE_VALISNULL(entries, i))
    1053                 :         {
    1054 CBC           3 :             dvalues[1] = (Datum) 0;
    1055               3 :             nulls[1] = true;
    1056 ECB             :         }
    1057                 :         else
    1058                 :         {
    1059 CBC        9562 :             item = cstring_to_text_with_len(HSTORE_VAL(entries, ptr, i),
    1060            9562 :                                             HSTORE_VALLEN(entries, i));
    1061 GIC        9562 :             dvalues[1] = PointerGetDatum(item);
    1062 ECB             :         }
    1063                 : 
    1064 GIC        9565 :         tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
    1065 CBC        9565 :         res = HeapTupleGetDatum(tuple);
    1066                 : 
    1067 GNC        9565 :         SRF_RETURN_NEXT(funcctx, res);
    1068                 :     }
    1069                 : 
    1070 GIC        2003 :     SRF_RETURN_DONE(funcctx);
    1071                 : }
    1072                 : 
    1073                 : 
    1074                 : /*
    1075 ECB             :  * 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 CBC           8 : PG_FUNCTION_INFO_V1(hstore_cmp);
    1081 ECB             : Datum
    1082 CBC       43261 : hstore_cmp(PG_FUNCTION_ARGS)
    1083 ECB             : {
    1084 GIC       43261 :     HStore     *hs1 = PG_GETARG_HSTORE_P(0);
    1085 CBC       43261 :     HStore     *hs2 = PG_GETARG_HSTORE_P(1);
    1086 GIC       43261 :     int         hcount1 = HS_COUNT(hs1);
    1087           43261 :     int         hcount2 = HS_COUNT(hs2);
    1088           43261 :     int         res = 0;
    1089                 : 
    1090           43261 :     if (hcount1 == 0 || hcount2 == 0)
    1091 ECB             :     {
    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 GIC        3676 :         if (hcount1 > 0)
    1097             253 :             res = 1;
    1098            3423 :         else if (hcount2 > 0)
    1099 CBC        1635 :             res = -1;
    1100 ECB             :     }
    1101                 :     else
    1102                 :     {
    1103                 :         /* here we know both operands are nonempty */
    1104 CBC       39585 :         char       *str1 = STRPTR(hs1);
    1105 GIC       39585 :         char       *str2 = STRPTR(hs2);
    1106 CBC       39585 :         HEntry     *ent1 = ARRPTR(hs1);
    1107 GIC       39585 :         HEntry     *ent2 = ARRPTR(hs2);
    1108 CBC       39585 :         size_t      len1 = HSE_ENDPOS(ent1[2 * hcount1 - 1]);
    1109 GIC       39585 :         size_t      len2 = HSE_ENDPOS(ent2[2 * hcount2 - 1]);
    1110 ECB             : 
    1111 GBC       39585 :         res = memcmp(str1, str2, Min(len1, len2));
    1112 ECB             : 
    1113 GBC       39585 :         if (res == 0)
    1114 ECB             :         {
    1115 GBC        2770 :             if (len1 > len2)
    1116 LBC           0 :                 res = 1;
    1117 GBC        2770 :             else if (len1 < len2)
    1118 UIC           0 :                 res = -1;
    1119 GIC        2770 :             else if (hcount1 > hcount2)
    1120 LBC           0 :                 res = 1;
    1121 GIC        2770 :             else if (hcount2 > hcount1)
    1122 UIC           0 :                 res = -1;
    1123 ECB             :             else
    1124                 :             {
    1125 CBC        2770 :                 int         count = hcount1 * 2;
    1126                 :                 int         i;
    1127 ECB             : 
    1128 GIC       32770 :                 for (i = 0; i < count; ++i)
    1129 GBC       30000 :                     if (HSE_ENDPOS(ent1[i]) != HSE_ENDPOS(ent2[i]) ||
    1130           30000 :                         HSE_ISNULL(ent1[i]) != HSE_ISNULL(ent2[i]))
    1131 EUB             :                         break;
    1132 GBC        2770 :                 if (i < count)
    1133 EUB             :                 {
    1134 UBC           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 UIC           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 ECB             :                 }
    1143                 :             }
    1144                 :         }
    1145                 :         else
    1146                 :         {
    1147 GIC       36815 :             res = (res > 0) ? 1 : -1;
    1148                 :         }
    1149                 :     }
    1150 ECB             : 
    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 GIC       43261 :     PG_FREE_IF_COPY(hs1, 0);
    1156 CBC       43261 :     PG_FREE_IF_COPY(hs2, 1);
    1157 GIC       43261 :     PG_RETURN_INT32(res);
    1158 ECB             : }
    1159                 : 
    1160                 : 
    1161 GIC           8 : PG_FUNCTION_INFO_V1(hstore_eq);
    1162                 : Datum
    1163            4121 : hstore_eq(PG_FUNCTION_ARGS)
    1164 ECB             : {
    1165 GIC        4121 :     int         res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
    1166                 :                                                         PG_GETARG_DATUM(0),
    1167 ECB             :                                                         PG_GETARG_DATUM(1)));
    1168                 : 
    1169 GBC        4121 :     PG_RETURN_BOOL(res == 0);
    1170                 : }
    1171 EUB             : 
    1172 GIC           7 : PG_FUNCTION_INFO_V1(hstore_ne);
    1173                 : Datum
    1174 UIC           0 : hstore_ne(PG_FUNCTION_ARGS)
    1175 EUB             : {
    1176 UIC           0 :     int         res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
    1177                 :                                                         PG_GETARG_DATUM(0),
    1178 ECB             :                                                         PG_GETARG_DATUM(1)));
    1179                 : 
    1180 LBC           0 :     PG_RETURN_BOOL(res != 0);
    1181                 : }
    1182 ECB             : 
    1183 GIC           8 : PG_FUNCTION_INFO_V1(hstore_gt);
    1184                 : Datum
    1185             127 : hstore_gt(PG_FUNCTION_ARGS)
    1186 ECB             : {
    1187 GIC         127 :     int         res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
    1188                 :                                                         PG_GETARG_DATUM(0),
    1189 ECB             :                                                         PG_GETARG_DATUM(1)));
    1190                 : 
    1191 GBC         127 :     PG_RETURN_BOOL(res > 0);
    1192                 : }
    1193 EUB             : 
    1194 GIC           7 : PG_FUNCTION_INFO_V1(hstore_ge);
    1195                 : Datum
    1196 UIC           0 : hstore_ge(PG_FUNCTION_ARGS)
    1197 EUB             : {
    1198 UIC           0 :     int         res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
    1199                 :                                                         PG_GETARG_DATUM(0),
    1200 ECB             :                                                         PG_GETARG_DATUM(1)));
    1201                 : 
    1202 UBC           0 :     PG_RETURN_BOOL(res >= 0);
    1203                 : }
    1204 EUB             : 
    1205 GIC           7 : PG_FUNCTION_INFO_V1(hstore_lt);
    1206                 : Datum
    1207 UIC           0 : hstore_lt(PG_FUNCTION_ARGS)
    1208 EUB             : {
    1209 UIC           0 :     int         res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
    1210                 :                                                         PG_GETARG_DATUM(0),
    1211 ECB             :                                                         PG_GETARG_DATUM(1)));
    1212                 : 
    1213 UBC           0 :     PG_RETURN_BOOL(res < 0);
    1214                 : }
    1215 EUB             : 
    1216 GIC           7 : PG_FUNCTION_INFO_V1(hstore_le);
    1217                 : Datum
    1218 UIC           0 : hstore_le(PG_FUNCTION_ARGS)
    1219 EUB             : {
    1220 UIC           0 :     int         res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
    1221                 :                                                         PG_GETARG_DATUM(0),
    1222                 :                                                         PG_GETARG_DATUM(1)));
    1223 ECB             : 
    1224 UIC           0 :     PG_RETURN_BOOL(res <= 0);
    1225 ECB             : }
    1226                 : 
    1227                 : 
    1228 CBC           8 : PG_FUNCTION_INFO_V1(hstore_hash);
    1229 ECB             : Datum
    1230 GIC        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 ECB             :      * 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 GIC        2014 :     Assert(VARSIZE(hs) ==
    1243 ECB             :            (HS_COUNT(hs) != 0 ?
    1244                 :             CALCDATASIZE(HS_COUNT(hs),
    1245                 :                          HSE_ENDPOS(ARRPTR(hs)[2 * HS_COUNT(hs) - 1])) :
    1246                 :             HSHRDSIZE));
    1247                 : 
    1248 GIC        2014 :     PG_FREE_IF_COPY(hs, 0);
    1249 CBC        2014 :     PG_RETURN_DATUM(hval);
    1250                 : }
    1251 ECB             : 
    1252 CBC           8 : PG_FUNCTION_INFO_V1(hstore_hash_extended);
    1253                 : Datum
    1254 GIC          10 : hstore_hash_extended(PG_FUNCTION_ARGS)
    1255 ECB             : {
    1256 CBC          10 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
    1257 GIC          10 :     uint64      seed = PG_GETARG_INT64(1);
    1258                 :     Datum       hval;
    1259                 : 
    1260 CBC          10 :     hval = hash_any_extended((unsigned char *) VARDATA(hs),
    1261 GIC          10 :                              VARSIZE(hs) - VARHDRSZ,
    1262                 :                              seed);
    1263                 : 
    1264                 :     /* See comment in hstore_hash */
    1265              10 :     Assert(VARSIZE(hs) ==
    1266 ECB             :            (HS_COUNT(hs) != 0 ?
    1267                 :             CALCDATASIZE(HS_COUNT(hs),
    1268                 :                          HSE_ENDPOS(ARRPTR(hs)[2 * HS_COUNT(hs) - 1])) :
    1269                 :             HSHRDSIZE));
    1270                 : 
    1271 GIC          10 :     PG_FREE_IF_COPY(hs, 0);
    1272              10 :     PG_RETURN_DATUM(hval);
    1273                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a