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

Generated by: LCOV version 2.0-1