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

Generated by: LCOV version 1.14