LCOV - code coverage report
Current view: top level - contrib/hstore - hstore_op.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 522 571 91.4 %
Date: 2024-04-20 01:11:48 Functions: 57 86 66.3 %
Legend: Lines: hit not hit

          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       18912 : hstoreFindKey(HStore *hs, int *lowbound, char *key, int keylen)
      37             : {
      38       18912 :     HEntry     *entries = ARRPTR(hs);
      39       18912 :     int         stopLow = lowbound ? *lowbound : 0;
      40       18912 :     int         stopHigh = HS_COUNT(hs);
      41             :     int         stopMiddle;
      42       18912 :     char       *base = STRPTR(hs);
      43             : 
      44       49698 :     while (stopLow < stopHigh)
      45             :     {
      46             :         int         difference;
      47             : 
      48       37112 :         stopMiddle = stopLow + (stopHigh - stopLow) / 2;
      49             : 
      50       37112 :         if (HSTORE_KEYLEN(entries, stopMiddle) == keylen)
      51       14826 :             difference = memcmp(HSTORE_KEY(entries, base, stopMiddle), key, keylen);
      52             :         else
      53       22286 :             difference = (HSTORE_KEYLEN(entries, stopMiddle) > keylen) ? 1 : -1;
      54             : 
      55       37112 :         if (difference == 0)
      56             :         {
      57        6326 :             if (lowbound)
      58        5038 :                 *lowbound = stopMiddle + 1;
      59        6326 :             return stopMiddle;
      60             :         }
      61       30786 :         else if (difference < 0)
      62       16456 :             stopLow = stopMiddle + 1;
      63             :         else
      64       14330 :             stopHigh = stopMiddle;
      65             :     }
      66             : 
      67       12586 :     if (lowbound)
      68       10658 :         *lowbound = stopLow;
      69       12586 :     return -1;
      70             : }
      71             : 
      72             : Pairs *
      73        5684 : 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        5684 :     deconstruct_array_builtin(a, TEXTOID, &key_datums, &key_nulls, &key_count);
      84             : 
      85        5684 :     if (key_count == 0)
      86             :     {
      87          10 :         *npairs = 0;
      88          10 :         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        5674 :     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        5674 :     key_pairs = palloc(sizeof(Pairs) * key_count);
     105             : 
     106       17032 :     for (i = 0, j = 0; i < key_count; i++)
     107             :     {
     108       11358 :         if (!key_nulls[i])
     109             :         {
     110       11358 :             key_pairs[j].key = VARDATA(key_datums[i]);
     111       11358 :             key_pairs[j].keylen = VARSIZE(key_datums[i]) - VARHDRSZ;
     112       11358 :             key_pairs[j].val = NULL;
     113       11358 :             key_pairs[j].vallen = 0;
     114       11358 :             key_pairs[j].needfree = 0;
     115       11358 :             key_pairs[j].isnull = 1;
     116       11358 :             j++;
     117             :         }
     118             :     }
     119             : 
     120        5674 :     *npairs = hstoreUniquePairs(key_pairs, j, &bufsiz);
     121             : 
     122        5674 :     return key_pairs;
     123             : }
     124             : 
     125             : 
     126          16 : PG_FUNCTION_INFO_V1(hstore_fetchval);
     127             : Datum
     128          12 : hstore_fetchval(PG_FUNCTION_ARGS)
     129             : {
     130          12 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     131          12 :     text       *key = PG_GETARG_TEXT_PP(1);
     132          12 :     HEntry     *entries = ARRPTR(hs);
     133             :     text       *out;
     134          24 :     int         idx = hstoreFindKey(hs, NULL,
     135          24 :                                     VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
     136             : 
     137          12 :     if (idx < 0 || HSTORE_VALISNULL(entries, idx))
     138           4 :         PG_RETURN_NULL();
     139             : 
     140           8 :     out = cstring_to_text_with_len(HSTORE_VAL(entries, STRPTR(hs), idx),
     141           8 :                                    HSTORE_VALLEN(entries, idx));
     142             : 
     143           8 :     PG_RETURN_TEXT_P(out);
     144             : }
     145             : 
     146             : 
     147          32 : PG_FUNCTION_INFO_V1(hstore_exists);
     148             : Datum
     149        2880 : hstore_exists(PG_FUNCTION_ARGS)
     150             : {
     151        2880 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     152        2880 :     text       *key = PG_GETARG_TEXT_PP(1);
     153        5760 :     int         idx = hstoreFindKey(hs, NULL,
     154        5760 :                                     VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
     155             : 
     156        2880 :     PG_RETURN_BOOL(idx >= 0);
     157             : }
     158             : 
     159             : 
     160          16 : PG_FUNCTION_INFO_V1(hstore_exists_any);
     161             : Datum
     162        3454 : hstore_exists_any(PG_FUNCTION_ARGS)
     163             : {
     164        3454 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     165        3454 :     ArrayType  *keys = PG_GETARG_ARRAYTYPE_P(1);
     166             :     int         nkeys;
     167        3454 :     Pairs      *key_pairs = hstoreArrayToPairs(keys, &nkeys);
     168             :     int         i;
     169        3454 :     int         lowbound = 0;
     170        3454 :     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        7160 :     for (i = 0; i < nkeys; i++)
     179             :     {
     180        5734 :         int         idx = hstoreFindKey(hs, &lowbound,
     181        5734 :                                         key_pairs[i].key, key_pairs[i].keylen);
     182             : 
     183        5734 :         if (idx >= 0)
     184             :         {
     185        2028 :             res = true;
     186        2028 :             break;
     187             :         }
     188             :     }
     189             : 
     190        3454 :     PG_RETURN_BOOL(res);
     191             : }
     192             : 
     193             : 
     194          16 : PG_FUNCTION_INFO_V1(hstore_exists_all);
     195             : Datum
     196        2194 : hstore_exists_all(PG_FUNCTION_ARGS)
     197             : {
     198        2194 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     199        2194 :     ArrayType  *keys = PG_GETARG_ARRAYTYPE_P(1);
     200             :     int         nkeys;
     201        2194 :     Pairs      *key_pairs = hstoreArrayToPairs(keys, &nkeys);
     202             :     int         i;
     203        2194 :     int         lowbound = 0;
     204        2194 :     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        3014 :     for (i = 0; i < nkeys; i++)
     213             :     {
     214        2756 :         int         idx = hstoreFindKey(hs, &lowbound,
     215        2756 :                                         key_pairs[i].key, key_pairs[i].keylen);
     216             : 
     217        2756 :         if (idx < 0)
     218             :         {
     219        1936 :             res = false;
     220        1936 :             break;
     221             :         }
     222             :     }
     223             : 
     224        2194 :     PG_RETURN_BOOL(res);
     225             : }
     226             : 
     227             : 
     228          30 : PG_FUNCTION_INFO_V1(hstore_defined);
     229             : Datum
     230           8 : hstore_defined(PG_FUNCTION_ARGS)
     231             : {
     232           8 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     233           8 :     text       *key = PG_GETARG_TEXT_PP(1);
     234           8 :     HEntry     *entries = ARRPTR(hs);
     235          16 :     int         idx = hstoreFindKey(hs, NULL,
     236          16 :                                     VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
     237           8 :     bool        res = (idx >= 0 && !HSTORE_VALISNULL(entries, idx));
     238             : 
     239           8 :     PG_RETURN_BOOL(res);
     240             : }
     241             : 
     242             : 
     243          16 : PG_FUNCTION_INFO_V1(hstore_delete);
     244             : Datum
     245          22 : hstore_delete(PG_FUNCTION_ARGS)
     246             : {
     247          22 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     248          22 :     text       *key = PG_GETARG_TEXT_PP(1);
     249          22 :     char       *keyptr = VARDATA_ANY(key);
     250          22 :     int         keylen = VARSIZE_ANY_EXHDR(key);
     251          22 :     HStore     *out = palloc(VARSIZE(hs));
     252             :     char       *bufs,
     253             :                *bufd,
     254             :                *ptrd;
     255             :     HEntry     *es,
     256             :                *ed;
     257             :     int         i;
     258          22 :     int         count = HS_COUNT(hs);
     259          22 :     int         outcount = 0;
     260             : 
     261          22 :     SET_VARSIZE(out, VARSIZE(hs));
     262          22 :     HS_SETCOUNT(out, count);    /* temporary! */
     263             : 
     264          22 :     bufs = STRPTR(hs);
     265          22 :     es = ARRPTR(hs);
     266          22 :     bufd = ptrd = STRPTR(out);
     267          22 :     ed = ARRPTR(out);
     268             : 
     269          88 :     for (i = 0; i < count; ++i)
     270             :     {
     271          66 :         int         len = HSTORE_KEYLEN(es, i);
     272          66 :         char       *ptrs = HSTORE_KEY(es, bufs, i);
     273             : 
     274          66 :         if (!(len == keylen && memcmp(ptrs, keyptr, keylen) == 0))
     275             :         {
     276          48 :             int         vallen = HSTORE_VALLEN(es, i);
     277             : 
     278          48 :             HS_COPYITEM(ed, bufd, ptrd, ptrs, len, vallen,
     279             :                         HSTORE_VALISNULL(es, i));
     280          48 :             ++outcount;
     281             :         }
     282             :     }
     283             : 
     284          22 :     HS_FINALIZE(out, outcount, bufd, ptrd);
     285             : 
     286          22 :     PG_RETURN_POINTER(out);
     287             : }
     288             : 
     289             : 
     290          16 : PG_FUNCTION_INFO_V1(hstore_delete_array);
     291             : Datum
     292          24 : hstore_delete_array(PG_FUNCTION_ARGS)
     293             : {
     294          24 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     295          24 :     HStore     *out = palloc(VARSIZE(hs));
     296          24 :     int         hs_count = HS_COUNT(hs);
     297             :     char       *ps,
     298             :                *bufd,
     299             :                *pd;
     300             :     HEntry     *es,
     301             :                *ed;
     302             :     int         i,
     303             :                 j;
     304          24 :     int         outcount = 0;
     305          24 :     ArrayType  *key_array = PG_GETARG_ARRAYTYPE_P(1);
     306             :     int         nkeys;
     307          24 :     Pairs      *key_pairs = hstoreArrayToPairs(key_array, &nkeys);
     308             : 
     309          24 :     SET_VARSIZE(out, VARSIZE(hs));
     310          24 :     HS_SETCOUNT(out, hs_count); /* temporary! */
     311             : 
     312          24 :     ps = STRPTR(hs);
     313          24 :     es = ARRPTR(hs);
     314          24 :     bufd = pd = STRPTR(out);
     315          24 :     ed = ARRPTR(out);
     316             : 
     317          24 :     if (nkeys == 0)
     318             :     {
     319             :         /* return a copy of the input, unchanged */
     320           6 :         memcpy(out, hs, VARSIZE(hs));
     321           6 :         HS_FIXSIZE(out, hs_count);
     322           6 :         HS_SETCOUNT(out, hs_count);
     323           6 :         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          72 :     for (i = j = 0; i < hs_count;)
     332             :     {
     333             :         int         difference;
     334             : 
     335          54 :         if (j >= nkeys)
     336           0 :             difference = -1;
     337             :         else
     338             :         {
     339          54 :             int         skeylen = HSTORE_KEYLEN(es, i);
     340             : 
     341          54 :             if (skeylen == key_pairs[j].keylen)
     342          54 :                 difference = memcmp(HSTORE_KEY(es, ps, i),
     343          54 :                                     key_pairs[j].key,
     344          54 :                                     key_pairs[j].keylen);
     345             :             else
     346           0 :                 difference = (skeylen > key_pairs[j].keylen) ? 1 : -1;
     347             :         }
     348             : 
     349          54 :         if (difference > 0)
     350           0 :             ++j;
     351          54 :         else if (difference == 0)
     352          28 :             ++i, ++j;
     353             :         else
     354             :         {
     355          26 :             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          26 :             ++outcount;
     359          26 :             ++i;
     360             :         }
     361             :     }
     362             : 
     363          18 :     HS_FINALIZE(out, outcount, bufd, pd);
     364             : 
     365          18 :     PG_RETURN_POINTER(out);
     366             : }
     367             : 
     368             : 
     369          16 : PG_FUNCTION_INFO_V1(hstore_delete_hstore);
     370             : Datum
     371          24 : hstore_delete_hstore(PG_FUNCTION_ARGS)
     372             : {
     373          24 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     374          24 :     HStore     *hs2 = PG_GETARG_HSTORE_P(1);
     375          24 :     HStore     *out = palloc(VARSIZE(hs));
     376          24 :     int         hs_count = HS_COUNT(hs);
     377          24 :     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          24 :     int         outcount = 0;
     388             : 
     389          24 :     SET_VARSIZE(out, VARSIZE(hs));
     390          24 :     HS_SETCOUNT(out, hs_count); /* temporary! */
     391             : 
     392          24 :     ps = STRPTR(hs);
     393          24 :     es = ARRPTR(hs);
     394          24 :     ps2 = STRPTR(hs2);
     395          24 :     es2 = ARRPTR(hs2);
     396          24 :     bufd = pd = STRPTR(out);
     397          24 :     ed = ARRPTR(out);
     398             : 
     399          24 :     if (hs2_count == 0)
     400             :     {
     401             :         /* return a copy of the input, unchanged */
     402           6 :         memcpy(out, hs, VARSIZE(hs));
     403           6 :         HS_FIXSIZE(out, hs_count);
     404           6 :         HS_SETCOUNT(out, hs_count);
     405           6 :         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          72 :     for (i = j = 0; i < hs_count;)
     415             :     {
     416             :         int         difference;
     417             : 
     418          54 :         if (j >= hs2_count)
     419          10 :             difference = -1;
     420             :         else
     421             :         {
     422          44 :             int         skeylen = HSTORE_KEYLEN(es, i);
     423          44 :             int         s2keylen = HSTORE_KEYLEN(es2, j);
     424             : 
     425          44 :             if (skeylen == s2keylen)
     426          40 :                 difference = memcmp(HSTORE_KEY(es, ps, i),
     427          40 :                                     HSTORE_KEY(es2, ps2, j),
     428             :                                     skeylen);
     429             :             else
     430           4 :                 difference = (skeylen > s2keylen) ? 1 : -1;
     431             :         }
     432             : 
     433          54 :         if (difference > 0)
     434           0 :             ++j;
     435          54 :         else if (difference == 0)
     436             :         {
     437          34 :             int         svallen = HSTORE_VALLEN(es, i);
     438          34 :             int         snullval = HSTORE_VALISNULL(es, i);
     439             : 
     440          34 :             if (snullval != HSTORE_VALISNULL(es2, j) ||
     441          30 :                 (!snullval && (svallen != HSTORE_VALLEN(es2, j) ||
     442          30 :                                memcmp(HSTORE_VAL(es, ps, i),
     443          30 :                                       HSTORE_VAL(es2, ps2, j),
     444             :                                       svallen) != 0)))
     445             :             {
     446           8 :                 HS_COPYITEM(ed, bufd, pd,
     447             :                             HSTORE_KEY(es, ps, i), HSTORE_KEYLEN(es, i),
     448             :                             svallen, snullval);
     449           8 :                 ++outcount;
     450             :             }
     451          34 :             ++i, ++j;
     452             :         }
     453             :         else
     454             :         {
     455          20 :             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          20 :             ++outcount;
     459          20 :             ++i;
     460             :         }
     461             :     }
     462             : 
     463          18 :     HS_FINALIZE(out, outcount, bufd, pd);
     464             : 
     465          18 :     PG_RETURN_POINTER(out);
     466             : }
     467             : 
     468             : 
     469          16 : PG_FUNCTION_INFO_V1(hstore_concat);
     470             : Datum
     471          60 : hstore_concat(PG_FUNCTION_ARGS)
     472             : {
     473          60 :     HStore     *s1 = PG_GETARG_HSTORE_P(0);
     474          60 :     HStore     *s2 = PG_GETARG_HSTORE_P(1);
     475          60 :     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          60 :     int         s1count = HS_COUNT(s1);
     486          60 :     int         s2count = HS_COUNT(s2);
     487          60 :     int         outcount = 0;
     488             : 
     489          60 :     SET_VARSIZE(out, VARSIZE(s1) + VARSIZE(s2) - HSHRDSIZE);
     490          60 :     HS_SETCOUNT(out, s1count + s2count);
     491             : 
     492          60 :     if (s1count == 0)
     493             :     {
     494             :         /* return a copy of the input, unchanged */
     495           8 :         memcpy(out, s2, VARSIZE(s2));
     496           8 :         HS_FIXSIZE(out, s2count);
     497           8 :         HS_SETCOUNT(out, s2count);
     498           8 :         PG_RETURN_POINTER(out);
     499             :     }
     500             : 
     501          52 :     if (s2count == 0)
     502             :     {
     503             :         /* return a copy of the input, unchanged */
     504           4 :         memcpy(out, s1, VARSIZE(s1));
     505           4 :         HS_FIXSIZE(out, s1count);
     506           4 :         HS_SETCOUNT(out, s1count);
     507           4 :         PG_RETURN_POINTER(out);
     508             :     }
     509             : 
     510          48 :     ps1 = STRPTR(s1);
     511          48 :     ps2 = STRPTR(s2);
     512          48 :     bufd = pd = STRPTR(out);
     513          48 :     es1 = ARRPTR(s1);
     514          48 :     es2 = ARRPTR(s2);
     515          48 :     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         180 :     for (s1idx = s2idx = 0; s1idx < s1count || s2idx < s2count; ++outcount)
     523             :     {
     524             :         int         difference;
     525             : 
     526         132 :         if (s1idx >= s1count)
     527          26 :             difference = 1;
     528         106 :         else if (s2idx >= s2count)
     529          14 :             difference = -1;
     530             :         else
     531             :         {
     532          92 :             int         s1keylen = HSTORE_KEYLEN(es1, s1idx);
     533          92 :             int         s2keylen = HSTORE_KEYLEN(es2, s2idx);
     534             : 
     535          92 :             if (s1keylen == s2keylen)
     536          82 :                 difference = memcmp(HSTORE_KEY(es1, ps1, s1idx),
     537          82 :                                     HSTORE_KEY(es2, ps2, s2idx),
     538             :                                     s1keylen);
     539             :             else
     540          10 :                 difference = (s1keylen > s2keylen) ? 1 : -1;
     541             :         }
     542             : 
     543         132 :         if (difference >= 0)
     544             :         {
     545          76 :             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          76 :             ++s2idx;
     549          76 :             if (difference == 0)
     550          38 :                 ++s1idx;
     551             :         }
     552             :         else
     553             :         {
     554          56 :             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          56 :             ++s1idx;
     558             :         }
     559             :     }
     560             : 
     561          48 :     HS_FINALIZE(out, outcount, bufd, pd);
     562             : 
     563          48 :     PG_RETURN_POINTER(out);
     564             : }
     565             : 
     566             : 
     567          16 : PG_FUNCTION_INFO_V1(hstore_slice_to_array);
     568             : Datum
     569           8 : hstore_slice_to_array(PG_FUNCTION_ARGS)
     570             : {
     571           8 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     572           8 :     HEntry     *entries = ARRPTR(hs);
     573           8 :     char       *ptr = STRPTR(hs);
     574           8 :     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           8 :     deconstruct_array_builtin(key_array, TEXTOID, &key_datums, &key_nulls, &key_count);
     584             : 
     585           8 :     if (key_count == 0)
     586             :     {
     587           0 :         aout = construct_empty_array(TEXTOID);
     588           0 :         PG_RETURN_POINTER(aout);
     589             :     }
     590             : 
     591           8 :     out_datums = palloc(sizeof(Datum) * key_count);
     592           8 :     out_nulls = palloc(sizeof(bool) * key_count);
     593             : 
     594          30 :     for (i = 0; i < key_count; ++i)
     595             :     {
     596          22 :         text       *key = (text *) DatumGetPointer(key_datums[i]);
     597             :         int         idx;
     598             : 
     599          22 :         if (key_nulls[i])
     600           2 :             idx = -1;
     601             :         else
     602          20 :             idx = hstoreFindKey(hs, NULL, VARDATA(key), VARSIZE(key) - VARHDRSZ);
     603             : 
     604          22 :         if (idx < 0 || HSTORE_VALISNULL(entries, idx))
     605             :         {
     606           4 :             out_nulls[i] = true;
     607           4 :             out_datums[i] = (Datum) 0;
     608             :         }
     609             :         else
     610             :         {
     611          36 :             out_datums[i] =
     612          18 :                 PointerGetDatum(cstring_to_text_with_len(HSTORE_VAL(entries, ptr, idx),
     613          18 :                                                          HSTORE_VALLEN(entries, idx)));
     614          18 :             out_nulls[i] = false;
     615             :         }
     616             :     }
     617             : 
     618           8 :     aout = construct_md_array(out_datums, out_nulls,
     619             :                               ARR_NDIM(key_array),
     620             :                               ARR_DIMS(key_array),
     621           8 :                               ARR_LBOUND(key_array),
     622             :                               TEXTOID, -1, false, TYPALIGN_INT);
     623             : 
     624           8 :     PG_RETURN_POINTER(aout);
     625             : }
     626             : 
     627             : 
     628          16 : PG_FUNCTION_INFO_V1(hstore_slice_to_hstore);
     629             : Datum
     630          12 : hstore_slice_to_hstore(PG_FUNCTION_ARGS)
     631             : {
     632          12 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     633          12 :     HEntry     *entries = ARRPTR(hs);
     634          12 :     char       *ptr = STRPTR(hs);
     635          12 :     ArrayType  *key_array = PG_GETARG_ARRAYTYPE_P(1);
     636             :     HStore     *out;
     637             :     int         nkeys;
     638          12 :     Pairs      *key_pairs = hstoreArrayToPairs(key_array, &nkeys);
     639             :     Pairs      *out_pairs;
     640             :     int         bufsiz;
     641          12 :     int         lastidx = 0;
     642             :     int         i;
     643          12 :     int         out_count = 0;
     644             : 
     645          12 :     if (nkeys == 0)
     646             :     {
     647           0 :         out = hstorePairs(NULL, 0, 0);
     648           0 :         PG_RETURN_POINTER(out);
     649             :     }
     650             : 
     651             :     /* hstoreArrayToPairs() checked overflow */
     652          12 :     out_pairs = palloc(sizeof(Pairs) * nkeys);
     653          12 :     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          42 :     for (i = 0; i < nkeys; ++i)
     663             :     {
     664          30 :         int         idx = hstoreFindKey(hs, &lastidx,
     665          30 :                                         key_pairs[i].key, key_pairs[i].keylen);
     666             : 
     667          30 :         if (idx >= 0)
     668             :         {
     669          24 :             out_pairs[out_count].key = key_pairs[i].key;
     670          24 :             bufsiz += (out_pairs[out_count].keylen = key_pairs[i].keylen);
     671          24 :             out_pairs[out_count].val = HSTORE_VAL(entries, ptr, idx);
     672          24 :             bufsiz += (out_pairs[out_count].vallen = HSTORE_VALLEN(entries, idx));
     673          24 :             out_pairs[out_count].isnull = HSTORE_VALISNULL(entries, idx);
     674          24 :             out_pairs[out_count].needfree = false;
     675          24 :             ++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          12 :     out = hstorePairs(out_pairs, out_count, bufsiz);
     685             : 
     686          12 :     PG_RETURN_POINTER(out);
     687             : }
     688             : 
     689             : 
     690          16 : PG_FUNCTION_INFO_V1(hstore_akeys);
     691             : Datum
     692           6 : hstore_akeys(PG_FUNCTION_ARGS)
     693             : {
     694           6 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     695             :     Datum      *d;
     696             :     ArrayType  *a;
     697           6 :     HEntry     *entries = ARRPTR(hs);
     698           6 :     char       *base = STRPTR(hs);
     699           6 :     int         count = HS_COUNT(hs);
     700             :     int         i;
     701             : 
     702           6 :     if (count == 0)
     703             :     {
     704           2 :         a = construct_empty_array(TEXTOID);
     705           2 :         PG_RETURN_POINTER(a);
     706             :     }
     707             : 
     708           4 :     d = (Datum *) palloc(sizeof(Datum) * count);
     709             : 
     710          14 :     for (i = 0; i < count; ++i)
     711             :     {
     712          10 :         text       *t = cstring_to_text_with_len(HSTORE_KEY(entries, base, i),
     713          10 :                                                  HSTORE_KEYLEN(entries, i));
     714             : 
     715          10 :         d[i] = PointerGetDatum(t);
     716             :     }
     717             : 
     718           4 :     a = construct_array_builtin(d, count, TEXTOID);
     719             : 
     720           4 :     PG_RETURN_POINTER(a);
     721             : }
     722             : 
     723             : 
     724          16 : PG_FUNCTION_INFO_V1(hstore_avals);
     725             : Datum
     726           8 : hstore_avals(PG_FUNCTION_ARGS)
     727             : {
     728           8 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     729             :     Datum      *d;
     730             :     bool       *nulls;
     731             :     ArrayType  *a;
     732           8 :     HEntry     *entries = ARRPTR(hs);
     733           8 :     char       *base = STRPTR(hs);
     734           8 :     int         count = HS_COUNT(hs);
     735           8 :     int         lb = 1;
     736             :     int         i;
     737             : 
     738           8 :     if (count == 0)
     739             :     {
     740           2 :         a = construct_empty_array(TEXTOID);
     741           2 :         PG_RETURN_POINTER(a);
     742             :     }
     743             : 
     744           6 :     d = (Datum *) palloc(sizeof(Datum) * count);
     745           6 :     nulls = (bool *) palloc(sizeof(bool) * count);
     746             : 
     747          24 :     for (i = 0; i < count; ++i)
     748             :     {
     749          18 :         if (HSTORE_VALISNULL(entries, i))
     750             :         {
     751           2 :             d[i] = (Datum) 0;
     752           2 :             nulls[i] = true;
     753             :         }
     754             :         else
     755             :         {
     756          16 :             text       *item = cstring_to_text_with_len(HSTORE_VAL(entries, base, i),
     757          16 :                                                         HSTORE_VALLEN(entries, i));
     758             : 
     759          16 :             d[i] = PointerGetDatum(item);
     760          16 :             nulls[i] = false;
     761             :         }
     762             :     }
     763             : 
     764           6 :     a = construct_md_array(d, nulls, 1, &count, &lb,
     765             :                            TEXTOID, -1, false, TYPALIGN_INT);
     766             : 
     767           6 :     PG_RETURN_POINTER(a);
     768             : }
     769             : 
     770             : 
     771             : static ArrayType *
     772           8 : hstore_to_array_internal(HStore *hs, int ndims)
     773             : {
     774           8 :     HEntry     *entries = ARRPTR(hs);
     775           8 :     char       *base = STRPTR(hs);
     776           8 :     int         count = HS_COUNT(hs);
     777           8 :     int         out_size[2] = {0, 2};
     778           8 :     int         lb[2] = {1, 1};
     779             :     Datum      *out_datums;
     780             :     bool       *out_nulls;
     781             :     int         i;
     782             : 
     783             :     Assert(ndims < 3);
     784             : 
     785           8 :     if (count == 0 || ndims == 0)
     786           0 :         return construct_empty_array(TEXTOID);
     787             : 
     788           8 :     out_size[0] = count * 2 / ndims;
     789           8 :     out_datums = palloc(sizeof(Datum) * count * 2);
     790           8 :     out_nulls = palloc(sizeof(bool) * count * 2);
     791             : 
     792          40 :     for (i = 0; i < count; ++i)
     793             :     {
     794          32 :         text       *key = cstring_to_text_with_len(HSTORE_KEY(entries, base, i),
     795          32 :                                                    HSTORE_KEYLEN(entries, i));
     796             : 
     797          32 :         out_datums[i * 2] = PointerGetDatum(key);
     798          32 :         out_nulls[i * 2] = false;
     799             : 
     800          32 :         if (HSTORE_VALISNULL(entries, i))
     801             :         {
     802           8 :             out_datums[i * 2 + 1] = (Datum) 0;
     803           8 :             out_nulls[i * 2 + 1] = true;
     804             :         }
     805             :         else
     806             :         {
     807          24 :             text       *item = cstring_to_text_with_len(HSTORE_VAL(entries, base, i),
     808          24 :                                                         HSTORE_VALLEN(entries, i));
     809             : 
     810          24 :             out_datums[i * 2 + 1] = PointerGetDatum(item);
     811          24 :             out_nulls[i * 2 + 1] = false;
     812             :         }
     813             :     }
     814             : 
     815           8 :     return construct_md_array(out_datums, out_nulls,
     816             :                               ndims, out_size, lb,
     817             :                               TEXTOID, -1, false, TYPALIGN_INT);
     818             : }
     819             : 
     820          16 : PG_FUNCTION_INFO_V1(hstore_to_array);
     821             : Datum
     822           4 : hstore_to_array(PG_FUNCTION_ARGS)
     823             : {
     824           4 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     825           4 :     ArrayType  *out = hstore_to_array_internal(hs, 1);
     826             : 
     827           4 :     PG_RETURN_POINTER(out);
     828             : }
     829             : 
     830          16 : PG_FUNCTION_INFO_V1(hstore_to_matrix);
     831             : Datum
     832           4 : hstore_to_matrix(PG_FUNCTION_ARGS)
     833             : {
     834           4 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
     835           4 :     ArrayType  *out = hstore_to_array_internal(hs, 2);
     836             : 
     837           4 :     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        4020 : setup_firstcall(FuncCallContext *funcctx, HStore *hs,
     851             :                 FunctionCallInfo fcinfo)
     852             : {
     853             :     MemoryContext oldcontext;
     854             :     HStore     *st;
     855             : 
     856        4020 :     oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
     857             : 
     858        4020 :     st = (HStore *) palloc(VARSIZE(hs));
     859        4020 :     memcpy(st, hs, VARSIZE(hs));
     860             : 
     861        4020 :     funcctx->user_fctx = (void *) st;
     862             : 
     863        4020 :     if (fcinfo)
     864             :     {
     865             :         TupleDesc   tupdesc;
     866             : 
     867             :         /* Build a tuple descriptor for our result type */
     868        4006 :         if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
     869           0 :             elog(ERROR, "return type must be a row type");
     870             : 
     871        4006 :         funcctx->tuple_desc = BlessTupleDesc(tupdesc);
     872             :     }
     873             : 
     874        4020 :     MemoryContextSwitchTo(oldcontext);
     875        4020 : }
     876             : 
     877             : 
     878          16 : PG_FUNCTION_INFO_V1(hstore_skeys);
     879             : Datum
     880          16 : hstore_skeys(PG_FUNCTION_ARGS)
     881             : {
     882             :     FuncCallContext *funcctx;
     883             :     HStore     *hs;
     884             :     int         i;
     885             : 
     886          16 :     if (SRF_IS_FIRSTCALL())
     887             :     {
     888           6 :         hs = PG_GETARG_HSTORE_P(0);
     889           6 :         funcctx = SRF_FIRSTCALL_INIT();
     890           6 :         setup_firstcall(funcctx, hs, NULL);
     891             :     }
     892             : 
     893          16 :     funcctx = SRF_PERCALL_SETUP();
     894          16 :     hs = (HStore *) funcctx->user_fctx;
     895          16 :     i = funcctx->call_cntr;
     896             : 
     897          16 :     if (i < HS_COUNT(hs))
     898             :     {
     899          10 :         HEntry     *entries = ARRPTR(hs);
     900             :         text       *item;
     901             : 
     902          10 :         item = cstring_to_text_with_len(HSTORE_KEY(entries, STRPTR(hs), i),
     903          10 :                                         HSTORE_KEYLEN(entries, i));
     904             : 
     905          10 :         SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
     906             :     }
     907             : 
     908           6 :     SRF_RETURN_DONE(funcctx);
     909             : }
     910             : 
     911             : 
     912          16 : PG_FUNCTION_INFO_V1(hstore_svals);
     913             : Datum
     914          26 : hstore_svals(PG_FUNCTION_ARGS)
     915             : {
     916             :     FuncCallContext *funcctx;
     917             :     HStore     *hs;
     918             :     int         i;
     919             : 
     920          26 :     if (SRF_IS_FIRSTCALL())
     921             :     {
     922           8 :         hs = PG_GETARG_HSTORE_P(0);
     923           8 :         funcctx = SRF_FIRSTCALL_INIT();
     924           8 :         setup_firstcall(funcctx, hs, NULL);
     925             :     }
     926             : 
     927          26 :     funcctx = SRF_PERCALL_SETUP();
     928          26 :     hs = (HStore *) funcctx->user_fctx;
     929          26 :     i = funcctx->call_cntr;
     930             : 
     931          26 :     if (i < HS_COUNT(hs))
     932             :     {
     933          18 :         HEntry     *entries = ARRPTR(hs);
     934             : 
     935          18 :         if (HSTORE_VALISNULL(entries, i))
     936             :         {
     937             :             ReturnSetInfo *rsi;
     938             : 
     939             :             /* ugly ugly ugly. why no macro for this? */
     940           2 :             (funcctx)->call_cntr++;
     941           2 :             rsi = (ReturnSetInfo *) fcinfo->resultinfo;
     942           2 :             rsi->isDone = ExprMultipleResult;
     943           2 :             PG_RETURN_NULL();
     944             :         }
     945             :         else
     946             :         {
     947             :             text       *item;
     948             : 
     949          16 :             item = cstring_to_text_with_len(HSTORE_VAL(entries, STRPTR(hs), i),
     950          16 :                                             HSTORE_VALLEN(entries, i));
     951             : 
     952          16 :             SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
     953             :         }
     954             :     }
     955             : 
     956           8 :     SRF_RETURN_DONE(funcctx);
     957             : }
     958             : 
     959             : 
     960          16 : PG_FUNCTION_INFO_V1(hstore_contains);
     961             : Datum
     962        7120 : hstore_contains(PG_FUNCTION_ARGS)
     963             : {
     964        7120 :     HStore     *val = PG_GETARG_HSTORE_P(0);
     965        7120 :     HStore     *tmpl = PG_GETARG_HSTORE_P(1);
     966        7120 :     bool        res = true;
     967        7120 :     HEntry     *te = ARRPTR(tmpl);
     968        7120 :     char       *tstr = STRPTR(tmpl);
     969        7120 :     HEntry     *ve = ARRPTR(val);
     970        7120 :     char       *vstr = STRPTR(val);
     971        7120 :     int         tcount = HS_COUNT(tmpl);
     972        7120 :     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       14296 :     for (i = 0; res && i < tcount; ++i)
     983             :     {
     984        7176 :         int         idx = hstoreFindKey(val, &lastidx,
     985        7176 :                                         HSTORE_KEY(te, tstr, i),
     986        7176 :                                         HSTORE_KEYLEN(te, i));
     987             : 
     988        7176 :         if (idx >= 0)
     989             :         {
     990        2166 :             bool        nullval = HSTORE_VALISNULL(te, i);
     991        2166 :             int         vallen = HSTORE_VALLEN(te, i);
     992             : 
     993        2166 :             if (nullval != HSTORE_VALISNULL(ve, idx) ||
     994        1026 :                 (!nullval && (vallen != HSTORE_VALLEN(ve, idx) ||
     995         610 :                               memcmp(HSTORE_VAL(te, tstr, i),
     996         610 :                                      HSTORE_VAL(ve, vstr, idx),
     997             :                                      vallen) != 0)))
     998        1960 :                 res = false;
     999             :         }
    1000             :         else
    1001        5010 :             res = false;
    1002             :     }
    1003             : 
    1004        7120 :     PG_RETURN_BOOL(res);
    1005             : }
    1006             : 
    1007             : 
    1008          14 : 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          16 : PG_FUNCTION_INFO_V1(hstore_each);
    1020             : Datum
    1021       23136 : hstore_each(PG_FUNCTION_ARGS)
    1022             : {
    1023             :     FuncCallContext *funcctx;
    1024             :     HStore     *hs;
    1025             :     int         i;
    1026             : 
    1027       23136 :     if (SRF_IS_FIRSTCALL())
    1028             :     {
    1029        4006 :         hs = PG_GETARG_HSTORE_P(0);
    1030        4006 :         funcctx = SRF_FIRSTCALL_INIT();
    1031        4006 :         setup_firstcall(funcctx, hs, fcinfo);
    1032             :     }
    1033             : 
    1034       23136 :     funcctx = SRF_PERCALL_SETUP();
    1035       23136 :     hs = (HStore *) funcctx->user_fctx;
    1036       23136 :     i = funcctx->call_cntr;
    1037             : 
    1038       23136 :     if (i < HS_COUNT(hs))
    1039             :     {
    1040       19130 :         HEntry     *entries = ARRPTR(hs);
    1041       19130 :         char       *ptr = STRPTR(hs);
    1042             :         Datum       res,
    1043             :                     dvalues[2];
    1044       19130 :         bool        nulls[2] = {false, false};
    1045             :         text       *item;
    1046             :         HeapTuple   tuple;
    1047             : 
    1048       19130 :         item = cstring_to_text_with_len(HSTORE_KEY(entries, ptr, i),
    1049       19130 :                                         HSTORE_KEYLEN(entries, i));
    1050       19130 :         dvalues[0] = PointerGetDatum(item);
    1051             : 
    1052       19130 :         if (HSTORE_VALISNULL(entries, i))
    1053             :         {
    1054           6 :             dvalues[1] = (Datum) 0;
    1055           6 :             nulls[1] = true;
    1056             :         }
    1057             :         else
    1058             :         {
    1059       19124 :             item = cstring_to_text_with_len(HSTORE_VAL(entries, ptr, i),
    1060       19124 :                                             HSTORE_VALLEN(entries, i));
    1061       19124 :             dvalues[1] = PointerGetDatum(item);
    1062             :         }
    1063             : 
    1064       19130 :         tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
    1065       19130 :         res = HeapTupleGetDatum(tuple);
    1066             : 
    1067       19130 :         SRF_RETURN_NEXT(funcctx, res);
    1068             :     }
    1069             : 
    1070        4006 :     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          16 : PG_FUNCTION_INFO_V1(hstore_cmp);
    1081             : Datum
    1082       86278 : hstore_cmp(PG_FUNCTION_ARGS)
    1083             : {
    1084       86278 :     HStore     *hs1 = PG_GETARG_HSTORE_P(0);
    1085       86278 :     HStore     *hs2 = PG_GETARG_HSTORE_P(1);
    1086       86278 :     int         hcount1 = HS_COUNT(hs1);
    1087       86278 :     int         hcount2 = HS_COUNT(hs2);
    1088       86278 :     int         res = 0;
    1089             : 
    1090       86278 :     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        7352 :         if (hcount1 > 0)
    1097         506 :             res = 1;
    1098        6846 :         else if (hcount2 > 0)
    1099        3270 :             res = -1;
    1100             :     }
    1101             :     else
    1102             :     {
    1103             :         /* here we know both operands are nonempty */
    1104       78926 :         char       *str1 = STRPTR(hs1);
    1105       78926 :         char       *str2 = STRPTR(hs2);
    1106       78926 :         HEntry     *ent1 = ARRPTR(hs1);
    1107       78926 :         HEntry     *ent2 = ARRPTR(hs2);
    1108       78926 :         size_t      len1 = HSE_ENDPOS(ent1[2 * hcount1 - 1]);
    1109       78926 :         size_t      len2 = HSE_ENDPOS(ent2[2 * hcount2 - 1]);
    1110             : 
    1111       78926 :         res = memcmp(str1, str2, Min(len1, len2));
    1112             : 
    1113       78926 :         if (res == 0)
    1114             :         {
    1115        5540 :             if (len1 > len2)
    1116           0 :                 res = 1;
    1117        5540 :             else if (len1 < len2)
    1118           0 :                 res = -1;
    1119        5540 :             else if (hcount1 > hcount2)
    1120           0 :                 res = 1;
    1121        5540 :             else if (hcount2 > hcount1)
    1122           0 :                 res = -1;
    1123             :             else
    1124             :             {
    1125        5540 :                 int         count = hcount1 * 2;
    1126             :                 int         i;
    1127             : 
    1128       65540 :                 for (i = 0; i < count; ++i)
    1129       60000 :                     if (HSE_ENDPOS(ent1[i]) != HSE_ENDPOS(ent2[i]) ||
    1130       60000 :                         HSE_ISNULL(ent1[i]) != HSE_ISNULL(ent2[i]))
    1131             :                         break;
    1132        5540 :                 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       73386 :             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       86278 :     PG_FREE_IF_COPY(hs1, 0);
    1156       86278 :     PG_FREE_IF_COPY(hs2, 1);
    1157       86278 :     PG_RETURN_INT32(res);
    1158             : }
    1159             : 
    1160             : 
    1161          16 : PG_FUNCTION_INFO_V1(hstore_eq);
    1162             : Datum
    1163        8242 : hstore_eq(PG_FUNCTION_ARGS)
    1164             : {
    1165        8242 :     int         res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
    1166             :                                                         PG_GETARG_DATUM(0),
    1167             :                                                         PG_GETARG_DATUM(1)));
    1168             : 
    1169        8242 :     PG_RETURN_BOOL(res == 0);
    1170             : }
    1171             : 
    1172          14 : 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          16 : PG_FUNCTION_INFO_V1(hstore_gt);
    1184             : Datum
    1185          10 : hstore_gt(PG_FUNCTION_ARGS)
    1186             : {
    1187          10 :     int         res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
    1188             :                                                         PG_GETARG_DATUM(0),
    1189             :                                                         PG_GETARG_DATUM(1)));
    1190             : 
    1191          10 :     PG_RETURN_BOOL(res > 0);
    1192             : }
    1193             : 
    1194          14 : 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          14 : 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          14 : 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          16 : PG_FUNCTION_INFO_V1(hstore_hash);
    1229             : Datum
    1230        4028 : hstore_hash(PG_FUNCTION_ARGS)
    1231             : {
    1232        4028 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
    1233        4028 :     Datum       hval = hash_any((unsigned char *) VARDATA(hs),
    1234        4028 :                                 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        4028 :     PG_FREE_IF_COPY(hs, 0);
    1249        4028 :     PG_RETURN_DATUM(hval);
    1250             : }
    1251             : 
    1252          16 : PG_FUNCTION_INFO_V1(hstore_hash_extended);
    1253             : Datum
    1254          20 : hstore_hash_extended(PG_FUNCTION_ARGS)
    1255             : {
    1256          20 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
    1257          20 :     uint64      seed = PG_GETARG_INT64(1);
    1258             :     Datum       hval;
    1259             : 
    1260          20 :     hval = hash_any_extended((unsigned char *) VARDATA(hs),
    1261          20 :                              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          20 :     PG_FREE_IF_COPY(hs, 0);
    1272          20 :     PG_RETURN_DATUM(hval);
    1273             : }

Generated by: LCOV version 1.14