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

Generated by: LCOV version 1.13