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

Generated by: LCOV version 1.14