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

Generated by: LCOV version 1.13