LCOV - code coverage report
Current view: top level - contrib/hstore - hstore_io.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 546 645 84.7 %
Date: 2019-11-22 07:06:56 Functions: 33 37 89.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * contrib/hstore/hstore_io.c
       3             :  */
       4             : #include "postgres.h"
       5             : 
       6             : #include <ctype.h>
       7             : 
       8             : #include "access/htup_details.h"
       9             : #include "catalog/pg_type.h"
      10             : #include "funcapi.h"
      11             : #include "hstore.h"
      12             : #include "lib/stringinfo.h"
      13             : #include "libpq/pqformat.h"
      14             : #include "utils/builtins.h"
      15             : #include "utils/json.h"
      16             : #include "utils/jsonapi.h"
      17             : #include "utils/jsonb.h"
      18             : #include "utils/lsyscache.h"
      19             : #include "utils/memutils.h"
      20             : #include "utils/typcache.h"
      21             : 
      22          36 : PG_MODULE_MAGIC;
      23             : 
      24             : /* old names for C functions */
      25           0 : HSTORE_POLLUTE(hstore_from_text, tconvert);
      26             : 
      27             : 
      28             : typedef struct
      29             : {
      30             :     char       *begin;
      31             :     char       *ptr;
      32             :     char       *cur;
      33             :     char       *word;
      34             :     int         wordlen;
      35             : 
      36             :     Pairs      *pairs;
      37             :     int         pcur;
      38             :     int         plen;
      39             : } HSParser;
      40             : 
      41             : #define RESIZEPRSBUF \
      42             : do { \
      43             :         if ( state->cur - state->word + 1 >= state->wordlen ) \
      44             :         { \
      45             :                 int32 clen = state->cur - state->word; \
      46             :                 state->wordlen *= 2; \
      47             :                 state->word = (char*)repalloc( (void*)state->word, state->wordlen ); \
      48             :                 state->cur = state->word + clen; \
      49             :         } \
      50             : } while (0)
      51             : 
      52             : 
      53             : #define GV_WAITVAL 0
      54             : #define GV_INVAL 1
      55             : #define GV_INESCVAL 2
      56             : #define GV_WAITESCIN 3
      57             : #define GV_WAITESCESCIN 4
      58             : 
      59             : static bool
      60       21600 : get_val(HSParser *state, bool ignoreeq, bool *escaped)
      61             : {
      62       21600 :     int         st = GV_WAITVAL;
      63             : 
      64       21600 :     state->wordlen = 32;
      65       21600 :     state->cur = state->word = palloc(state->wordlen);
      66       21600 :     *escaped = false;
      67             : 
      68             :     while (1)
      69             :     {
      70      186320 :         if (st == GV_WAITVAL)
      71             :         {
      72       30118 :             if (*(state->ptr) == '"')
      73             :             {
      74         176 :                 *escaped = true;
      75         176 :                 st = GV_INESCVAL;
      76             :             }
      77       29942 :             else if (*(state->ptr) == '\0')
      78             :             {
      79         292 :                 return false;
      80             :             }
      81       29650 :             else if (*(state->ptr) == '=' && !ignoreeq)
      82             :             {
      83           0 :                 elog(ERROR, "Syntax error near '%c' at position %d", *(state->ptr), (int32) (state->ptr - state->begin));
      84             :             }
      85       29650 :             else if (*(state->ptr) == '\\')
      86             :             {
      87           4 :                 st = GV_WAITESCIN;
      88             :             }
      89       29646 :             else if (!isspace((unsigned char) *(state->ptr)))
      90             :             {
      91       21128 :                 *(state->cur) = *(state->ptr);
      92       21128 :                 state->cur++;
      93       21128 :                 st = GV_INVAL;
      94             :             }
      95             :         }
      96       73842 :         else if (st == GV_INVAL)
      97             :         {
      98       73042 :             if (*(state->ptr) == '\\')
      99             :             {
     100           2 :                 st = GV_WAITESCIN;
     101             :             }
     102       73040 :             else if (*(state->ptr) == '=' && !ignoreeq)
     103             :             {
     104       10506 :                 state->ptr--;
     105       10506 :                 return true;
     106             :             }
     107       62534 :             else if (*(state->ptr) == ',' && ignoreeq)
     108             :             {
     109        8260 :                 state->ptr--;
     110        8260 :                 return true;
     111             :             }
     112       54274 :             else if (isspace((unsigned char) *(state->ptr)))
     113             :             {
     114         180 :                 return true;
     115             :             }
     116       54094 :             else if (*(state->ptr) == '\0')
     117             :             {
     118        2186 :                 state->ptr--;
     119        2186 :                 return true;
     120             :             }
     121             :             else
     122             :             {
     123       51908 :                 RESIZEPRSBUF;
     124       51908 :                 *(state->cur) = *(state->ptr);
     125       51908 :                 state->cur++;
     126             :             }
     127             :         }
     128         800 :         else if (st == GV_INESCVAL)
     129             :         {
     130         792 :             if (*(state->ptr) == '\\')
     131             :             {
     132           2 :                 st = GV_WAITESCESCIN;
     133             :             }
     134         790 :             else if (*(state->ptr) == '"')
     135             :             {
     136         176 :                 return true;
     137             :             }
     138         614 :             else if (*(state->ptr) == '\0')
     139             :             {
     140           0 :                 elog(ERROR, "Unexpected end of string");
     141             :             }
     142             :             else
     143             :             {
     144         614 :                 RESIZEPRSBUF;
     145         614 :                 *(state->cur) = *(state->ptr);
     146         614 :                 state->cur++;
     147             :             }
     148             :         }
     149           8 :         else if (st == GV_WAITESCIN)
     150             :         {
     151           6 :             if (*(state->ptr) == '\0')
     152           0 :                 elog(ERROR, "Unexpected end of string");
     153           6 :             RESIZEPRSBUF;
     154           6 :             *(state->cur) = *(state->ptr);
     155           6 :             state->cur++;
     156           6 :             st = GV_INVAL;
     157             :         }
     158           2 :         else if (st == GV_WAITESCESCIN)
     159             :         {
     160           2 :             if (*(state->ptr) == '\0')
     161           0 :                 elog(ERROR, "Unexpected end of string");
     162           2 :             RESIZEPRSBUF;
     163           2 :             *(state->cur) = *(state->ptr);
     164           2 :             state->cur++;
     165           2 :             st = GV_INESCVAL;
     166             :         }
     167             :         else
     168           0 :             elog(ERROR, "Unknown state %d at position line %d in file '%s'", st, __LINE__, __FILE__);
     169             : 
     170       82360 :         state->ptr++;
     171             :     }
     172             : }
     173             : 
     174             : #define WKEY    0
     175             : #define WVAL    1
     176             : #define WEQ 2
     177             : #define WGT 3
     178             : #define WDEL    4
     179             : 
     180             : 
     181             : static void
     182        2544 : parse_hstore(HSParser *state)
     183             : {
     184        2544 :     int         st = WKEY;
     185        2544 :     bool        escaped = false;
     186             : 
     187        2544 :     state->plen = 16;
     188        2544 :     state->pairs = (Pairs *) palloc(sizeof(Pairs) * state->plen);
     189        2544 :     state->pcur = 0;
     190        2544 :     state->ptr = state->begin;
     191        2544 :     state->word = NULL;
     192             : 
     193             :     while (1)
     194             :     {
     195      104640 :         if (st == WKEY)
     196             :         {
     197       10946 :             if (!get_val(state, false, &escaped))
     198         292 :                 return;
     199       10654 :             if (state->pcur >= state->plen)
     200             :             {
     201           0 :                 state->plen *= 2;
     202           0 :                 state->pairs = (Pairs *) repalloc(state->pairs, sizeof(Pairs) * state->plen);
     203             :             }
     204       10654 :             state->pairs[state->pcur].key = state->word;
     205       10654 :             state->pairs[state->pcur].keylen = hstoreCheckKeyLen(state->cur - state->word);
     206       10654 :             state->pairs[state->pcur].val = NULL;
     207       10654 :             state->word = NULL;
     208       10654 :             st = WEQ;
     209             :         }
     210       42646 :         else if (st == WEQ)
     211             :         {
     212       10676 :             if (*(state->ptr) == '=')
     213             :             {
     214       10654 :                 st = WGT;
     215             :             }
     216          22 :             else if (*(state->ptr) == '\0')
     217             :             {
     218           0 :                 elog(ERROR, "Unexpected end of string");
     219             :             }
     220          22 :             else if (!isspace((unsigned char) *(state->ptr)))
     221             :             {
     222           0 :                 elog(ERROR, "Syntax error near '%c' at position %d", *(state->ptr), (int32) (state->ptr - state->begin));
     223             :             }
     224             :         }
     225       31970 :         else if (st == WGT)
     226             :         {
     227       10654 :             if (*(state->ptr) == '>')
     228             :             {
     229       10654 :                 st = WVAL;
     230             :             }
     231           0 :             else if (*(state->ptr) == '\0')
     232             :             {
     233           0 :                 elog(ERROR, "Unexpected end of string");
     234             :             }
     235             :             else
     236             :             {
     237           0 :                 elog(ERROR, "Syntax error near '%c' at position %d", *(state->ptr), (int32) (state->ptr - state->begin));
     238             :             }
     239             :         }
     240       21316 :         else if (st == WVAL)
     241             :         {
     242       10654 :             if (!get_val(state, true, &escaped))
     243           0 :                 elog(ERROR, "Unexpected end of string");
     244       10654 :             state->pairs[state->pcur].val = state->word;
     245       10654 :             state->pairs[state->pcur].vallen = hstoreCheckValLen(state->cur - state->word);
     246       10654 :             state->pairs[state->pcur].isnull = false;
     247       10654 :             state->pairs[state->pcur].needfree = true;
     248       10654 :             if (state->cur - state->word == 4 && !escaped)
     249             :             {
     250         144 :                 state->word[4] = '\0';
     251         144 :                 if (0 == pg_strcasecmp(state->word, "null"))
     252         136 :                     state->pairs[state->pcur].isnull = true;
     253             :             }
     254       10654 :             state->word = NULL;
     255       10654 :             state->pcur++;
     256       10654 :             st = WDEL;
     257             :         }
     258       10662 :         else if (st == WDEL)
     259             :         {
     260       10662 :             if (*(state->ptr) == ',')
     261             :             {
     262        8402 :                 st = WKEY;
     263             :             }
     264        2260 :             else if (*(state->ptr) == '\0')
     265             :             {
     266        2252 :                 return;
     267             :             }
     268           8 :             else if (!isspace((unsigned char) *(state->ptr)))
     269             :             {
     270           0 :                 elog(ERROR, "Syntax error near '%c' at position %d", *(state->ptr), (int32) (state->ptr - state->begin));
     271             :             }
     272             :         }
     273             :         else
     274           0 :             elog(ERROR, "Unknown state %d at line %d in file '%s'", st, __LINE__, __FILE__);
     275             : 
     276       51048 :         state->ptr++;
     277             :     }
     278             : }
     279             : 
     280             : static int
     281       24626 : comparePairs(const void *a, const void *b)
     282             : {
     283       24626 :     const Pairs *pa = a;
     284       24626 :     const Pairs *pb = b;
     285             : 
     286       24626 :     if (pa->keylen == pb->keylen)
     287             :     {
     288        5070 :         int         res = memcmp(pa->key, pb->key, pa->keylen);
     289             : 
     290        5070 :         if (res)
     291        5070 :             return res;
     292             : 
     293             :         /* guarantee that needfree will be later */
     294           0 :         if (pb->needfree == pa->needfree)
     295           0 :             return 0;
     296           0 :         else if (pa->needfree)
     297           0 :             return 1;
     298             :         else
     299           0 :             return -1;
     300             :     }
     301       19556 :     return (pa->keylen > pb->keylen) ? 1 : -1;
     302             : }
     303             : 
     304             : /*
     305             :  * this code still respects pairs.needfree, even though in general
     306             :  * it should never be called in a context where anything needs freeing.
     307             :  * we keep it because (a) those calls are in a rare code path anyway,
     308             :  * and (b) who knows whether they might be needed by some caller.
     309             :  */
     310             : int
     311        7522 : hstoreUniquePairs(Pairs *a, int32 l, int32 *buflen)
     312             : {
     313             :     Pairs      *ptr,
     314             :                *res;
     315             : 
     316        7522 :     *buflen = 0;
     317        7522 :     if (l < 2)
     318             :     {
     319         454 :         if (l == 1)
     320         158 :             *buflen = a->keylen + ((a->isnull) ? 0 : a->vallen);
     321         454 :         return l;
     322             :     }
     323             : 
     324        7068 :     qsort((void *) a, l, sizeof(Pairs), comparePairs);
     325             : 
     326             :     /*
     327             :      * We can't use qunique here because we have some clean-up code to run on
     328             :      * removed elements.
     329             :      */
     330        7068 :     ptr = a + 1;
     331        7068 :     res = a;
     332       27592 :     while (ptr - a < l)
     333             :     {
     334       17204 :         if (ptr->keylen == res->keylen &&
     335        3748 :             memcmp(ptr->key, res->key, res->keylen) == 0)
     336             :         {
     337           0 :             if (ptr->needfree)
     338             :             {
     339           0 :                 pfree(ptr->key);
     340           0 :                 pfree(ptr->val);
     341             :             }
     342             :         }
     343             :         else
     344             :         {
     345       13456 :             *buflen += res->keylen + ((res->isnull) ? 0 : res->vallen);
     346       13456 :             res++;
     347       13456 :             if (res != ptr)
     348           0 :                 memcpy(res, ptr, sizeof(Pairs));
     349             :         }
     350             : 
     351       13456 :         ptr++;
     352             :     }
     353             : 
     354        7068 :     *buflen += res->keylen + ((res->isnull) ? 0 : res->vallen);
     355        7068 :     return res + 1 - a;
     356             : }
     357             : 
     358             : size_t
     359       10910 : hstoreCheckKeyLen(size_t len)
     360             : {
     361       10910 :     if (len > HSTORE_MAX_KEY_LEN)
     362           0 :         ereport(ERROR,
     363             :                 (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
     364             :                  errmsg("string too long for hstore key")));
     365       10910 :     return len;
     366             : }
     367             : 
     368             : size_t
     369       10838 : hstoreCheckValLen(size_t len)
     370             : {
     371       10838 :     if (len > HSTORE_MAX_VALUE_LEN)
     372           0 :         ereport(ERROR,
     373             :                 (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
     374             :                  errmsg("string too long for hstore value")));
     375       10838 :     return len;
     376             : }
     377             : 
     378             : 
     379             : HStore *
     380        2692 : hstorePairs(Pairs *pairs, int32 pcount, int32 buflen)
     381             : {
     382             :     HStore     *out;
     383             :     HEntry     *entry;
     384             :     char       *ptr;
     385             :     char       *buf;
     386             :     int32       len;
     387             :     int32       i;
     388             : 
     389        2692 :     len = CALCDATASIZE(pcount, buflen);
     390        2692 :     out = palloc(len);
     391        2692 :     SET_VARSIZE(out, len);
     392        2692 :     HS_SETCOUNT(out, pcount);
     393             : 
     394        2692 :     if (pcount == 0)
     395         302 :         return out;
     396             : 
     397        2390 :     entry = ARRPTR(out);
     398        2390 :     buf = ptr = STRPTR(out);
     399             : 
     400       13324 :     for (i = 0; i < pcount; i++)
     401       10934 :         HS_ADDITEM(entry, buf, ptr, pairs[i]);
     402             : 
     403        2390 :     HS_FINALIZE(out, pcount, buf, ptr);
     404             : 
     405        2390 :     return out;
     406             : }
     407             : 
     408             : 
     409          30 : PG_FUNCTION_INFO_V1(hstore_in);
     410             : Datum
     411        2544 : hstore_in(PG_FUNCTION_ARGS)
     412             : {
     413             :     HSParser    state;
     414             :     int32       buflen;
     415             :     HStore     *out;
     416             : 
     417        2544 :     state.begin = PG_GETARG_CSTRING(0);
     418             : 
     419        2544 :     parse_hstore(&state);
     420             : 
     421        2544 :     state.pcur = hstoreUniquePairs(state.pairs, state.pcur, &buflen);
     422             : 
     423        2544 :     out = hstorePairs(state.pairs, state.pcur, buflen);
     424             : 
     425        2544 :     PG_RETURN_POINTER(out);
     426             : }
     427             : 
     428             : 
     429          16 : PG_FUNCTION_INFO_V1(hstore_recv);
     430             : Datum
     431           0 : hstore_recv(PG_FUNCTION_ARGS)
     432             : {
     433             :     int32       buflen;
     434             :     HStore     *out;
     435             :     Pairs      *pairs;
     436             :     int32       i;
     437             :     int32       pcount;
     438           0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     439             : 
     440           0 :     pcount = pq_getmsgint(buf, 4);
     441             : 
     442           0 :     if (pcount == 0)
     443             :     {
     444           0 :         out = hstorePairs(NULL, 0, 0);
     445           0 :         PG_RETURN_POINTER(out);
     446             :     }
     447             : 
     448           0 :     if (pcount < 0 || pcount > MaxAllocSize / sizeof(Pairs))
     449           0 :         ereport(ERROR,
     450             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     451             :                  errmsg("number of pairs (%d) exceeds the maximum allowed (%d)",
     452             :                         pcount, (int) (MaxAllocSize / sizeof(Pairs)))));
     453           0 :     pairs = palloc(pcount * sizeof(Pairs));
     454             : 
     455           0 :     for (i = 0; i < pcount; ++i)
     456             :     {
     457           0 :         int         rawlen = pq_getmsgint(buf, 4);
     458             :         int         len;
     459             : 
     460           0 :         if (rawlen < 0)
     461           0 :             ereport(ERROR,
     462             :                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
     463             :                      errmsg("null value not allowed for hstore key")));
     464             : 
     465           0 :         pairs[i].key = pq_getmsgtext(buf, rawlen, &len);
     466           0 :         pairs[i].keylen = hstoreCheckKeyLen(len);
     467           0 :         pairs[i].needfree = true;
     468             : 
     469           0 :         rawlen = pq_getmsgint(buf, 4);
     470           0 :         if (rawlen < 0)
     471             :         {
     472           0 :             pairs[i].val = NULL;
     473           0 :             pairs[i].vallen = 0;
     474           0 :             pairs[i].isnull = true;
     475             :         }
     476             :         else
     477             :         {
     478           0 :             pairs[i].val = pq_getmsgtext(buf, rawlen, &len);
     479           0 :             pairs[i].vallen = hstoreCheckValLen(len);
     480           0 :             pairs[i].isnull = false;
     481             :         }
     482             :     }
     483             : 
     484           0 :     pcount = hstoreUniquePairs(pairs, pcount, &buflen);
     485             : 
     486           0 :     out = hstorePairs(pairs, pcount, buflen);
     487             : 
     488           0 :     PG_RETURN_POINTER(out);
     489             : }
     490             : 
     491             : 
     492          30 : PG_FUNCTION_INFO_V1(hstore_from_text);
     493             : Datum
     494          72 : hstore_from_text(PG_FUNCTION_ARGS)
     495             : {
     496             :     text       *key;
     497          72 :     text       *val = NULL;
     498             :     Pairs       p;
     499             :     HStore     *out;
     500             : 
     501          72 :     if (PG_ARGISNULL(0))
     502           2 :         PG_RETURN_NULL();
     503             : 
     504          70 :     p.needfree = false;
     505          70 :     key = PG_GETARG_TEXT_PP(0);
     506          70 :     p.key = VARDATA_ANY(key);
     507          70 :     p.keylen = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(key));
     508             : 
     509          70 :     if (PG_ARGISNULL(1))
     510             :     {
     511          16 :         p.vallen = 0;
     512          16 :         p.isnull = true;
     513             :     }
     514             :     else
     515             :     {
     516          54 :         val = PG_GETARG_TEXT_PP(1);
     517          54 :         p.val = VARDATA_ANY(val);
     518          54 :         p.vallen = hstoreCheckValLen(VARSIZE_ANY_EXHDR(val));
     519          54 :         p.isnull = false;
     520             :     }
     521             : 
     522          70 :     out = hstorePairs(&p, 1, p.keylen + p.vallen);
     523             : 
     524          70 :     PG_RETURN_POINTER(out);
     525             : }
     526             : 
     527             : 
     528          16 : PG_FUNCTION_INFO_V1(hstore_from_arrays);
     529             : Datum
     530          20 : hstore_from_arrays(PG_FUNCTION_ARGS)
     531             : {
     532             :     int32       buflen;
     533             :     HStore     *out;
     534             :     Pairs      *pairs;
     535             :     Datum      *key_datums;
     536             :     bool       *key_nulls;
     537             :     int         key_count;
     538             :     Datum      *value_datums;
     539             :     bool       *value_nulls;
     540             :     int         value_count;
     541             :     ArrayType  *key_array;
     542             :     ArrayType  *value_array;
     543             :     int         i;
     544             : 
     545          20 :     if (PG_ARGISNULL(0))
     546           0 :         PG_RETURN_NULL();
     547             : 
     548          20 :     key_array = PG_GETARG_ARRAYTYPE_P(0);
     549             : 
     550             :     Assert(ARR_ELEMTYPE(key_array) == TEXTOID);
     551             : 
     552             :     /*
     553             :      * must check >1 rather than != 1 because empty arrays have 0 dimensions,
     554             :      * not 1
     555             :      */
     556             : 
     557          20 :     if (ARR_NDIM(key_array) > 1)
     558           0 :         ereport(ERROR,
     559             :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     560             :                  errmsg("wrong number of array subscripts")));
     561             : 
     562          20 :     deconstruct_array(key_array,
     563             :                       TEXTOID, -1, false, 'i',
     564             :                       &key_datums, &key_nulls, &key_count);
     565             : 
     566             :     /* see discussion in hstoreArrayToPairs() */
     567          20 :     if (key_count > MaxAllocSize / sizeof(Pairs))
     568           0 :         ereport(ERROR,
     569             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     570             :                  errmsg("number of pairs (%d) exceeds the maximum allowed (%d)",
     571             :                         key_count, (int) (MaxAllocSize / sizeof(Pairs)))));
     572             : 
     573             :     /* value_array might be NULL */
     574             : 
     575          20 :     if (PG_ARGISNULL(1))
     576             :     {
     577           4 :         value_array = NULL;
     578           4 :         value_count = key_count;
     579           4 :         value_datums = NULL;
     580           4 :         value_nulls = NULL;
     581             :     }
     582             :     else
     583             :     {
     584          16 :         value_array = PG_GETARG_ARRAYTYPE_P(1);
     585             : 
     586             :         Assert(ARR_ELEMTYPE(value_array) == TEXTOID);
     587             : 
     588          16 :         if (ARR_NDIM(value_array) > 1)
     589           0 :             ereport(ERROR,
     590             :                     (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     591             :                      errmsg("wrong number of array subscripts")));
     592             : 
     593          30 :         if ((ARR_NDIM(key_array) > 0 || ARR_NDIM(value_array) > 0) &&
     594          24 :             (ARR_NDIM(key_array) != ARR_NDIM(value_array) ||
     595          20 :              ARR_DIMS(key_array)[0] != ARR_DIMS(value_array)[0] ||
     596          10 :              ARR_LBOUND(key_array)[0] != ARR_LBOUND(value_array)[0]))
     597           4 :             ereport(ERROR,
     598             :                     (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     599             :                      errmsg("arrays must have same bounds")));
     600             : 
     601          12 :         deconstruct_array(value_array,
     602             :                           TEXTOID, -1, false, 'i',
     603             :                           &value_datums, &value_nulls, &value_count);
     604             : 
     605             :         Assert(key_count == value_count);
     606             :     }
     607             : 
     608          16 :     pairs = palloc(key_count * sizeof(Pairs));
     609             : 
     610          56 :     for (i = 0; i < key_count; ++i)
     611             :     {
     612          40 :         if (key_nulls[i])
     613           0 :             ereport(ERROR,
     614             :                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
     615             :                      errmsg("null value not allowed for hstore key")));
     616             : 
     617          40 :         if (!value_nulls || value_nulls[i])
     618             :         {
     619          18 :             pairs[i].key = VARDATA(key_datums[i]);
     620          18 :             pairs[i].val = NULL;
     621          36 :             pairs[i].keylen =
     622          18 :                 hstoreCheckKeyLen(VARSIZE(key_datums[i]) - VARHDRSZ);
     623          18 :             pairs[i].vallen = 4;
     624          18 :             pairs[i].isnull = true;
     625          18 :             pairs[i].needfree = false;
     626             :         }
     627             :         else
     628             :         {
     629          22 :             pairs[i].key = VARDATA(key_datums[i]);
     630          22 :             pairs[i].val = VARDATA(value_datums[i]);
     631          44 :             pairs[i].keylen =
     632          22 :                 hstoreCheckKeyLen(VARSIZE(key_datums[i]) - VARHDRSZ);
     633          44 :             pairs[i].vallen =
     634          22 :                 hstoreCheckValLen(VARSIZE(value_datums[i]) - VARHDRSZ);
     635          22 :             pairs[i].isnull = false;
     636          22 :             pairs[i].needfree = false;
     637             :         }
     638             :     }
     639             : 
     640          16 :     key_count = hstoreUniquePairs(pairs, key_count, &buflen);
     641             : 
     642          16 :     out = hstorePairs(pairs, key_count, buflen);
     643             : 
     644          16 :     PG_RETURN_POINTER(out);
     645             : }
     646             : 
     647             : 
     648          16 : PG_FUNCTION_INFO_V1(hstore_from_array);
     649             : Datum
     650          28 : hstore_from_array(PG_FUNCTION_ARGS)
     651             : {
     652          28 :     ArrayType  *in_array = PG_GETARG_ARRAYTYPE_P(0);
     653          28 :     int         ndims = ARR_NDIM(in_array);
     654             :     int         count;
     655             :     int32       buflen;
     656             :     HStore     *out;
     657             :     Pairs      *pairs;
     658             :     Datum      *in_datums;
     659             :     bool       *in_nulls;
     660             :     int         in_count;
     661             :     int         i;
     662             : 
     663             :     Assert(ARR_ELEMTYPE(in_array) == TEXTOID);
     664             : 
     665          28 :     switch (ndims)
     666             :     {
     667             :         case 0:
     668           4 :             out = hstorePairs(NULL, 0, 0);
     669           4 :             PG_RETURN_POINTER(out);
     670             : 
     671             :         case 1:
     672          10 :             if ((ARR_DIMS(in_array)[0]) % 2)
     673           4 :                 ereport(ERROR,
     674             :                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     675             :                          errmsg("array must have even number of elements")));
     676           6 :             break;
     677             : 
     678             :         case 2:
     679          10 :             if ((ARR_DIMS(in_array)[1]) != 2)
     680           4 :                 ereport(ERROR,
     681             :                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     682             :                          errmsg("array must have two columns")));
     683           6 :             break;
     684             : 
     685             :         default:
     686           4 :             ereport(ERROR,
     687             :                     (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     688             :                      errmsg("wrong number of array subscripts")));
     689             :     }
     690             : 
     691          12 :     deconstruct_array(in_array,
     692             :                       TEXTOID, -1, false, 'i',
     693             :                       &in_datums, &in_nulls, &in_count);
     694             : 
     695          12 :     count = in_count / 2;
     696             : 
     697             :     /* see discussion in hstoreArrayToPairs() */
     698          12 :     if (count > MaxAllocSize / sizeof(Pairs))
     699           0 :         ereport(ERROR,
     700             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     701             :                  errmsg("number of pairs (%d) exceeds the maximum allowed (%d)",
     702             :                         count, (int) (MaxAllocSize / sizeof(Pairs)))));
     703             : 
     704          12 :     pairs = palloc(count * sizeof(Pairs));
     705             : 
     706          48 :     for (i = 0; i < count; ++i)
     707             :     {
     708          36 :         if (in_nulls[i * 2])
     709           0 :             ereport(ERROR,
     710             :                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
     711             :                      errmsg("null value not allowed for hstore key")));
     712             : 
     713          36 :         if (in_nulls[i * 2 + 1])
     714             :         {
     715           0 :             pairs[i].key = VARDATA(in_datums[i * 2]);
     716           0 :             pairs[i].val = NULL;
     717           0 :             pairs[i].keylen =
     718           0 :                 hstoreCheckKeyLen(VARSIZE(in_datums[i * 2]) - VARHDRSZ);
     719           0 :             pairs[i].vallen = 4;
     720           0 :             pairs[i].isnull = true;
     721           0 :             pairs[i].needfree = false;
     722             :         }
     723             :         else
     724             :         {
     725          36 :             pairs[i].key = VARDATA(in_datums[i * 2]);
     726          36 :             pairs[i].val = VARDATA(in_datums[i * 2 + 1]);
     727          72 :             pairs[i].keylen =
     728          36 :                 hstoreCheckKeyLen(VARSIZE(in_datums[i * 2]) - VARHDRSZ);
     729          72 :             pairs[i].vallen =
     730          36 :                 hstoreCheckValLen(VARSIZE(in_datums[i * 2 + 1]) - VARHDRSZ);
     731          36 :             pairs[i].isnull = false;
     732          36 :             pairs[i].needfree = false;
     733             :         }
     734             :     }
     735             : 
     736          12 :     count = hstoreUniquePairs(pairs, count, &buflen);
     737             : 
     738          12 :     out = hstorePairs(pairs, count, buflen);
     739             : 
     740          12 :     PG_RETURN_POINTER(out);
     741             : }
     742             : 
     743             : /* most of hstore_from_record is shamelessly swiped from record_out */
     744             : 
     745             : /*
     746             :  * structure to cache metadata needed for record I/O
     747             :  */
     748             : typedef struct ColumnIOData
     749             : {
     750             :     Oid         column_type;
     751             :     Oid         typiofunc;
     752             :     Oid         typioparam;
     753             :     FmgrInfo    proc;
     754             : } ColumnIOData;
     755             : 
     756             : typedef struct RecordIOData
     757             : {
     758             :     Oid         record_type;
     759             :     int32       record_typmod;
     760             :     /* this field is used only if target type is domain over composite: */
     761             :     void       *domain_info;    /* opaque cache for domain checks */
     762             :     int         ncolumns;
     763             :     ColumnIOData columns[FLEXIBLE_ARRAY_MEMBER];
     764             : } RecordIOData;
     765             : 
     766          16 : PG_FUNCTION_INFO_V1(hstore_from_record);
     767             : Datum
     768          10 : hstore_from_record(PG_FUNCTION_ARGS)
     769             : {
     770             :     HeapTupleHeader rec;
     771             :     int32       buflen;
     772             :     HStore     *out;
     773             :     Pairs      *pairs;
     774             :     Oid         tupType;
     775             :     int32       tupTypmod;
     776             :     TupleDesc   tupdesc;
     777             :     HeapTupleData tuple;
     778             :     RecordIOData *my_extra;
     779             :     int         ncolumns;
     780             :     int         i,
     781             :                 j;
     782             :     Datum      *values;
     783             :     bool       *nulls;
     784             : 
     785          10 :     if (PG_ARGISNULL(0))
     786             :     {
     787           4 :         Oid         argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
     788             : 
     789             :         /*
     790             :          * We have no tuple to look at, so the only source of type info is the
     791             :          * argtype --- which might be domain over composite, but we don't care
     792             :          * here, since we have no need to be concerned about domain
     793             :          * constraints.  The lookup_rowtype_tupdesc_domain call below will
     794             :          * error out if we don't have a known composite type oid here.
     795             :          */
     796           4 :         tupType = argtype;
     797           4 :         tupTypmod = -1;
     798             : 
     799           4 :         rec = NULL;
     800             :     }
     801             :     else
     802             :     {
     803           6 :         rec = PG_GETARG_HEAPTUPLEHEADER(0);
     804             : 
     805             :         /*
     806             :          * Extract type info from the tuple itself -- this will work even for
     807             :          * anonymous record types.
     808             :          */
     809           6 :         tupType = HeapTupleHeaderGetTypeId(rec);
     810           6 :         tupTypmod = HeapTupleHeaderGetTypMod(rec);
     811             :     }
     812             : 
     813          10 :     tupdesc = lookup_rowtype_tupdesc_domain(tupType, tupTypmod, false);
     814          10 :     ncolumns = tupdesc->natts;
     815             : 
     816             :     /*
     817             :      * We arrange to look up the needed I/O info just once per series of
     818             :      * calls, assuming the record type doesn't change underneath us.
     819             :      */
     820          10 :     my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
     821          10 :     if (my_extra == NULL ||
     822           0 :         my_extra->ncolumns != ncolumns)
     823             :     {
     824          20 :         fcinfo->flinfo->fn_extra =
     825          10 :             MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
     826             :                                offsetof(RecordIOData, columns) +
     827          10 :                                ncolumns * sizeof(ColumnIOData));
     828          10 :         my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
     829          10 :         my_extra->record_type = InvalidOid;
     830          10 :         my_extra->record_typmod = 0;
     831             :     }
     832             : 
     833          10 :     if (my_extra->record_type != tupType ||
     834           0 :         my_extra->record_typmod != tupTypmod)
     835             :     {
     836          10 :         MemSet(my_extra, 0,
     837             :                offsetof(RecordIOData, columns) +
     838             :                ncolumns * sizeof(ColumnIOData));
     839          10 :         my_extra->record_type = tupType;
     840          10 :         my_extra->record_typmod = tupTypmod;
     841          10 :         my_extra->ncolumns = ncolumns;
     842             :     }
     843             : 
     844             :     Assert(ncolumns <= MaxTupleAttributeNumber); /* thus, no overflow */
     845          10 :     pairs = palloc(ncolumns * sizeof(Pairs));
     846             : 
     847          10 :     if (rec)
     848             :     {
     849             :         /* Build a temporary HeapTuple control structure */
     850           6 :         tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
     851           6 :         ItemPointerSetInvalid(&(tuple.t_self));
     852           6 :         tuple.t_tableOid = InvalidOid;
     853           6 :         tuple.t_data = rec;
     854             : 
     855           6 :         values = (Datum *) palloc(ncolumns * sizeof(Datum));
     856           6 :         nulls = (bool *) palloc(ncolumns * sizeof(bool));
     857             : 
     858             :         /* Break down the tuple into fields */
     859           6 :         heap_deform_tuple(&tuple, tupdesc, values, nulls);
     860             :     }
     861             :     else
     862             :     {
     863           4 :         values = NULL;
     864           4 :         nulls = NULL;
     865             :     }
     866             : 
     867          56 :     for (i = 0, j = 0; i < ncolumns; ++i)
     868             :     {
     869          46 :         ColumnIOData *column_info = &my_extra->columns[i];
     870          46 :         Form_pg_attribute att = TupleDescAttr(tupdesc, i);
     871          46 :         Oid         column_type = att->atttypid;
     872             :         char       *value;
     873             : 
     874             :         /* Ignore dropped columns in datatype */
     875          46 :         if (att->attisdropped)
     876           0 :             continue;
     877             : 
     878          46 :         pairs[j].key = NameStr(att->attname);
     879          46 :         pairs[j].keylen = hstoreCheckKeyLen(strlen(NameStr(att->attname)));
     880             : 
     881          46 :         if (!nulls || nulls[i])
     882             :         {
     883          18 :             pairs[j].val = NULL;
     884          18 :             pairs[j].vallen = 4;
     885          18 :             pairs[j].isnull = true;
     886          18 :             pairs[j].needfree = false;
     887          18 :             ++j;
     888          18 :             continue;
     889             :         }
     890             : 
     891             :         /*
     892             :          * Convert the column value to text
     893             :          */
     894          28 :         if (column_info->column_type != column_type)
     895             :         {
     896             :             bool        typIsVarlena;
     897             : 
     898          28 :             getTypeOutputInfo(column_type,
     899             :                               &column_info->typiofunc,
     900             :                               &typIsVarlena);
     901          28 :             fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
     902          28 :                           fcinfo->flinfo->fn_mcxt);
     903          28 :             column_info->column_type = column_type;
     904             :         }
     905             : 
     906          28 :         value = OutputFunctionCall(&column_info->proc, values[i]);
     907             : 
     908          28 :         pairs[j].val = value;
     909          28 :         pairs[j].vallen = hstoreCheckValLen(strlen(value));
     910          28 :         pairs[j].isnull = false;
     911          28 :         pairs[j].needfree = false;
     912          28 :         ++j;
     913             :     }
     914             : 
     915          10 :     ncolumns = hstoreUniquePairs(pairs, j, &buflen);
     916             : 
     917          10 :     out = hstorePairs(pairs, ncolumns, buflen);
     918             : 
     919          10 :     ReleaseTupleDesc(tupdesc);
     920             : 
     921          10 :     PG_RETURN_POINTER(out);
     922             : }
     923             : 
     924             : 
     925          16 : PG_FUNCTION_INFO_V1(hstore_populate_record);
     926             : Datum
     927          66 : hstore_populate_record(PG_FUNCTION_ARGS)
     928             : {
     929          66 :     Oid         argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
     930             :     HStore     *hs;
     931             :     HEntry     *entries;
     932             :     char       *ptr;
     933             :     HeapTupleHeader rec;
     934             :     Oid         tupType;
     935             :     int32       tupTypmod;
     936             :     TupleDesc   tupdesc;
     937             :     HeapTupleData tuple;
     938             :     HeapTuple   rettuple;
     939             :     RecordIOData *my_extra;
     940             :     int         ncolumns;
     941             :     int         i;
     942             :     Datum      *values;
     943             :     bool       *nulls;
     944             : 
     945          66 :     if (!type_is_rowtype(argtype))
     946           0 :         ereport(ERROR,
     947             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
     948             :                  errmsg("first argument must be a rowtype")));
     949             : 
     950          66 :     if (PG_ARGISNULL(0))
     951             :     {
     952          16 :         if (PG_ARGISNULL(1))
     953           0 :             PG_RETURN_NULL();
     954             : 
     955          16 :         rec = NULL;
     956             : 
     957             :         /*
     958             :          * We have no tuple to look at, so the only source of type info is the
     959             :          * argtype.  The lookup_rowtype_tupdesc_domain call below will error
     960             :          * out if we don't have a known composite type oid here.
     961             :          */
     962          16 :         tupType = argtype;
     963          16 :         tupTypmod = -1;
     964             :     }
     965             :     else
     966             :     {
     967          50 :         rec = PG_GETARG_HEAPTUPLEHEADER(0);
     968             : 
     969          50 :         if (PG_ARGISNULL(1))
     970           0 :             PG_RETURN_POINTER(rec);
     971             : 
     972             :         /*
     973             :          * Extract type info from the tuple itself -- this will work even for
     974             :          * anonymous record types.
     975             :          */
     976          50 :         tupType = HeapTupleHeaderGetTypeId(rec);
     977          50 :         tupTypmod = HeapTupleHeaderGetTypMod(rec);
     978             :     }
     979             : 
     980          66 :     hs = PG_GETARG_HSTORE_P(1);
     981          66 :     entries = ARRPTR(hs);
     982          66 :     ptr = STRPTR(hs);
     983             : 
     984             :     /*
     985             :      * if the input hstore is empty, we can only skip the rest if we were
     986             :      * passed in a non-null record, since otherwise there may be issues with
     987             :      * domain nulls.
     988             :      */
     989             : 
     990          66 :     if (HS_COUNT(hs) == 0 && rec)
     991           8 :         PG_RETURN_POINTER(rec);
     992             : 
     993             :     /*
     994             :      * Lookup the input record's tupdesc.  For the moment, we don't worry
     995             :      * about whether it is a domain over composite.
     996             :      */
     997          58 :     tupdesc = lookup_rowtype_tupdesc_domain(tupType, tupTypmod, false);
     998          58 :     ncolumns = tupdesc->natts;
     999             : 
    1000          58 :     if (rec)
    1001             :     {
    1002             :         /* Build a temporary HeapTuple control structure */
    1003          42 :         tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
    1004          42 :         ItemPointerSetInvalid(&(tuple.t_self));
    1005          42 :         tuple.t_tableOid = InvalidOid;
    1006          42 :         tuple.t_data = rec;
    1007             :     }
    1008             : 
    1009             :     /*
    1010             :      * We arrange to look up the needed I/O info just once per series of
    1011             :      * calls, assuming the record type doesn't change underneath us.
    1012             :      */
    1013          58 :     my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
    1014          66 :     if (my_extra == NULL ||
    1015           8 :         my_extra->ncolumns != ncolumns)
    1016             :     {
    1017         100 :         fcinfo->flinfo->fn_extra =
    1018          50 :             MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
    1019             :                                offsetof(RecordIOData, columns) +
    1020          50 :                                ncolumns * sizeof(ColumnIOData));
    1021          50 :         my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
    1022          50 :         my_extra->record_type = InvalidOid;
    1023          50 :         my_extra->record_typmod = 0;
    1024          50 :         my_extra->domain_info = NULL;
    1025             :     }
    1026             : 
    1027          66 :     if (my_extra->record_type != tupType ||
    1028           8 :         my_extra->record_typmod != tupTypmod)
    1029             :     {
    1030          50 :         MemSet(my_extra, 0,
    1031             :                offsetof(RecordIOData, columns) +
    1032             :                ncolumns * sizeof(ColumnIOData));
    1033          50 :         my_extra->record_type = tupType;
    1034          50 :         my_extra->record_typmod = tupTypmod;
    1035          50 :         my_extra->ncolumns = ncolumns;
    1036             :     }
    1037             : 
    1038          58 :     values = (Datum *) palloc(ncolumns * sizeof(Datum));
    1039          58 :     nulls = (bool *) palloc(ncolumns * sizeof(bool));
    1040             : 
    1041          58 :     if (rec)
    1042             :     {
    1043             :         /* Break down the tuple into fields */
    1044          42 :         heap_deform_tuple(&tuple, tupdesc, values, nulls);
    1045             :     }
    1046             :     else
    1047             :     {
    1048          92 :         for (i = 0; i < ncolumns; ++i)
    1049             :         {
    1050          76 :             values[i] = (Datum) 0;
    1051          76 :             nulls[i] = true;
    1052             :         }
    1053             :     }
    1054             : 
    1055         326 :     for (i = 0; i < ncolumns; ++i)
    1056             :     {
    1057         282 :         ColumnIOData *column_info = &my_extra->columns[i];
    1058         282 :         Form_pg_attribute att = TupleDescAttr(tupdesc, i);
    1059         282 :         Oid         column_type = att->atttypid;
    1060             :         char       *value;
    1061             :         int         idx;
    1062             :         int         vallen;
    1063             : 
    1064             :         /* Ignore dropped columns in datatype */
    1065         282 :         if (att->attisdropped)
    1066             :         {
    1067           0 :             nulls[i] = true;
    1068           0 :             continue;
    1069             :         }
    1070             : 
    1071         564 :         idx = hstoreFindKey(hs, 0,
    1072         282 :                             NameStr(att->attname),
    1073         282 :                             strlen(NameStr(att->attname)));
    1074             : 
    1075             :         /*
    1076             :          * we can't just skip here if the key wasn't found since we might have
    1077             :          * a domain to deal with. If we were passed in a non-null record
    1078             :          * datum, we assume that the existing values are valid (if they're
    1079             :          * not, then it's not our fault), but if we were passed in a null,
    1080             :          * then every field which we don't populate needs to be run through
    1081             :          * the input function just in case it's a domain type.
    1082             :          */
    1083         282 :         if (idx < 0 && rec)
    1084         158 :             continue;
    1085             : 
    1086             :         /*
    1087             :          * Prepare to convert the column value from text
    1088             :          */
    1089         124 :         if (column_info->column_type != column_type)
    1090             :         {
    1091         122 :             getTypeInputInfo(column_type,
    1092             :                              &column_info->typiofunc,
    1093             :                              &column_info->typioparam);
    1094         122 :             fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
    1095         122 :                           fcinfo->flinfo->fn_mcxt);
    1096         122 :             column_info->column_type = column_type;
    1097             :         }
    1098             : 
    1099         124 :         if (idx < 0 || HSTORE_VALISNULL(entries, idx))
    1100             :         {
    1101             :             /*
    1102             :              * need InputFunctionCall to happen even for nulls, so that domain
    1103             :              * checks are done
    1104             :              */
    1105          72 :             values[i] = InputFunctionCall(&column_info->proc, NULL,
    1106             :                                           column_info->typioparam,
    1107             :                                           att->atttypmod);
    1108          58 :             nulls[i] = true;
    1109             :         }
    1110             :         else
    1111             :         {
    1112          52 :             vallen = HSTORE_VALLEN(entries, idx);
    1113          52 :             value = palloc(1 + vallen);
    1114          52 :             memcpy(value, HSTORE_VAL(entries, ptr, idx), vallen);
    1115          52 :             value[vallen] = 0;
    1116             : 
    1117          52 :             values[i] = InputFunctionCall(&column_info->proc, value,
    1118             :                                           column_info->typioparam,
    1119             :                                           att->atttypmod);
    1120          52 :             nulls[i] = false;
    1121             :         }
    1122             :     }
    1123             : 
    1124          44 :     rettuple = heap_form_tuple(tupdesc, values, nulls);
    1125             : 
    1126             :     /*
    1127             :      * If the target type is domain over composite, all we know at this point
    1128             :      * is that we've made a valid value of the base composite type.  Must
    1129             :      * check domain constraints before deciding we're done.
    1130             :      */
    1131          44 :     if (argtype != tupdesc->tdtypeid)
    1132           0 :         domain_check(HeapTupleGetDatum(rettuple), false,
    1133             :                      argtype,
    1134             :                      &my_extra->domain_info,
    1135           0 :                      fcinfo->flinfo->fn_mcxt);
    1136             : 
    1137          44 :     ReleaseTupleDesc(tupdesc);
    1138             : 
    1139          44 :     PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
    1140             : }
    1141             : 
    1142             : 
    1143             : static char *
    1144         902 : cpw(char *dst, char *src, int len)
    1145             : {
    1146         902 :     char       *ptr = src;
    1147             : 
    1148        3344 :     while (ptr - src < len)
    1149             :     {
    1150        1540 :         if (*ptr == '"' || *ptr == '\\')
    1151           6 :             *dst++ = '\\';
    1152        1540 :         *dst++ = *ptr++;
    1153             :     }
    1154         902 :     return dst;
    1155             : }
    1156             : 
    1157          32 : PG_FUNCTION_INFO_V1(hstore_out);
    1158             : Datum
    1159         268 : hstore_out(PG_FUNCTION_ARGS)
    1160             : {
    1161         268 :     HStore     *in = PG_GETARG_HSTORE_P(0);
    1162             :     int         buflen,
    1163             :                 i;
    1164         268 :     int         count = HS_COUNT(in);
    1165             :     char       *out,
    1166             :                *ptr;
    1167         268 :     char       *base = STRPTR(in);
    1168         268 :     HEntry     *entries = ARRPTR(in);
    1169             : 
    1170         268 :     if (count == 0)
    1171          26 :         PG_RETURN_CSTRING(pstrdup(""));
    1172             : 
    1173         242 :     buflen = 0;
    1174             : 
    1175             :     /*
    1176             :      * this loop overestimates due to pessimistic assumptions about escaping,
    1177             :      * so very large hstore values can't be output. this could be fixed, but
    1178             :      * many other data types probably have the same issue. This replaced code
    1179             :      * that used the original varlena size for calculations, which was wrong
    1180             :      * in some subtle ways.
    1181             :      */
    1182             : 
    1183         726 :     for (i = 0; i < count; i++)
    1184             :     {
    1185             :         /* include "" and => and comma-space */
    1186         484 :         buflen += 6 + 2 * HSTORE_KEYLEN(entries, i);
    1187             :         /* include "" only if nonnull */
    1188        1320 :         buflen += 2 + (HSTORE_VALISNULL(entries, i)
    1189             :                        ? 2
    1190         836 :                        : 2 * HSTORE_VALLEN(entries, i));
    1191             :     }
    1192             : 
    1193         242 :     out = ptr = palloc(buflen);
    1194             : 
    1195         726 :     for (i = 0; i < count; i++)
    1196             :     {
    1197         484 :         *ptr++ = '"';
    1198         484 :         ptr = cpw(ptr, HSTORE_KEY(entries, base, i), HSTORE_KEYLEN(entries, i));
    1199         484 :         *ptr++ = '"';
    1200         484 :         *ptr++ = '=';
    1201         484 :         *ptr++ = '>';
    1202         484 :         if (HSTORE_VALISNULL(entries, i))
    1203             :         {
    1204          66 :             *ptr++ = 'N';
    1205          66 :             *ptr++ = 'U';
    1206          66 :             *ptr++ = 'L';
    1207          66 :             *ptr++ = 'L';
    1208             :         }
    1209             :         else
    1210             :         {
    1211         418 :             *ptr++ = '"';
    1212         418 :             ptr = cpw(ptr, HSTORE_VAL(entries, base, i), HSTORE_VALLEN(entries, i));
    1213         418 :             *ptr++ = '"';
    1214             :         }
    1215             : 
    1216         484 :         if (i + 1 != count)
    1217             :         {
    1218         242 :             *ptr++ = ',';
    1219         242 :             *ptr++ = ' ';
    1220             :         }
    1221             :     }
    1222         242 :     *ptr = '\0';
    1223             : 
    1224         242 :     PG_RETURN_CSTRING(out);
    1225             : }
    1226             : 
    1227             : 
    1228          14 : PG_FUNCTION_INFO_V1(hstore_send);
    1229             : Datum
    1230           0 : hstore_send(PG_FUNCTION_ARGS)
    1231             : {
    1232           0 :     HStore     *in = PG_GETARG_HSTORE_P(0);
    1233             :     int         i;
    1234           0 :     int         count = HS_COUNT(in);
    1235           0 :     char       *base = STRPTR(in);
    1236           0 :     HEntry     *entries = ARRPTR(in);
    1237             :     StringInfoData buf;
    1238             : 
    1239           0 :     pq_begintypsend(&buf);
    1240             : 
    1241           0 :     pq_sendint32(&buf, count);
    1242             : 
    1243           0 :     for (i = 0; i < count; i++)
    1244             :     {
    1245           0 :         int32       keylen = HSTORE_KEYLEN(entries, i);
    1246             : 
    1247           0 :         pq_sendint32(&buf, keylen);
    1248           0 :         pq_sendtext(&buf, HSTORE_KEY(entries, base, i), keylen);
    1249           0 :         if (HSTORE_VALISNULL(entries, i))
    1250             :         {
    1251           0 :             pq_sendint32(&buf, -1);
    1252             :         }
    1253             :         else
    1254             :         {
    1255           0 :             int32       vallen = HSTORE_VALLEN(entries, i);
    1256             : 
    1257           0 :             pq_sendint32(&buf, vallen);
    1258           0 :             pq_sendtext(&buf, HSTORE_VAL(entries, base, i), vallen);
    1259             :         }
    1260             :     }
    1261             : 
    1262           0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
    1263             : }
    1264             : 
    1265             : 
    1266             : /*
    1267             :  * hstore_to_json_loose
    1268             :  *
    1269             :  * This is a heuristic conversion to json which treats
    1270             :  * 't' and 'f' as booleans and strings that look like numbers as numbers,
    1271             :  * as long as they don't start with a leading zero followed by another digit
    1272             :  * (think zip codes or phone numbers starting with 0).
    1273             :  */
    1274          16 : PG_FUNCTION_INFO_V1(hstore_to_json_loose);
    1275             : Datum
    1276           6 : hstore_to_json_loose(PG_FUNCTION_ARGS)
    1277             : {
    1278           6 :     HStore     *in = PG_GETARG_HSTORE_P(0);
    1279             :     int         i;
    1280           6 :     int         count = HS_COUNT(in);
    1281           6 :     char       *base = STRPTR(in);
    1282           6 :     HEntry     *entries = ARRPTR(in);
    1283             :     StringInfoData tmp,
    1284             :                 dst;
    1285             : 
    1286           6 :     if (count == 0)
    1287           0 :         PG_RETURN_TEXT_P(cstring_to_text_with_len("{}", 2));
    1288             : 
    1289           6 :     initStringInfo(&tmp);
    1290           6 :     initStringInfo(&dst);
    1291             : 
    1292           6 :     appendStringInfoChar(&dst, '{');
    1293             : 
    1294          50 :     for (i = 0; i < count; i++)
    1295             :     {
    1296          44 :         resetStringInfo(&tmp);
    1297          88 :         appendBinaryStringInfo(&tmp, HSTORE_KEY(entries, base, i),
    1298          88 :                                HSTORE_KEYLEN(entries, i));
    1299          44 :         escape_json(&dst, tmp.data);
    1300          44 :         appendStringInfoString(&dst, ": ");
    1301          44 :         if (HSTORE_VALISNULL(entries, i))
    1302           4 :             appendStringInfoString(&dst, "null");
    1303             :         /* guess that values of 't' or 'f' are booleans */
    1304          52 :         else if (HSTORE_VALLEN(entries, i) == 1 &&
    1305          12 :                  *(HSTORE_VAL(entries, base, i)) == 't')
    1306           4 :             appendStringInfoString(&dst, "true");
    1307          44 :         else if (HSTORE_VALLEN(entries, i) == 1 &&
    1308           8 :                  *(HSTORE_VAL(entries, base, i)) == 'f')
    1309           2 :             appendStringInfoString(&dst, "false");
    1310             :         else
    1311             :         {
    1312          34 :             resetStringInfo(&tmp);
    1313          68 :             appendBinaryStringInfo(&tmp, HSTORE_VAL(entries, base, i),
    1314          68 :                                    HSTORE_VALLEN(entries, i));
    1315          34 :             if (IsValidJsonNumber(tmp.data, tmp.len))
    1316          24 :                 appendBinaryStringInfo(&dst, tmp.data, tmp.len);
    1317             :             else
    1318          10 :                 escape_json(&dst, tmp.data);
    1319             :         }
    1320             : 
    1321          44 :         if (i + 1 != count)
    1322          38 :             appendStringInfoString(&dst, ", ");
    1323             :     }
    1324           6 :     appendStringInfoChar(&dst, '}');
    1325             : 
    1326           6 :     PG_RETURN_TEXT_P(cstring_to_text(dst.data));
    1327             : }
    1328             : 
    1329          16 : PG_FUNCTION_INFO_V1(hstore_to_json);
    1330             : Datum
    1331           8 : hstore_to_json(PG_FUNCTION_ARGS)
    1332             : {
    1333           8 :     HStore     *in = PG_GETARG_HSTORE_P(0);
    1334             :     int         i;
    1335           8 :     int         count = HS_COUNT(in);
    1336           8 :     char       *base = STRPTR(in);
    1337           8 :     HEntry     *entries = ARRPTR(in);
    1338             :     StringInfoData tmp,
    1339             :                 dst;
    1340             : 
    1341           8 :     if (count == 0)
    1342           0 :         PG_RETURN_TEXT_P(cstring_to_text_with_len("{}", 2));
    1343             : 
    1344           8 :     initStringInfo(&tmp);
    1345           8 :     initStringInfo(&dst);
    1346             : 
    1347           8 :     appendStringInfoChar(&dst, '{');
    1348             : 
    1349          64 :     for (i = 0; i < count; i++)
    1350             :     {
    1351          56 :         resetStringInfo(&tmp);
    1352         112 :         appendBinaryStringInfo(&tmp, HSTORE_KEY(entries, base, i),
    1353         112 :                                HSTORE_KEYLEN(entries, i));
    1354          56 :         escape_json(&dst, tmp.data);
    1355          56 :         appendStringInfoString(&dst, ": ");
    1356          56 :         if (HSTORE_VALISNULL(entries, i))
    1357           6 :             appendStringInfoString(&dst, "null");
    1358             :         else
    1359             :         {
    1360          50 :             resetStringInfo(&tmp);
    1361         100 :             appendBinaryStringInfo(&tmp, HSTORE_VAL(entries, base, i),
    1362         100 :                                    HSTORE_VALLEN(entries, i));
    1363          50 :             escape_json(&dst, tmp.data);
    1364             :         }
    1365             : 
    1366          56 :         if (i + 1 != count)
    1367          48 :             appendStringInfoString(&dst, ", ");
    1368             :     }
    1369           8 :     appendStringInfoChar(&dst, '}');
    1370             : 
    1371           8 :     PG_RETURN_TEXT_P(cstring_to_text(dst.data));
    1372             : }
    1373             : 
    1374          16 : PG_FUNCTION_INFO_V1(hstore_to_jsonb);
    1375             : Datum
    1376           4 : hstore_to_jsonb(PG_FUNCTION_ARGS)
    1377             : {
    1378           4 :     HStore     *in = PG_GETARG_HSTORE_P(0);
    1379             :     int         i;
    1380           4 :     int         count = HS_COUNT(in);
    1381           4 :     char       *base = STRPTR(in);
    1382           4 :     HEntry     *entries = ARRPTR(in);
    1383           4 :     JsonbParseState *state = NULL;
    1384             :     JsonbValue *res;
    1385             : 
    1386           4 :     (void) pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
    1387             : 
    1388          32 :     for (i = 0; i < count; i++)
    1389             :     {
    1390             :         JsonbValue  key,
    1391             :                     val;
    1392             : 
    1393          28 :         key.type = jbvString;
    1394          28 :         key.val.string.len = HSTORE_KEYLEN(entries, i);
    1395          28 :         key.val.string.val = HSTORE_KEY(entries, base, i);
    1396             : 
    1397          28 :         (void) pushJsonbValue(&state, WJB_KEY, &key);
    1398             : 
    1399          28 :         if (HSTORE_VALISNULL(entries, i))
    1400             :         {
    1401           4 :             val.type = jbvNull;
    1402             :         }
    1403             :         else
    1404             :         {
    1405          24 :             val.type = jbvString;
    1406          24 :             val.val.string.len = HSTORE_VALLEN(entries, i);
    1407          24 :             val.val.string.val = HSTORE_VAL(entries, base, i);
    1408             :         }
    1409          28 :         (void) pushJsonbValue(&state, WJB_VALUE, &val);
    1410             :     }
    1411             : 
    1412           4 :     res = pushJsonbValue(&state, WJB_END_OBJECT, NULL);
    1413             : 
    1414           4 :     PG_RETURN_POINTER(JsonbValueToJsonb(res));
    1415             : }
    1416             : 
    1417          16 : PG_FUNCTION_INFO_V1(hstore_to_jsonb_loose);
    1418             : Datum
    1419           2 : hstore_to_jsonb_loose(PG_FUNCTION_ARGS)
    1420             : {
    1421           2 :     HStore     *in = PG_GETARG_HSTORE_P(0);
    1422             :     int         i;
    1423           2 :     int         count = HS_COUNT(in);
    1424           2 :     char       *base = STRPTR(in);
    1425           2 :     HEntry     *entries = ARRPTR(in);
    1426           2 :     JsonbParseState *state = NULL;
    1427             :     JsonbValue *res;
    1428             :     StringInfoData tmp;
    1429             : 
    1430           2 :     initStringInfo(&tmp);
    1431             : 
    1432           2 :     (void) pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
    1433             : 
    1434          18 :     for (i = 0; i < count; i++)
    1435             :     {
    1436             :         JsonbValue  key,
    1437             :                     val;
    1438             : 
    1439          16 :         key.type = jbvString;
    1440          16 :         key.val.string.len = HSTORE_KEYLEN(entries, i);
    1441          16 :         key.val.string.val = HSTORE_KEY(entries, base, i);
    1442             : 
    1443          16 :         (void) pushJsonbValue(&state, WJB_KEY, &key);
    1444             : 
    1445          16 :         if (HSTORE_VALISNULL(entries, i))
    1446             :         {
    1447           2 :             val.type = jbvNull;
    1448             :         }
    1449             :         /* guess that values of 't' or 'f' are booleans */
    1450          18 :         else if (HSTORE_VALLEN(entries, i) == 1 &&
    1451           4 :                  *(HSTORE_VAL(entries, base, i)) == 't')
    1452             :         {
    1453           2 :             val.type = jbvBool;
    1454           2 :             val.val.boolean = true;
    1455             :         }
    1456          14 :         else if (HSTORE_VALLEN(entries, i) == 1 &&
    1457           2 :                  *(HSTORE_VAL(entries, base, i)) == 'f')
    1458             :         {
    1459           0 :             val.type = jbvBool;
    1460           0 :             val.val.boolean = false;
    1461             :         }
    1462             :         else
    1463             :         {
    1464          12 :             resetStringInfo(&tmp);
    1465          24 :             appendBinaryStringInfo(&tmp, HSTORE_VAL(entries, base, i),
    1466          24 :                                    HSTORE_VALLEN(entries, i));
    1467          12 :             if (IsValidJsonNumber(tmp.data, tmp.len))
    1468             :             {
    1469             :                 Datum       numd;
    1470             : 
    1471           8 :                 val.type = jbvNumeric;
    1472           8 :                 numd = DirectFunctionCall3(numeric_in,
    1473             :                                            CStringGetDatum(tmp.data),
    1474             :                                            ObjectIdGetDatum(InvalidOid),
    1475             :                                            Int32GetDatum(-1));
    1476           8 :                 val.val.numeric = DatumGetNumeric(numd);
    1477             :             }
    1478             :             else
    1479             :             {
    1480           4 :                 val.type = jbvString;
    1481           4 :                 val.val.string.len = HSTORE_VALLEN(entries, i);
    1482           4 :                 val.val.string.val = HSTORE_VAL(entries, base, i);
    1483             :             }
    1484             :         }
    1485          16 :         (void) pushJsonbValue(&state, WJB_VALUE, &val);
    1486             :     }
    1487             : 
    1488           2 :     res = pushJsonbValue(&state, WJB_END_OBJECT, NULL);
    1489             : 
    1490           2 :     PG_RETURN_POINTER(JsonbValueToJsonb(res));
    1491             : }

Generated by: LCOV version 1.13