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

Generated by: LCOV version 1.13