Header And Logo

PostgreSQL
| The world's most advanced open source database.

hstore_op.c

Go to the documentation of this file.
00001 /*
00002  * contrib/hstore/hstore_op.c
00003  */
00004 #include "postgres.h"
00005 
00006 #include "access/hash.h"
00007 #include "access/htup_details.h"
00008 #include "catalog/pg_type.h"
00009 #include "funcapi.h"
00010 #include "utils/builtins.h"
00011 
00012 #include "hstore.h"
00013 
00014 /* old names for C functions */
00015 HSTORE_POLLUTE(hstore_fetchval, fetchval);
00016 HSTORE_POLLUTE(hstore_exists, exists);
00017 HSTORE_POLLUTE(hstore_defined, defined);
00018 HSTORE_POLLUTE(hstore_delete, delete);
00019 HSTORE_POLLUTE(hstore_concat, hs_concat);
00020 HSTORE_POLLUTE(hstore_contains, hs_contains);
00021 HSTORE_POLLUTE(hstore_contained, hs_contained);
00022 HSTORE_POLLUTE(hstore_akeys, akeys);
00023 HSTORE_POLLUTE(hstore_avals, avals);
00024 HSTORE_POLLUTE(hstore_skeys, skeys);
00025 HSTORE_POLLUTE(hstore_svals, svals);
00026 HSTORE_POLLUTE(hstore_each, each);
00027 
00028 
00029 /*
00030  * We're often finding a sequence of keys in ascending order. The
00031  * "lowbound" parameter is used to cache lower bounds of searches
00032  * between calls, based on this assumption. Pass NULL for it for
00033  * one-off or unordered searches.
00034  */
00035 int
00036 hstoreFindKey(HStore *hs, int *lowbound, char *key, int keylen)
00037 {
00038     HEntry     *entries = ARRPTR(hs);
00039     int         stopLow = lowbound ? *lowbound : 0;
00040     int         stopHigh = HS_COUNT(hs);
00041     int         stopMiddle;
00042     char       *base = STRPTR(hs);
00043 
00044     while (stopLow < stopHigh)
00045     {
00046         int         difference;
00047 
00048         stopMiddle = stopLow + (stopHigh - stopLow) / 2;
00049 
00050         if (HS_KEYLEN(entries, stopMiddle) == keylen)
00051             difference = memcmp(HS_KEY(entries, base, stopMiddle), key, keylen);
00052         else
00053             difference = (HS_KEYLEN(entries, stopMiddle) > keylen) ? 1 : -1;
00054 
00055         if (difference == 0)
00056         {
00057             if (lowbound)
00058                 *lowbound = stopMiddle + 1;
00059             return stopMiddle;
00060         }
00061         else if (difference < 0)
00062             stopLow = stopMiddle + 1;
00063         else
00064             stopHigh = stopMiddle;
00065     }
00066 
00067     if (lowbound)
00068         *lowbound = stopLow;
00069     return -1;
00070 }
00071 
00072 Pairs *
00073 hstoreArrayToPairs(ArrayType *a, int *npairs)
00074 {
00075     Datum      *key_datums;
00076     bool       *key_nulls;
00077     int         key_count;
00078     Pairs      *key_pairs;
00079     int         bufsiz;
00080     int         i,
00081                 j;
00082 
00083     deconstruct_array(a,
00084                       TEXTOID, -1, false, 'i',
00085                       &key_datums, &key_nulls, &key_count);
00086 
00087     if (key_count == 0)
00088     {
00089         *npairs = 0;
00090         return NULL;
00091     }
00092 
00093     key_pairs = palloc(sizeof(Pairs) * key_count);
00094 
00095     for (i = 0, j = 0; i < key_count; i++)
00096     {
00097         if (!key_nulls[i])
00098         {
00099             key_pairs[j].key = VARDATA(key_datums[i]);
00100             key_pairs[j].keylen = VARSIZE(key_datums[i]) - VARHDRSZ;
00101             key_pairs[j].val = NULL;
00102             key_pairs[j].vallen = 0;
00103             key_pairs[j].needfree = 0;
00104             key_pairs[j].isnull = 1;
00105             j++;
00106         }
00107     }
00108 
00109     *npairs = hstoreUniquePairs(key_pairs, j, &bufsiz);
00110 
00111     return key_pairs;
00112 }
00113 
00114 
00115 PG_FUNCTION_INFO_V1(hstore_fetchval);
00116 Datum       hstore_fetchval(PG_FUNCTION_ARGS);
00117 Datum
00118 hstore_fetchval(PG_FUNCTION_ARGS)
00119 {
00120     HStore     *hs = PG_GETARG_HS(0);
00121     text       *key = PG_GETARG_TEXT_PP(1);
00122     HEntry     *entries = ARRPTR(hs);
00123     text       *out;
00124     int         idx = hstoreFindKey(hs, NULL,
00125                                     VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
00126 
00127     if (idx < 0 || HS_VALISNULL(entries, idx))
00128         PG_RETURN_NULL();
00129 
00130     out = cstring_to_text_with_len(HS_VAL(entries, STRPTR(hs), idx),
00131                                    HS_VALLEN(entries, idx));
00132 
00133     PG_RETURN_TEXT_P(out);
00134 }
00135 
00136 
00137 PG_FUNCTION_INFO_V1(hstore_exists);
00138 Datum       hstore_exists(PG_FUNCTION_ARGS);
00139 Datum
00140 hstore_exists(PG_FUNCTION_ARGS)
00141 {
00142     HStore     *hs = PG_GETARG_HS(0);
00143     text       *key = PG_GETARG_TEXT_PP(1);
00144     int         idx = hstoreFindKey(hs, NULL,
00145                                     VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
00146 
00147     PG_RETURN_BOOL(idx >= 0);
00148 }
00149 
00150 
00151 PG_FUNCTION_INFO_V1(hstore_exists_any);
00152 Datum       hstore_exists_any(PG_FUNCTION_ARGS);
00153 Datum
00154 hstore_exists_any(PG_FUNCTION_ARGS)
00155 {
00156     HStore     *hs = PG_GETARG_HS(0);
00157     ArrayType  *keys = PG_GETARG_ARRAYTYPE_P(1);
00158     int         nkeys;
00159     Pairs      *key_pairs = hstoreArrayToPairs(keys, &nkeys);
00160     int         i;
00161     int         lowbound = 0;
00162     bool        res = false;
00163 
00164     /*
00165      * we exploit the fact that the pairs list is already sorted into strictly
00166      * increasing order to narrow the hstoreFindKey search; each search can
00167      * start one entry past the previous "found" entry, or at the lower bound
00168      * of the last search.
00169      */
00170     for (i = 0; i < nkeys; i++)
00171     {
00172         int         idx = hstoreFindKey(hs, &lowbound,
00173                                       key_pairs[i].key, key_pairs[i].keylen);
00174 
00175         if (idx >= 0)
00176         {
00177             res = true;
00178             break;
00179         }
00180     }
00181 
00182     PG_RETURN_BOOL(res);
00183 }
00184 
00185 
00186 PG_FUNCTION_INFO_V1(hstore_exists_all);
00187 Datum       hstore_exists_all(PG_FUNCTION_ARGS);
00188 Datum
00189 hstore_exists_all(PG_FUNCTION_ARGS)
00190 {
00191     HStore     *hs = PG_GETARG_HS(0);
00192     ArrayType  *keys = PG_GETARG_ARRAYTYPE_P(1);
00193     int         nkeys;
00194     Pairs      *key_pairs = hstoreArrayToPairs(keys, &nkeys);
00195     int         i;
00196     int         lowbound = 0;
00197     bool        res = true;
00198 
00199     /*
00200      * we exploit the fact that the pairs list is already sorted into strictly
00201      * increasing order to narrow the hstoreFindKey search; each search can
00202      * start one entry past the previous "found" entry, or at the lower bound
00203      * of the last search.
00204      */
00205     for (i = 0; i < nkeys; i++)
00206     {
00207         int         idx = hstoreFindKey(hs, &lowbound,
00208                                       key_pairs[i].key, key_pairs[i].keylen);
00209 
00210         if (idx < 0)
00211         {
00212             res = false;
00213             break;
00214         }
00215     }
00216 
00217     PG_RETURN_BOOL(res);
00218 }
00219 
00220 
00221 PG_FUNCTION_INFO_V1(hstore_defined);
00222 Datum       hstore_defined(PG_FUNCTION_ARGS);
00223 Datum
00224 hstore_defined(PG_FUNCTION_ARGS)
00225 {
00226     HStore     *hs = PG_GETARG_HS(0);
00227     text       *key = PG_GETARG_TEXT_PP(1);
00228     HEntry     *entries = ARRPTR(hs);
00229     int         idx = hstoreFindKey(hs, NULL,
00230                                     VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
00231     bool        res = (idx >= 0 && !HS_VALISNULL(entries, idx));
00232 
00233     PG_RETURN_BOOL(res);
00234 }
00235 
00236 
00237 PG_FUNCTION_INFO_V1(hstore_delete);
00238 Datum       hstore_delete(PG_FUNCTION_ARGS);
00239 Datum
00240 hstore_delete(PG_FUNCTION_ARGS)
00241 {
00242     HStore     *hs = PG_GETARG_HS(0);
00243     text       *key = PG_GETARG_TEXT_PP(1);
00244     char       *keyptr = VARDATA_ANY(key);
00245     int         keylen = VARSIZE_ANY_EXHDR(key);
00246     HStore     *out = palloc(VARSIZE(hs));
00247     char       *bufs,
00248                *bufd,
00249                *ptrd;
00250     HEntry     *es,
00251                *ed;
00252     int         i;
00253     int         count = HS_COUNT(hs);
00254     int         outcount = 0;
00255 
00256     SET_VARSIZE(out, VARSIZE(hs));
00257     HS_SETCOUNT(out, count);    /* temporary! */
00258 
00259     bufs = STRPTR(hs);
00260     es = ARRPTR(hs);
00261     bufd = ptrd = STRPTR(out);
00262     ed = ARRPTR(out);
00263 
00264     for (i = 0; i < count; ++i)
00265     {
00266         int         len = HS_KEYLEN(es, i);
00267         char       *ptrs = HS_KEY(es, bufs, i);
00268 
00269         if (!(len == keylen && memcmp(ptrs, keyptr, keylen) == 0))
00270         {
00271             int         vallen = HS_VALLEN(es, i);
00272 
00273             HS_COPYITEM(ed, bufd, ptrd, ptrs, len, vallen, HS_VALISNULL(es, i));
00274             ++outcount;
00275         }
00276     }
00277 
00278     HS_FINALIZE(out, outcount, bufd, ptrd);
00279 
00280     PG_RETURN_POINTER(out);
00281 }
00282 
00283 
00284 PG_FUNCTION_INFO_V1(hstore_delete_array);
00285 Datum       hstore_delete_array(PG_FUNCTION_ARGS);
00286 Datum
00287 hstore_delete_array(PG_FUNCTION_ARGS)
00288 {
00289     HStore     *hs = PG_GETARG_HS(0);
00290     HStore     *out = palloc(VARSIZE(hs));
00291     int         hs_count = HS_COUNT(hs);
00292     char       *ps,
00293                *bufd,
00294                *pd;
00295     HEntry     *es,
00296                *ed;
00297     int         i,
00298                 j;
00299     int         outcount = 0;
00300     ArrayType  *key_array = PG_GETARG_ARRAYTYPE_P(1);
00301     int         nkeys;
00302     Pairs      *key_pairs = hstoreArrayToPairs(key_array, &nkeys);
00303 
00304     SET_VARSIZE(out, VARSIZE(hs));
00305     HS_SETCOUNT(out, hs_count); /* temporary! */
00306 
00307     ps = STRPTR(hs);
00308     es = ARRPTR(hs);
00309     bufd = pd = STRPTR(out);
00310     ed = ARRPTR(out);
00311 
00312     if (nkeys == 0)
00313     {
00314         /* return a copy of the input, unchanged */
00315         memcpy(out, hs, VARSIZE(hs));
00316         HS_FIXSIZE(out, hs_count);
00317         HS_SETCOUNT(out, hs_count);
00318         PG_RETURN_POINTER(out);
00319     }
00320 
00321     /*
00322      * this is in effect a merge between hs and key_pairs, both of which are
00323      * already sorted by (keylen,key); we take keys from hs only
00324      */
00325 
00326     for (i = j = 0; i < hs_count;)
00327     {
00328         int         difference;
00329 
00330         if (j >= nkeys)
00331             difference = -1;
00332         else
00333         {
00334             int         skeylen = HS_KEYLEN(es, i);
00335 
00336             if (skeylen == key_pairs[j].keylen)
00337                 difference = memcmp(HS_KEY(es, ps, i),
00338                                     key_pairs[j].key,
00339                                     key_pairs[j].keylen);
00340             else
00341                 difference = (skeylen > key_pairs[j].keylen) ? 1 : -1;
00342         }
00343 
00344         if (difference > 0)
00345             ++j;
00346         else if (difference == 0)
00347             ++i, ++j;
00348         else
00349         {
00350             HS_COPYITEM(ed, bufd, pd,
00351                         HS_KEY(es, ps, i), HS_KEYLEN(es, i),
00352                         HS_VALLEN(es, i), HS_VALISNULL(es, i));
00353             ++outcount;
00354             ++i;
00355         }
00356     }
00357 
00358     HS_FINALIZE(out, outcount, bufd, pd);
00359 
00360     PG_RETURN_POINTER(out);
00361 }
00362 
00363 
00364 PG_FUNCTION_INFO_V1(hstore_delete_hstore);
00365 Datum       hstore_delete_hstore(PG_FUNCTION_ARGS);
00366 Datum
00367 hstore_delete_hstore(PG_FUNCTION_ARGS)
00368 {
00369     HStore     *hs = PG_GETARG_HS(0);
00370     HStore     *hs2 = PG_GETARG_HS(1);
00371     HStore     *out = palloc(VARSIZE(hs));
00372     int         hs_count = HS_COUNT(hs);
00373     int         hs2_count = HS_COUNT(hs2);
00374     char       *ps,
00375                *ps2,
00376                *bufd,
00377                *pd;
00378     HEntry     *es,
00379                *es2,
00380                *ed;
00381     int         i,
00382                 j;
00383     int         outcount = 0;
00384 
00385     SET_VARSIZE(out, VARSIZE(hs));
00386     HS_SETCOUNT(out, hs_count); /* temporary! */
00387 
00388     ps = STRPTR(hs);
00389     es = ARRPTR(hs);
00390     ps2 = STRPTR(hs2);
00391     es2 = ARRPTR(hs2);
00392     bufd = pd = STRPTR(out);
00393     ed = ARRPTR(out);
00394 
00395     if (hs2_count == 0)
00396     {
00397         /* return a copy of the input, unchanged */
00398         memcpy(out, hs, VARSIZE(hs));
00399         HS_FIXSIZE(out, hs_count);
00400         HS_SETCOUNT(out, hs_count);
00401         PG_RETURN_POINTER(out);
00402     }
00403 
00404     /*
00405      * this is in effect a merge between hs and hs2, both of which are already
00406      * sorted by (keylen,key); we take keys from hs only; for equal keys, we
00407      * take the value from hs unless the values are equal
00408      */
00409 
00410     for (i = j = 0; i < hs_count;)
00411     {
00412         int         difference;
00413 
00414         if (j >= hs2_count)
00415             difference = -1;
00416         else
00417         {
00418             int         skeylen = HS_KEYLEN(es, i);
00419             int         s2keylen = HS_KEYLEN(es2, j);
00420 
00421             if (skeylen == s2keylen)
00422                 difference = memcmp(HS_KEY(es, ps, i),
00423                                     HS_KEY(es2, ps2, j),
00424                                     skeylen);
00425             else
00426                 difference = (skeylen > s2keylen) ? 1 : -1;
00427         }
00428 
00429         if (difference > 0)
00430             ++j;
00431         else if (difference == 0)
00432         {
00433             int         svallen = HS_VALLEN(es, i);
00434             int         snullval = HS_VALISNULL(es, i);
00435 
00436             if (snullval != HS_VALISNULL(es2, j)
00437                 || (!snullval
00438                     && (svallen != HS_VALLEN(es2, j)
00439             || memcmp(HS_VAL(es, ps, i), HS_VAL(es2, ps2, j), svallen) != 0)))
00440             {
00441                 HS_COPYITEM(ed, bufd, pd,
00442                             HS_KEY(es, ps, i), HS_KEYLEN(es, i),
00443                             svallen, snullval);
00444                 ++outcount;
00445             }
00446             ++i, ++j;
00447         }
00448         else
00449         {
00450             HS_COPYITEM(ed, bufd, pd,
00451                         HS_KEY(es, ps, i), HS_KEYLEN(es, i),
00452                         HS_VALLEN(es, i), HS_VALISNULL(es, i));
00453             ++outcount;
00454             ++i;
00455         }
00456     }
00457 
00458     HS_FINALIZE(out, outcount, bufd, pd);
00459 
00460     PG_RETURN_POINTER(out);
00461 }
00462 
00463 
00464 PG_FUNCTION_INFO_V1(hstore_concat);
00465 Datum       hstore_concat(PG_FUNCTION_ARGS);
00466 Datum
00467 hstore_concat(PG_FUNCTION_ARGS)
00468 {
00469     HStore     *s1 = PG_GETARG_HS(0);
00470     HStore     *s2 = PG_GETARG_HS(1);
00471     HStore     *out = palloc(VARSIZE(s1) + VARSIZE(s2));
00472     char       *ps1,
00473                *ps2,
00474                *bufd,
00475                *pd;
00476     HEntry     *es1,
00477                *es2,
00478                *ed;
00479     int         s1idx;
00480     int         s2idx;
00481     int         s1count = HS_COUNT(s1);
00482     int         s2count = HS_COUNT(s2);
00483     int         outcount = 0;
00484 
00485     SET_VARSIZE(out, VARSIZE(s1) + VARSIZE(s2) - HSHRDSIZE);
00486     HS_SETCOUNT(out, s1count + s2count);
00487 
00488     if (s1count == 0)
00489     {
00490         /* return a copy of the input, unchanged */
00491         memcpy(out, s2, VARSIZE(s2));
00492         HS_FIXSIZE(out, s2count);
00493         HS_SETCOUNT(out, s2count);
00494         PG_RETURN_POINTER(out);
00495     }
00496 
00497     if (s2count == 0)
00498     {
00499         /* return a copy of the input, unchanged */
00500         memcpy(out, s1, VARSIZE(s1));
00501         HS_FIXSIZE(out, s1count);
00502         HS_SETCOUNT(out, s1count);
00503         PG_RETURN_POINTER(out);
00504     }
00505 
00506     ps1 = STRPTR(s1);
00507     ps2 = STRPTR(s2);
00508     bufd = pd = STRPTR(out);
00509     es1 = ARRPTR(s1);
00510     es2 = ARRPTR(s2);
00511     ed = ARRPTR(out);
00512 
00513     /*
00514      * this is in effect a merge between s1 and s2, both of which are already
00515      * sorted by (keylen,key); we take s2 for equal keys
00516      */
00517 
00518     for (s1idx = s2idx = 0; s1idx < s1count || s2idx < s2count; ++outcount)
00519     {
00520         int         difference;
00521 
00522         if (s1idx >= s1count)
00523             difference = 1;
00524         else if (s2idx >= s2count)
00525             difference = -1;
00526         else
00527         {
00528             int         s1keylen = HS_KEYLEN(es1, s1idx);
00529             int         s2keylen = HS_KEYLEN(es2, s2idx);
00530 
00531             if (s1keylen == s2keylen)
00532                 difference = memcmp(HS_KEY(es1, ps1, s1idx),
00533                                     HS_KEY(es2, ps2, s2idx),
00534                                     s1keylen);
00535             else
00536                 difference = (s1keylen > s2keylen) ? 1 : -1;
00537         }
00538 
00539         if (difference >= 0)
00540         {
00541             HS_COPYITEM(ed, bufd, pd,
00542                         HS_KEY(es2, ps2, s2idx), HS_KEYLEN(es2, s2idx),
00543                         HS_VALLEN(es2, s2idx), HS_VALISNULL(es2, s2idx));
00544             ++s2idx;
00545             if (difference == 0)
00546                 ++s1idx;
00547         }
00548         else
00549         {
00550             HS_COPYITEM(ed, bufd, pd,
00551                         HS_KEY(es1, ps1, s1idx), HS_KEYLEN(es1, s1idx),
00552                         HS_VALLEN(es1, s1idx), HS_VALISNULL(es1, s1idx));
00553             ++s1idx;
00554         }
00555     }
00556 
00557     HS_FINALIZE(out, outcount, bufd, pd);
00558 
00559     PG_RETURN_POINTER(out);
00560 }
00561 
00562 
00563 PG_FUNCTION_INFO_V1(hstore_slice_to_array);
00564 Datum       hstore_slice_to_array(PG_FUNCTION_ARGS);
00565 Datum
00566 hstore_slice_to_array(PG_FUNCTION_ARGS)
00567 {
00568     HStore     *hs = PG_GETARG_HS(0);
00569     HEntry     *entries = ARRPTR(hs);
00570     char       *ptr = STRPTR(hs);
00571     ArrayType  *key_array = PG_GETARG_ARRAYTYPE_P(1);
00572     ArrayType  *aout;
00573     Datum      *key_datums;
00574     bool       *key_nulls;
00575     Datum      *out_datums;
00576     bool       *out_nulls;
00577     int         key_count;
00578     int         i;
00579 
00580     deconstruct_array(key_array,
00581                       TEXTOID, -1, false, 'i',
00582                       &key_datums, &key_nulls, &key_count);
00583 
00584     if (key_count == 0)
00585     {
00586         aout = construct_empty_array(TEXTOID);
00587         PG_RETURN_POINTER(aout);
00588     }
00589 
00590     out_datums = palloc(sizeof(Datum) * key_count);
00591     out_nulls = palloc(sizeof(bool) * key_count);
00592 
00593     for (i = 0; i < key_count; ++i)
00594     {
00595         text       *key = (text *) DatumGetPointer(key_datums[i]);
00596         int         idx;
00597 
00598         if (key_nulls[i])
00599             idx = -1;
00600         else
00601             idx = hstoreFindKey(hs, NULL, VARDATA(key), VARSIZE(key) - VARHDRSZ);
00602 
00603         if (idx < 0 || HS_VALISNULL(entries, idx))
00604         {
00605             out_nulls[i] = true;
00606             out_datums[i] = (Datum) 0;
00607         }
00608         else
00609         {
00610             out_datums[i] = PointerGetDatum(
00611                           cstring_to_text_with_len(HS_VAL(entries, ptr, idx),
00612                                                    HS_VALLEN(entries, idx)));
00613             out_nulls[i] = false;
00614         }
00615     }
00616 
00617     aout = construct_md_array(out_datums, out_nulls,
00618                               ARR_NDIM(key_array),
00619                               ARR_DIMS(key_array),
00620                               ARR_LBOUND(key_array),
00621                               TEXTOID, -1, false, 'i');
00622 
00623     PG_RETURN_POINTER(aout);
00624 }
00625 
00626 
00627 PG_FUNCTION_INFO_V1(hstore_slice_to_hstore);
00628 Datum       hstore_slice_to_hstore(PG_FUNCTION_ARGS);
00629 Datum
00630 hstore_slice_to_hstore(PG_FUNCTION_ARGS)
00631 {
00632     HStore     *hs = PG_GETARG_HS(0);
00633     HEntry     *entries = ARRPTR(hs);
00634     char       *ptr = STRPTR(hs);
00635     ArrayType  *key_array = PG_GETARG_ARRAYTYPE_P(1);
00636     HStore     *out;
00637     int         nkeys;
00638     Pairs      *key_pairs = hstoreArrayToPairs(key_array, &nkeys);
00639     Pairs      *out_pairs;
00640     int         bufsiz;
00641     int         lastidx = 0;
00642     int         i;
00643     int         out_count = 0;
00644 
00645     if (nkeys == 0)
00646     {
00647         out = hstorePairs(NULL, 0, 0);
00648         PG_RETURN_POINTER(out);
00649     }
00650 
00651     out_pairs = palloc(sizeof(Pairs) * nkeys);
00652     bufsiz = 0;
00653 
00654     /*
00655      * we exploit the fact that the pairs list is already sorted into strictly
00656      * increasing order to narrow the hstoreFindKey search; each search can
00657      * start one entry past the previous "found" entry, or at the lower bound
00658      * of the last search.
00659      */
00660 
00661     for (i = 0; i < nkeys; ++i)
00662     {
00663         int         idx = hstoreFindKey(hs, &lastidx,
00664                                       key_pairs[i].key, key_pairs[i].keylen);
00665 
00666         if (idx >= 0)
00667         {
00668             out_pairs[out_count].key = key_pairs[i].key;
00669             bufsiz += (out_pairs[out_count].keylen = key_pairs[i].keylen);
00670             out_pairs[out_count].val = HS_VAL(entries, ptr, idx);
00671             bufsiz += (out_pairs[out_count].vallen = HS_VALLEN(entries, idx));
00672             out_pairs[out_count].isnull = HS_VALISNULL(entries, idx);
00673             out_pairs[out_count].needfree = false;
00674             ++out_count;
00675         }
00676     }
00677 
00678     /*
00679      * we don't use uniquePairs here because we know that the pairs list is
00680      * already sorted and uniq'ed.
00681      */
00682 
00683     out = hstorePairs(out_pairs, out_count, bufsiz);
00684 
00685     PG_RETURN_POINTER(out);
00686 }
00687 
00688 
00689 PG_FUNCTION_INFO_V1(hstore_akeys);
00690 Datum       hstore_akeys(PG_FUNCTION_ARGS);
00691 Datum
00692 hstore_akeys(PG_FUNCTION_ARGS)
00693 {
00694     HStore     *hs = PG_GETARG_HS(0);
00695     Datum      *d;
00696     ArrayType  *a;
00697     HEntry     *entries = ARRPTR(hs);
00698     char       *base = STRPTR(hs);
00699     int         count = HS_COUNT(hs);
00700     int         i;
00701 
00702     if (count == 0)
00703     {
00704         a = construct_empty_array(TEXTOID);
00705         PG_RETURN_POINTER(a);
00706     }
00707 
00708     d = (Datum *) palloc(sizeof(Datum) * count);
00709 
00710     for (i = 0; i < count; ++i)
00711     {
00712         text       *item = cstring_to_text_with_len(HS_KEY(entries, base, i),
00713                                                     HS_KEYLEN(entries, i));
00714 
00715         d[i] = PointerGetDatum(item);
00716     }
00717 
00718     a = construct_array(d, count,
00719                         TEXTOID, -1, false, 'i');
00720 
00721     PG_RETURN_POINTER(a);
00722 }
00723 
00724 
00725 PG_FUNCTION_INFO_V1(hstore_avals);
00726 Datum       hstore_avals(PG_FUNCTION_ARGS);
00727 Datum
00728 hstore_avals(PG_FUNCTION_ARGS)
00729 {
00730     HStore     *hs = PG_GETARG_HS(0);
00731     Datum      *d;
00732     bool       *nulls;
00733     ArrayType  *a;
00734     HEntry     *entries = ARRPTR(hs);
00735     char       *base = STRPTR(hs);
00736     int         count = HS_COUNT(hs);
00737     int         lb = 1;
00738     int         i;
00739 
00740     if (count == 0)
00741     {
00742         a = construct_empty_array(TEXTOID);
00743         PG_RETURN_POINTER(a);
00744     }
00745 
00746     d = (Datum *) palloc(sizeof(Datum) * count);
00747     nulls = (bool *) palloc(sizeof(bool) * count);
00748 
00749     for (i = 0; i < count; ++i)
00750     {
00751         if (HS_VALISNULL(entries, i))
00752         {
00753             d[i] = (Datum) 0;
00754             nulls[i] = true;
00755         }
00756         else
00757         {
00758             text       *item = cstring_to_text_with_len(HS_VAL(entries, base, i),
00759                                                       HS_VALLEN(entries, i));
00760 
00761             d[i] = PointerGetDatum(item);
00762             nulls[i] = false;
00763         }
00764     }
00765 
00766     a = construct_md_array(d, nulls, 1, &count, &lb,
00767                            TEXTOID, -1, false, 'i');
00768 
00769     PG_RETURN_POINTER(a);
00770 }
00771 
00772 
00773 static ArrayType *
00774 hstore_to_array_internal(HStore *hs, int ndims)
00775 {
00776     HEntry     *entries = ARRPTR(hs);
00777     char       *base = STRPTR(hs);
00778     int         count = HS_COUNT(hs);
00779     int         out_size[2] = {0, 2};
00780     int         lb[2] = {1, 1};
00781     Datum      *out_datums;
00782     bool       *out_nulls;
00783     int         i;
00784 
00785     Assert(ndims < 3);
00786 
00787     if (count == 0 || ndims == 0)
00788         return construct_empty_array(TEXTOID);
00789 
00790     out_size[0] = count * 2 / ndims;
00791     out_datums = palloc(sizeof(Datum) * count * 2);
00792     out_nulls = palloc(sizeof(bool) * count * 2);
00793 
00794     for (i = 0; i < count; ++i)
00795     {
00796         text       *key = cstring_to_text_with_len(HS_KEY(entries, base, i),
00797                                                    HS_KEYLEN(entries, i));
00798 
00799         out_datums[i * 2] = PointerGetDatum(key);
00800         out_nulls[i * 2] = false;
00801 
00802         if (HS_VALISNULL(entries, i))
00803         {
00804             out_datums[i * 2 + 1] = (Datum) 0;
00805             out_nulls[i * 2 + 1] = true;
00806         }
00807         else
00808         {
00809             text       *item = cstring_to_text_with_len(HS_VAL(entries, base, i),
00810                                                       HS_VALLEN(entries, i));
00811 
00812             out_datums[i * 2 + 1] = PointerGetDatum(item);
00813             out_nulls[i * 2 + 1] = false;
00814         }
00815     }
00816 
00817     return construct_md_array(out_datums, out_nulls,
00818                               ndims, out_size, lb,
00819                               TEXTOID, -1, false, 'i');
00820 }
00821 
00822 PG_FUNCTION_INFO_V1(hstore_to_array);
00823 Datum       hstore_to_array(PG_FUNCTION_ARGS);
00824 Datum
00825 hstore_to_array(PG_FUNCTION_ARGS)
00826 {
00827     HStore     *hs = PG_GETARG_HS(0);
00828     ArrayType  *out = hstore_to_array_internal(hs, 1);
00829 
00830     PG_RETURN_POINTER(out);
00831 }
00832 
00833 PG_FUNCTION_INFO_V1(hstore_to_matrix);
00834 Datum       hstore_to_matrix(PG_FUNCTION_ARGS);
00835 Datum
00836 hstore_to_matrix(PG_FUNCTION_ARGS)
00837 {
00838     HStore     *hs = PG_GETARG_HS(0);
00839     ArrayType  *out = hstore_to_array_internal(hs, 2);
00840 
00841     PG_RETURN_POINTER(out);
00842 }
00843 
00844 /*
00845  * Common initialization function for the various set-returning
00846  * funcs. fcinfo is only passed if the function is to return a
00847  * composite; it will be used to look up the return tupledesc.
00848  * we stash a copy of the hstore in the multi-call context in
00849  * case it was originally toasted. (At least I assume that's why;
00850  * there was no explanatory comment in the original code. --AG)
00851  */
00852 
00853 static void
00854 setup_firstcall(FuncCallContext *funcctx, HStore *hs,
00855                 FunctionCallInfoData *fcinfo)
00856 {
00857     MemoryContext oldcontext;
00858     HStore     *st;
00859 
00860     oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
00861 
00862     st = (HStore *) palloc(VARSIZE(hs));
00863     memcpy(st, hs, VARSIZE(hs));
00864 
00865     funcctx->user_fctx = (void *) st;
00866 
00867     if (fcinfo)
00868     {
00869         TupleDesc   tupdesc;
00870 
00871         /* Build a tuple descriptor for our result type */
00872         if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
00873             elog(ERROR, "return type must be a row type");
00874 
00875         funcctx->tuple_desc = BlessTupleDesc(tupdesc);
00876     }
00877 
00878     MemoryContextSwitchTo(oldcontext);
00879 }
00880 
00881 
00882 PG_FUNCTION_INFO_V1(hstore_skeys);
00883 Datum       hstore_skeys(PG_FUNCTION_ARGS);
00884 Datum
00885 hstore_skeys(PG_FUNCTION_ARGS)
00886 {
00887     FuncCallContext *funcctx;
00888     HStore     *hs;
00889     int         i;
00890 
00891     if (SRF_IS_FIRSTCALL())
00892     {
00893         hs = PG_GETARG_HS(0);
00894         funcctx = SRF_FIRSTCALL_INIT();
00895         setup_firstcall(funcctx, hs, NULL);
00896     }
00897 
00898     funcctx = SRF_PERCALL_SETUP();
00899     hs = (HStore *) funcctx->user_fctx;
00900     i = funcctx->call_cntr;
00901 
00902     if (i < HS_COUNT(hs))
00903     {
00904         HEntry     *entries = ARRPTR(hs);
00905         text       *item;
00906 
00907         item = cstring_to_text_with_len(HS_KEY(entries, STRPTR(hs), i),
00908                                         HS_KEYLEN(entries, i));
00909 
00910         SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
00911     }
00912 
00913     SRF_RETURN_DONE(funcctx);
00914 }
00915 
00916 
00917 PG_FUNCTION_INFO_V1(hstore_svals);
00918 Datum       hstore_svals(PG_FUNCTION_ARGS);
00919 Datum
00920 hstore_svals(PG_FUNCTION_ARGS)
00921 {
00922     FuncCallContext *funcctx;
00923     HStore     *hs;
00924     int         i;
00925 
00926     if (SRF_IS_FIRSTCALL())
00927     {
00928         hs = PG_GETARG_HS(0);
00929         funcctx = SRF_FIRSTCALL_INIT();
00930         setup_firstcall(funcctx, hs, NULL);
00931     }
00932 
00933     funcctx = SRF_PERCALL_SETUP();
00934     hs = (HStore *) funcctx->user_fctx;
00935     i = funcctx->call_cntr;
00936 
00937     if (i < HS_COUNT(hs))
00938     {
00939         HEntry     *entries = ARRPTR(hs);
00940 
00941         if (HS_VALISNULL(entries, i))
00942         {
00943             ReturnSetInfo *rsi;
00944 
00945             /* ugly ugly ugly. why no macro for this? */
00946             (funcctx)->call_cntr++;
00947             rsi = (ReturnSetInfo *) fcinfo->resultinfo;
00948             rsi->isDone = ExprMultipleResult;
00949             PG_RETURN_NULL();
00950         }
00951         else
00952         {
00953             text       *item;
00954 
00955             item = cstring_to_text_with_len(HS_VAL(entries, STRPTR(hs), i),
00956                                             HS_VALLEN(entries, i));
00957 
00958             SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
00959         }
00960     }
00961 
00962     SRF_RETURN_DONE(funcctx);
00963 }
00964 
00965 
00966 PG_FUNCTION_INFO_V1(hstore_contains);
00967 Datum       hstore_contains(PG_FUNCTION_ARGS);
00968 Datum
00969 hstore_contains(PG_FUNCTION_ARGS)
00970 {
00971     HStore     *val = PG_GETARG_HS(0);
00972     HStore     *tmpl = PG_GETARG_HS(1);
00973     bool        res = true;
00974     HEntry     *te = ARRPTR(tmpl);
00975     char       *tstr = STRPTR(tmpl);
00976     HEntry     *ve = ARRPTR(val);
00977     char       *vstr = STRPTR(val);
00978     int         tcount = HS_COUNT(tmpl);
00979     int         lastidx = 0;
00980     int         i;
00981 
00982     /*
00983      * we exploit the fact that keys in "tmpl" are in strictly increasing
00984      * order to narrow the hstoreFindKey search; each search can start one
00985      * entry past the previous "found" entry, or at the lower bound of the
00986      * search
00987      */
00988 
00989     for (i = 0; res && i < tcount; ++i)
00990     {
00991         int         idx = hstoreFindKey(val, &lastidx,
00992                                       HS_KEY(te, tstr, i), HS_KEYLEN(te, i));
00993 
00994         if (idx >= 0)
00995         {
00996             bool        nullval = HS_VALISNULL(te, i);
00997             int         vallen = HS_VALLEN(te, i);
00998 
00999             if (nullval != HS_VALISNULL(ve, idx)
01000                 || (!nullval
01001                     && (vallen != HS_VALLEN(ve, idx)
01002              || memcmp(HS_VAL(te, tstr, i), HS_VAL(ve, vstr, idx), vallen))))
01003                 res = false;
01004         }
01005         else
01006             res = false;
01007     }
01008 
01009     PG_RETURN_BOOL(res);
01010 }
01011 
01012 
01013 PG_FUNCTION_INFO_V1(hstore_contained);
01014 Datum       hstore_contained(PG_FUNCTION_ARGS);
01015 Datum
01016 hstore_contained(PG_FUNCTION_ARGS)
01017 {
01018     PG_RETURN_DATUM(DirectFunctionCall2(hstore_contains,
01019                                         PG_GETARG_DATUM(1),
01020                                         PG_GETARG_DATUM(0)
01021                                         ));
01022 }
01023 
01024 
01025 PG_FUNCTION_INFO_V1(hstore_each);
01026 Datum       hstore_each(PG_FUNCTION_ARGS);
01027 Datum
01028 hstore_each(PG_FUNCTION_ARGS)
01029 {
01030     FuncCallContext *funcctx;
01031     HStore     *hs;
01032     int         i;
01033 
01034     if (SRF_IS_FIRSTCALL())
01035     {
01036         hs = PG_GETARG_HS(0);
01037         funcctx = SRF_FIRSTCALL_INIT();
01038         setup_firstcall(funcctx, hs, fcinfo);
01039     }
01040 
01041     funcctx = SRF_PERCALL_SETUP();
01042     hs = (HStore *) funcctx->user_fctx;
01043     i = funcctx->call_cntr;
01044 
01045     if (i < HS_COUNT(hs))
01046     {
01047         HEntry     *entries = ARRPTR(hs);
01048         char       *ptr = STRPTR(hs);
01049         Datum       res,
01050                     dvalues[2];
01051         bool        nulls[2] = {false, false};
01052         text       *item;
01053         HeapTuple   tuple;
01054 
01055         item = cstring_to_text_with_len(HS_KEY(entries, ptr, i),
01056                                         HS_KEYLEN(entries, i));
01057         dvalues[0] = PointerGetDatum(item);
01058 
01059         if (HS_VALISNULL(entries, i))
01060         {
01061             dvalues[1] = (Datum) 0;
01062             nulls[1] = true;
01063         }
01064         else
01065         {
01066             item = cstring_to_text_with_len(HS_VAL(entries, ptr, i),
01067                                             HS_VALLEN(entries, i));
01068             dvalues[1] = PointerGetDatum(item);
01069         }
01070 
01071         tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
01072         res = HeapTupleGetDatum(tuple);
01073 
01074         SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
01075     }
01076 
01077     SRF_RETURN_DONE(funcctx);
01078 }
01079 
01080 
01081 /*
01082  * btree sort order for hstores isn't intended to be useful; we really only
01083  * care about equality versus non-equality.  we compare the entire string
01084  * buffer first, then the entry pos array.
01085  */
01086 
01087 PG_FUNCTION_INFO_V1(hstore_cmp);
01088 Datum       hstore_cmp(PG_FUNCTION_ARGS);
01089 Datum
01090 hstore_cmp(PG_FUNCTION_ARGS)
01091 {
01092     HStore     *hs1 = PG_GETARG_HS(0);
01093     HStore     *hs2 = PG_GETARG_HS(1);
01094     int         hcount1 = HS_COUNT(hs1);
01095     int         hcount2 = HS_COUNT(hs2);
01096     int         res = 0;
01097 
01098     if (hcount1 == 0 || hcount2 == 0)
01099     {
01100         /*
01101          * if either operand is empty, and the other is nonempty, the nonempty
01102          * one is larger. If both are empty they are equal.
01103          */
01104         if (hcount1 > 0)
01105             res = 1;
01106         else if (hcount2 > 0)
01107             res = -1;
01108     }
01109     else
01110     {
01111         /* here we know both operands are nonempty */
01112         char       *str1 = STRPTR(hs1);
01113         char       *str2 = STRPTR(hs2);
01114         HEntry     *ent1 = ARRPTR(hs1);
01115         HEntry     *ent2 = ARRPTR(hs2);
01116         size_t      len1 = HSE_ENDPOS(ent1[2 * hcount1 - 1]);
01117         size_t      len2 = HSE_ENDPOS(ent2[2 * hcount2 - 1]);
01118 
01119         res = memcmp(str1, str2, Min(len1, len2));
01120 
01121         if (res == 0)
01122         {
01123             if (len1 > len2)
01124                 res = 1;
01125             else if (len1 < len2)
01126                 res = -1;
01127             else if (hcount1 > hcount2)
01128                 res = 1;
01129             else if (hcount2 > hcount1)
01130                 res = -1;
01131             else
01132             {
01133                 int         count = hcount1 * 2;
01134                 int         i;
01135 
01136                 for (i = 0; i < count; ++i)
01137                     if (HSE_ENDPOS(ent1[i]) != HSE_ENDPOS(ent2[i]) ||
01138                         HSE_ISNULL(ent1[i]) != HSE_ISNULL(ent2[i]))
01139                         break;
01140                 if (i < count)
01141                 {
01142                     if (HSE_ENDPOS(ent1[i]) < HSE_ENDPOS(ent2[i]))
01143                         res = -1;
01144                     else if (HSE_ENDPOS(ent1[i]) > HSE_ENDPOS(ent2[i]))
01145                         res = 1;
01146                     else if (HSE_ISNULL(ent1[i]))
01147                         res = 1;
01148                     else if (HSE_ISNULL(ent2[i]))
01149                         res = -1;
01150                 }
01151             }
01152         }
01153         else
01154         {
01155             res = (res > 0) ? 1 : -1;
01156         }
01157     }
01158 
01159     /*
01160      * this is a btree support function; this is one of the few places where
01161      * memory needs to be explicitly freed.
01162      */
01163     PG_FREE_IF_COPY(hs1, 0);
01164     PG_FREE_IF_COPY(hs2, 1);
01165     PG_RETURN_INT32(res);
01166 }
01167 
01168 
01169 PG_FUNCTION_INFO_V1(hstore_eq);
01170 Datum       hstore_eq(PG_FUNCTION_ARGS);
01171 Datum
01172 hstore_eq(PG_FUNCTION_ARGS)
01173 {
01174     int         res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
01175                                                         PG_GETARG_DATUM(0),
01176                                                         PG_GETARG_DATUM(1)));
01177 
01178     PG_RETURN_BOOL(res == 0);
01179 }
01180 
01181 PG_FUNCTION_INFO_V1(hstore_ne);
01182 Datum       hstore_ne(PG_FUNCTION_ARGS);
01183 Datum
01184 hstore_ne(PG_FUNCTION_ARGS)
01185 {
01186     int         res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
01187                                                         PG_GETARG_DATUM(0),
01188                                                         PG_GETARG_DATUM(1)));
01189 
01190     PG_RETURN_BOOL(res != 0);
01191 }
01192 
01193 PG_FUNCTION_INFO_V1(hstore_gt);
01194 Datum       hstore_gt(PG_FUNCTION_ARGS);
01195 Datum
01196 hstore_gt(PG_FUNCTION_ARGS)
01197 {
01198     int         res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
01199                                                         PG_GETARG_DATUM(0),
01200                                                         PG_GETARG_DATUM(1)));
01201 
01202     PG_RETURN_BOOL(res > 0);
01203 }
01204 
01205 PG_FUNCTION_INFO_V1(hstore_ge);
01206 Datum       hstore_ge(PG_FUNCTION_ARGS);
01207 Datum
01208 hstore_ge(PG_FUNCTION_ARGS)
01209 {
01210     int         res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
01211                                                         PG_GETARG_DATUM(0),
01212                                                         PG_GETARG_DATUM(1)));
01213 
01214     PG_RETURN_BOOL(res >= 0);
01215 }
01216 
01217 PG_FUNCTION_INFO_V1(hstore_lt);
01218 Datum       hstore_lt(PG_FUNCTION_ARGS);
01219 Datum
01220 hstore_lt(PG_FUNCTION_ARGS)
01221 {
01222     int         res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
01223                                                         PG_GETARG_DATUM(0),
01224                                                         PG_GETARG_DATUM(1)));
01225 
01226     PG_RETURN_BOOL(res < 0);
01227 }
01228 
01229 PG_FUNCTION_INFO_V1(hstore_le);
01230 Datum       hstore_le(PG_FUNCTION_ARGS);
01231 Datum
01232 hstore_le(PG_FUNCTION_ARGS)
01233 {
01234     int         res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
01235                                                         PG_GETARG_DATUM(0),
01236                                                         PG_GETARG_DATUM(1)));
01237 
01238     PG_RETURN_BOOL(res <= 0);
01239 }
01240 
01241 
01242 PG_FUNCTION_INFO_V1(hstore_hash);
01243 Datum       hstore_hash(PG_FUNCTION_ARGS);
01244 Datum
01245 hstore_hash(PG_FUNCTION_ARGS)
01246 {
01247     HStore     *hs = PG_GETARG_HS(0);
01248     Datum       hval = hash_any((unsigned char *) VARDATA(hs),
01249                                 VARSIZE(hs) - VARHDRSZ);
01250 
01251     /*
01252      * this is the only place in the code that cares whether the overall
01253      * varlena size exactly matches the true data size; this assertion should
01254      * be maintained by all the other code, but we make it explicit here.
01255      */
01256     Assert(VARSIZE(hs) ==
01257            (HS_COUNT(hs) != 0 ?
01258             CALCDATASIZE(HS_COUNT(hs),
01259                          HSE_ENDPOS(ARRPTR(hs)[2 * HS_COUNT(hs) - 1])) :
01260             HSHRDSIZE));
01261 
01262     PG_FREE_IF_COPY(hs, 0);
01263     PG_RETURN_DATUM(hval);
01264 }