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

Generated by: LCOV version 2.3.2-1