LCOV - code coverage report
Current view: top level - contrib/hstore - hstore_io.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 853 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 41 0
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            0 : 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            0 : prssyntaxerror(HSParser *state)
      66              : {
      67            0 :         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            0 :         return false;
      74              : }
      75              : 
      76              : #define PRSEOF return prseof(state)
      77              : 
      78              : static bool
      79            0 : prseof(HSParser *state)
      80              : {
      81            0 :         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            0 : get_val(HSParser *state, bool ignoreeq, bool *escaped)
      97              : {
      98            0 :         int                     st = GV_WAITVAL;
      99              : 
     100            0 :         state->wordlen = 32;
     101            0 :         state->cur = state->word = palloc(state->wordlen);
     102            0 :         *escaped = false;
     103              : 
     104            0 :         while (1)
     105              :         {
     106            0 :                 if (st == GV_WAITVAL)
     107              :                 {
     108            0 :                         if (*(state->ptr) == '"')
     109              :                         {
     110            0 :                                 *escaped = true;
     111            0 :                                 st = GV_INESCVAL;
     112            0 :                         }
     113            0 :                         else if (*(state->ptr) == '\0')
     114              :                         {
     115            0 :                                 return false;
     116              :                         }
     117            0 :                         else if (*(state->ptr) == '=' && !ignoreeq)
     118              :                         {
     119            0 :                                 PRSSYNTAXERROR;
     120              :                         }
     121            0 :                         else if (*(state->ptr) == '\\')
     122              :                         {
     123            0 :                                 st = GV_WAITESCIN;
     124            0 :                         }
     125            0 :                         else if (!scanner_isspace((unsigned char) *(state->ptr)))
     126              :                         {
     127            0 :                                 *(state->cur) = *(state->ptr);
     128            0 :                                 state->cur++;
     129            0 :                                 st = GV_INVAL;
     130            0 :                         }
     131            0 :                 }
     132            0 :                 else if (st == GV_INVAL)
     133              :                 {
     134            0 :                         if (*(state->ptr) == '\\')
     135              :                         {
     136            0 :                                 st = GV_WAITESCIN;
     137            0 :                         }
     138            0 :                         else if (*(state->ptr) == '=' && !ignoreeq)
     139              :                         {
     140            0 :                                 state->ptr--;
     141            0 :                                 return true;
     142              :                         }
     143            0 :                         else if (*(state->ptr) == ',' && ignoreeq)
     144              :                         {
     145            0 :                                 state->ptr--;
     146            0 :                                 return true;
     147              :                         }
     148            0 :                         else if (scanner_isspace((unsigned char) *(state->ptr)))
     149              :                         {
     150            0 :                                 return true;
     151              :                         }
     152            0 :                         else if (*(state->ptr) == '\0')
     153              :                         {
     154            0 :                                 state->ptr--;
     155            0 :                                 return true;
     156              :                         }
     157              :                         else
     158              :                         {
     159            0 :                                 RESIZEPRSBUF;
     160            0 :                                 *(state->cur) = *(state->ptr);
     161            0 :                                 state->cur++;
     162              :                         }
     163            0 :                 }
     164            0 :                 else if (st == GV_INESCVAL)
     165              :                 {
     166            0 :                         if (*(state->ptr) == '\\')
     167              :                         {
     168            0 :                                 st = GV_WAITESCESCIN;
     169            0 :                         }
     170            0 :                         else if (*(state->ptr) == '"')
     171              :                         {
     172            0 :                                 return true;
     173              :                         }
     174            0 :                         else if (*(state->ptr) == '\0')
     175              :                         {
     176            0 :                                 PRSEOF;
     177              :                         }
     178              :                         else
     179              :                         {
     180            0 :                                 RESIZEPRSBUF;
     181            0 :                                 *(state->cur) = *(state->ptr);
     182            0 :                                 state->cur++;
     183              :                         }
     184            0 :                 }
     185            0 :                 else if (st == GV_WAITESCIN)
     186              :                 {
     187            0 :                         if (*(state->ptr) == '\0')
     188            0 :                                 PRSEOF;
     189            0 :                         RESIZEPRSBUF;
     190            0 :                         *(state->cur) = *(state->ptr);
     191            0 :                         state->cur++;
     192            0 :                         st = GV_INVAL;
     193            0 :                 }
     194            0 :                 else if (st == GV_WAITESCESCIN)
     195              :                 {
     196            0 :                         if (*(state->ptr) == '\0')
     197            0 :                                 PRSEOF;
     198            0 :                         RESIZEPRSBUF;
     199            0 :                         *(state->cur) = *(state->ptr);
     200            0 :                         state->cur++;
     201            0 :                         st = GV_INESCVAL;
     202            0 :                 }
     203              :                 else
     204            0 :                         elog(ERROR, "unrecognized get_val state: %d", st);
     205              : 
     206            0 :                 state->ptr++;
     207              :         }
     208            0 : }
     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            0 : parse_hstore(HSParser *state)
     219              : {
     220            0 :         int                     st = WKEY;
     221            0 :         bool            escaped = false;
     222              : 
     223            0 :         state->plen = 16;
     224            0 :         state->pairs = palloc_array(Pairs, state->plen);
     225            0 :         state->pcur = 0;
     226            0 :         state->ptr = state->begin;
     227            0 :         state->word = NULL;
     228              : 
     229            0 :         while (1)
     230              :         {
     231            0 :                 if (st == WKEY)
     232              :                 {
     233            0 :                         if (!get_val(state, false, &escaped))
     234              :                         {
     235            0 :                                 if (SOFT_ERROR_OCCURRED(state->escontext))
     236            0 :                                         return false;
     237            0 :                                 return true;    /* EOF, all okay */
     238              :                         }
     239            0 :                         if (state->pcur >= state->plen)
     240              :                         {
     241            0 :                                 state->plen *= 2;
     242            0 :                                 state->pairs = (Pairs *) repalloc(state->pairs, sizeof(Pairs) * state->plen);
     243            0 :                         }
     244            0 :                         if (!hstoreCheckKeyLength(state->cur - state->word, state))
     245            0 :                                 return false;
     246            0 :                         state->pairs[state->pcur].key = state->word;
     247            0 :                         state->pairs[state->pcur].keylen = state->cur - state->word;
     248            0 :                         state->pairs[state->pcur].val = NULL;
     249            0 :                         state->word = NULL;
     250            0 :                         st = WEQ;
     251            0 :                 }
     252            0 :                 else if (st == WEQ)
     253              :                 {
     254            0 :                         if (*(state->ptr) == '=')
     255              :                         {
     256            0 :                                 st = WGT;
     257            0 :                         }
     258            0 :                         else if (*(state->ptr) == '\0')
     259              :                         {
     260            0 :                                 PRSEOF;
     261              :                         }
     262            0 :                         else if (!scanner_isspace((unsigned char) *(state->ptr)))
     263              :                         {
     264            0 :                                 PRSSYNTAXERROR;
     265              :                         }
     266            0 :                 }
     267            0 :                 else if (st == WGT)
     268              :                 {
     269            0 :                         if (*(state->ptr) == '>')
     270              :                         {
     271            0 :                                 st = WVAL;
     272            0 :                         }
     273            0 :                         else if (*(state->ptr) == '\0')
     274              :                         {
     275            0 :                                 PRSEOF;
     276              :                         }
     277              :                         else
     278              :                         {
     279            0 :                                 PRSSYNTAXERROR;
     280              :                         }
     281            0 :                 }
     282            0 :                 else if (st == WVAL)
     283              :                 {
     284            0 :                         if (!get_val(state, true, &escaped))
     285              :                         {
     286            0 :                                 if (SOFT_ERROR_OCCURRED(state->escontext))
     287            0 :                                         return false;
     288            0 :                                 PRSEOF;
     289              :                         }
     290            0 :                         if (!hstoreCheckValLength(state->cur - state->word, state))
     291            0 :                                 return false;
     292            0 :                         state->pairs[state->pcur].val = state->word;
     293            0 :                         state->pairs[state->pcur].vallen = state->cur - state->word;
     294            0 :                         state->pairs[state->pcur].isnull = false;
     295            0 :                         state->pairs[state->pcur].needfree = true;
     296            0 :                         if (state->cur - state->word == 4 && !escaped)
     297              :                         {
     298            0 :                                 state->word[4] = '\0';
     299            0 :                                 if (pg_strcasecmp(state->word, "null") == 0)
     300            0 :                                         state->pairs[state->pcur].isnull = true;
     301            0 :                         }
     302            0 :                         state->word = NULL;
     303            0 :                         state->pcur++;
     304            0 :                         st = WDEL;
     305            0 :                 }
     306            0 :                 else if (st == WDEL)
     307              :                 {
     308            0 :                         if (*(state->ptr) == ',')
     309              :                         {
     310            0 :                                 st = WKEY;
     311            0 :                         }
     312            0 :                         else if (*(state->ptr) == '\0')
     313              :                         {
     314            0 :                                 return true;
     315              :                         }
     316            0 :                         else if (!scanner_isspace((unsigned char) *(state->ptr)))
     317              :                         {
     318            0 :                                 PRSSYNTAXERROR;
     319              :                         }
     320            0 :                 }
     321              :                 else
     322            0 :                         elog(ERROR, "unrecognized parse_hstore state: %d", st);
     323              : 
     324            0 :                 state->ptr++;
     325              :         }
     326            0 : }
     327              : 
     328              : static int
     329            0 : comparePairs(const void *a, const void *b)
     330              : {
     331            0 :         const Pairs *pa = a;
     332            0 :         const Pairs *pb = b;
     333              : 
     334            0 :         if (pa->keylen == pb->keylen)
     335              :         {
     336            0 :                 int                     res = memcmp(pa->key, pb->key, pa->keylen);
     337              : 
     338            0 :                 if (res)
     339            0 :                         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            0 :         }
     349            0 :         return (pa->keylen > pb->keylen) ? 1 : -1;
     350            0 : }
     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            0 : hstoreUniquePairs(Pairs *a, int32 l, int32 *buflen)
     360              : {
     361            0 :         Pairs      *ptr,
     362              :                            *res;
     363              : 
     364            0 :         *buflen = 0;
     365            0 :         if (l < 2)
     366              :         {
     367            0 :                 if (l == 1)
     368            0 :                         *buflen = a->keylen + ((a->isnull) ? 0 : a->vallen);
     369            0 :                 return l;
     370              :         }
     371              : 
     372            0 :         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            0 :         ptr = a + 1;
     379            0 :         res = a;
     380            0 :         while (ptr - a < l)
     381              :         {
     382            0 :                 if (ptr->keylen == res->keylen &&
     383            0 :                         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            0 :                         }
     390            0 :                 }
     391              :                 else
     392              :                 {
     393            0 :                         *buflen += res->keylen + ((res->isnull) ? 0 : res->vallen);
     394            0 :                         res++;
     395            0 :                         if (res != ptr)
     396            0 :                                 memcpy(res, ptr, sizeof(Pairs));
     397              :                 }
     398              : 
     399            0 :                 ptr++;
     400              :         }
     401              : 
     402            0 :         *buflen += res->keylen + ((res->isnull) ? 0 : res->vallen);
     403            0 :         return res + 1 - a;
     404            0 : }
     405              : 
     406              : size_t
     407            0 : hstoreCheckKeyLen(size_t len)
     408              : {
     409            0 :         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            0 :         return len;
     414              : }
     415              : 
     416              : static bool
     417            0 : hstoreCheckKeyLength(size_t len, HSParser *state)
     418              : {
     419            0 :         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            0 :         return true;
     424            0 : }
     425              : 
     426              : size_t
     427            0 : hstoreCheckValLen(size_t len)
     428              : {
     429            0 :         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            0 :         return len;
     434              : }
     435              : 
     436              : static bool
     437            0 : hstoreCheckValLength(size_t len, HSParser *state)
     438              : {
     439            0 :         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            0 :         return true;
     444            0 : }
     445              : 
     446              : 
     447              : HStore *
     448            0 : hstorePairs(Pairs *pairs, int32 pcount, int32 buflen)
     449              : {
     450            0 :         HStore     *out;
     451            0 :         HEntry     *entry;
     452            0 :         char       *ptr;
     453            0 :         char       *buf;
     454            0 :         int32           len;
     455            0 :         int32           i;
     456              : 
     457            0 :         len = CALCDATASIZE(pcount, buflen);
     458            0 :         out = palloc(len);
     459            0 :         SET_VARSIZE(out, len);
     460            0 :         HS_SETCOUNT(out, pcount);
     461              : 
     462            0 :         if (pcount == 0)
     463            0 :                 return out;
     464              : 
     465            0 :         entry = ARRPTR(out);
     466            0 :         buf = ptr = STRPTR(out);
     467              : 
     468            0 :         for (i = 0; i < pcount; i++)
     469            0 :                 HS_ADDITEM(entry, buf, ptr, pairs[i]);
     470              : 
     471            0 :         HS_FINALIZE(out, pcount, buf, ptr);
     472              : 
     473            0 :         return out;
     474            0 : }
     475              : 
     476              : 
     477            0 : PG_FUNCTION_INFO_V1(hstore_in);
     478              : Datum
     479            0 : hstore_in(PG_FUNCTION_ARGS)
     480              : {
     481            0 :         char       *str = PG_GETARG_CSTRING(0);
     482            0 :         Node       *escontext = fcinfo->context;
     483            0 :         HSParser        state;
     484            0 :         int32           buflen;
     485            0 :         HStore     *out;
     486              : 
     487            0 :         state.begin = str;
     488            0 :         state.escontext = escontext;
     489              : 
     490            0 :         if (!parse_hstore(&state))
     491            0 :                 PG_RETURN_NULL();
     492              : 
     493            0 :         state.pcur = hstoreUniquePairs(state.pairs, state.pcur, &buflen);
     494              : 
     495            0 :         out = hstorePairs(state.pairs, state.pcur, buflen);
     496              : 
     497            0 :         PG_RETURN_POINTER(out);
     498            0 : }
     499              : 
     500              : 
     501            0 : PG_FUNCTION_INFO_V1(hstore_recv);
     502              : Datum
     503            0 : hstore_recv(PG_FUNCTION_ARGS)
     504              : {
     505            0 :         int32           buflen;
     506            0 :         HStore     *out;
     507            0 :         Pairs      *pairs;
     508            0 :         int32           i;
     509            0 :         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            0 :                 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            0 :                 }
     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            0 :         }
     555              : 
     556            0 :         pcount = hstoreUniquePairs(pairs, pcount, &buflen);
     557              : 
     558            0 :         out = hstorePairs(pairs, pcount, buflen);
     559              : 
     560            0 :         PG_RETURN_POINTER(out);
     561            0 : }
     562              : 
     563              : 
     564            0 : PG_FUNCTION_INFO_V1(hstore_from_text);
     565              : Datum
     566            0 : hstore_from_text(PG_FUNCTION_ARGS)
     567              : {
     568            0 :         text       *key;
     569            0 :         text       *val = NULL;
     570            0 :         Pairs           p;
     571            0 :         HStore     *out;
     572              : 
     573            0 :         if (PG_ARGISNULL(0))
     574            0 :                 PG_RETURN_NULL();
     575              : 
     576            0 :         p.needfree = false;
     577            0 :         key = PG_GETARG_TEXT_PP(0);
     578            0 :         p.key = VARDATA_ANY(key);
     579            0 :         p.keylen = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(key));
     580              : 
     581            0 :         if (PG_ARGISNULL(1))
     582              :         {
     583            0 :                 p.vallen = 0;
     584            0 :                 p.isnull = true;
     585            0 :         }
     586              :         else
     587              :         {
     588            0 :                 val = PG_GETARG_TEXT_PP(1);
     589            0 :                 p.val = VARDATA_ANY(val);
     590            0 :                 p.vallen = hstoreCheckValLen(VARSIZE_ANY_EXHDR(val));
     591            0 :                 p.isnull = false;
     592              :         }
     593              : 
     594            0 :         out = hstorePairs(&p, 1, p.keylen + p.vallen);
     595              : 
     596            0 :         PG_RETURN_POINTER(out);
     597            0 : }
     598              : 
     599              : 
     600            0 : PG_FUNCTION_INFO_V1(hstore_from_arrays);
     601              : Datum
     602            0 : hstore_from_arrays(PG_FUNCTION_ARGS)
     603              : {
     604            0 :         int32           buflen;
     605            0 :         HStore     *out;
     606            0 :         Pairs      *pairs;
     607            0 :         Datum      *key_datums;
     608            0 :         bool       *key_nulls;
     609            0 :         int                     key_count;
     610            0 :         Datum      *value_datums;
     611            0 :         bool       *value_nulls;
     612            0 :         int                     value_count;
     613            0 :         ArrayType  *key_array;
     614            0 :         ArrayType  *value_array;
     615            0 :         int                     i;
     616              : 
     617            0 :         if (PG_ARGISNULL(0))
     618            0 :                 PG_RETURN_NULL();
     619              : 
     620            0 :         key_array = PG_GETARG_ARRAYTYPE_P(0);
     621              : 
     622            0 :         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            0 :         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            0 :         deconstruct_array_builtin(key_array, TEXTOID, &key_datums, &key_nulls, &key_count);
     635              : 
     636              :         /* see discussion in hstoreArrayToPairs() */
     637            0 :         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            0 :         if (PG_ARGISNULL(1))
     646              :         {
     647            0 :                 value_array = NULL;
     648            0 :                 value_count = key_count;
     649            0 :                 value_datums = NULL;
     650            0 :                 value_nulls = NULL;
     651            0 :         }
     652              :         else
     653              :         {
     654            0 :                 value_array = PG_GETARG_ARRAYTYPE_P(1);
     655              : 
     656            0 :                 Assert(ARR_ELEMTYPE(value_array) == TEXTOID);
     657              : 
     658            0 :                 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            0 :                 if ((ARR_NDIM(key_array) > 0 || ARR_NDIM(value_array) > 0) &&
     664            0 :                         (ARR_NDIM(key_array) != ARR_NDIM(value_array) ||
     665            0 :                          ARR_DIMS(key_array)[0] != ARR_DIMS(value_array)[0] ||
     666            0 :                          ARR_LBOUND(key_array)[0] != ARR_LBOUND(value_array)[0]))
     667            0 :                         ereport(ERROR,
     668              :                                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     669              :                                          errmsg("arrays must have same bounds")));
     670              : 
     671            0 :                 deconstruct_array_builtin(value_array, TEXTOID, &value_datums, &value_nulls, &value_count);
     672              : 
     673            0 :                 Assert(key_count == value_count);
     674              :         }
     675              : 
     676            0 :         pairs = palloc(key_count * sizeof(Pairs));
     677              : 
     678            0 :         for (i = 0; i < key_count; ++i)
     679              :         {
     680            0 :                 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            0 :                 if (!value_nulls || value_nulls[i])
     686              :                 {
     687            0 :                         pairs[i].key = VARDATA(DatumGetPointer(key_datums[i]));
     688            0 :                         pairs[i].val = NULL;
     689            0 :                         pairs[i].keylen =
     690            0 :                                 hstoreCheckKeyLen(VARSIZE(DatumGetPointer(key_datums[i])) - VARHDRSZ);
     691            0 :                         pairs[i].vallen = 4;
     692            0 :                         pairs[i].isnull = true;
     693            0 :                         pairs[i].needfree = false;
     694            0 :                 }
     695              :                 else
     696              :                 {
     697            0 :                         pairs[i].key = VARDATA(DatumGetPointer(key_datums[i]));
     698            0 :                         pairs[i].val = VARDATA(DatumGetPointer(value_datums[i]));
     699            0 :                         pairs[i].keylen =
     700            0 :                                 hstoreCheckKeyLen(VARSIZE(DatumGetPointer(key_datums[i])) - VARHDRSZ);
     701            0 :                         pairs[i].vallen =
     702            0 :                                 hstoreCheckValLen(VARSIZE(DatumGetPointer(value_datums[i])) - VARHDRSZ);
     703            0 :                         pairs[i].isnull = false;
     704            0 :                         pairs[i].needfree = false;
     705              :                 }
     706            0 :         }
     707              : 
     708            0 :         key_count = hstoreUniquePairs(pairs, key_count, &buflen);
     709              : 
     710            0 :         out = hstorePairs(pairs, key_count, buflen);
     711              : 
     712            0 :         PG_RETURN_POINTER(out);
     713            0 : }
     714              : 
     715              : 
     716            0 : PG_FUNCTION_INFO_V1(hstore_from_array);
     717              : Datum
     718            0 : hstore_from_array(PG_FUNCTION_ARGS)
     719              : {
     720            0 :         ArrayType  *in_array = PG_GETARG_ARRAYTYPE_P(0);
     721            0 :         int                     ndims = ARR_NDIM(in_array);
     722            0 :         int                     count;
     723            0 :         int32           buflen;
     724            0 :         HStore     *out;
     725            0 :         Pairs      *pairs;
     726            0 :         Datum      *in_datums;
     727            0 :         bool       *in_nulls;
     728            0 :         int                     in_count;
     729            0 :         int                     i;
     730              : 
     731            0 :         Assert(ARR_ELEMTYPE(in_array) == TEXTOID);
     732              : 
     733            0 :         switch (ndims)
     734              :         {
     735              :                 case 0:
     736            0 :                         out = hstorePairs(NULL, 0, 0);
     737            0 :                         PG_RETURN_POINTER(out);
     738              : 
     739              :                 case 1:
     740            0 :                         if ((ARR_DIMS(in_array)[0]) % 2)
     741            0 :                                 ereport(ERROR,
     742              :                                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     743              :                                                  errmsg("array must have even number of elements")));
     744            0 :                         break;
     745              : 
     746              :                 case 2:
     747            0 :                         if ((ARR_DIMS(in_array)[1]) != 2)
     748            0 :                                 ereport(ERROR,
     749              :                                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     750              :                                                  errmsg("array must have two columns")));
     751            0 :                         break;
     752              : 
     753              :                 default:
     754            0 :                         ereport(ERROR,
     755              :                                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     756              :                                          errmsg("wrong number of array subscripts")));
     757            0 :         }
     758              : 
     759            0 :         deconstruct_array_builtin(in_array, TEXTOID, &in_datums, &in_nulls, &in_count);
     760              : 
     761            0 :         count = in_count / 2;
     762              : 
     763              :         /* see discussion in hstoreArrayToPairs() */
     764            0 :         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            0 :         pairs = palloc(count * sizeof(Pairs));
     771              : 
     772            0 :         for (i = 0; i < count; ++i)
     773              :         {
     774            0 :                 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            0 :                 if (in_nulls[i * 2 + 1])
     780              :                 {
     781            0 :                         pairs[i].key = VARDATA(DatumGetPointer(in_datums[i * 2]));
     782            0 :                         pairs[i].val = NULL;
     783            0 :                         pairs[i].keylen =
     784            0 :                                 hstoreCheckKeyLen(VARSIZE(DatumGetPointer(in_datums[i * 2])) - VARHDRSZ);
     785            0 :                         pairs[i].vallen = 4;
     786            0 :                         pairs[i].isnull = true;
     787            0 :                         pairs[i].needfree = false;
     788            0 :                 }
     789              :                 else
     790              :                 {
     791            0 :                         pairs[i].key = VARDATA(DatumGetPointer(in_datums[i * 2]));
     792            0 :                         pairs[i].val = VARDATA(DatumGetPointer(in_datums[i * 2 + 1]));
     793            0 :                         pairs[i].keylen =
     794            0 :                                 hstoreCheckKeyLen(VARSIZE(DatumGetPointer(in_datums[i * 2])) - VARHDRSZ);
     795            0 :                         pairs[i].vallen =
     796            0 :                                 hstoreCheckValLen(VARSIZE(DatumGetPointer(in_datums[i * 2 + 1])) - VARHDRSZ);
     797            0 :                         pairs[i].isnull = false;
     798            0 :                         pairs[i].needfree = false;
     799              :                 }
     800            0 :         }
     801              : 
     802            0 :         count = hstoreUniquePairs(pairs, count, &buflen);
     803              : 
     804            0 :         out = hstorePairs(pairs, count, buflen);
     805              : 
     806            0 :         PG_RETURN_POINTER(out);
     807            0 : }
     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            0 : PG_FUNCTION_INFO_V1(hstore_from_record);
     833              : Datum
     834            0 : hstore_from_record(PG_FUNCTION_ARGS)
     835              : {
     836            0 :         HeapTupleHeader rec;
     837            0 :         int32           buflen;
     838            0 :         HStore     *out;
     839            0 :         Pairs      *pairs;
     840            0 :         Oid                     tupType;
     841            0 :         int32           tupTypmod;
     842            0 :         TupleDesc       tupdesc;
     843            0 :         HeapTupleData tuple;
     844            0 :         RecordIOData *my_extra;
     845            0 :         int                     ncolumns;
     846            0 :         int                     i,
     847              :                                 j;
     848            0 :         Datum      *values;
     849            0 :         bool       *nulls;
     850              : 
     851            0 :         if (PG_ARGISNULL(0))
     852              :         {
     853            0 :                 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            0 :                 tupType = argtype;
     863            0 :                 tupTypmod = -1;
     864              : 
     865            0 :                 rec = NULL;
     866            0 :         }
     867              :         else
     868              :         {
     869            0 :                 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            0 :                 tupType = HeapTupleHeaderGetTypeId(rec);
     876            0 :                 tupTypmod = HeapTupleHeaderGetTypMod(rec);
     877              :         }
     878              : 
     879            0 :         tupdesc = lookup_rowtype_tupdesc_domain(tupType, tupTypmod, false);
     880            0 :         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            0 :         my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
     887            0 :         if (my_extra == NULL ||
     888            0 :                 my_extra->ncolumns != ncolumns)
     889              :         {
     890            0 :                 fcinfo->flinfo->fn_extra =
     891            0 :                         MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
     892            0 :                                                            offsetof(RecordIOData, columns) +
     893            0 :                                                            ncolumns * sizeof(ColumnIOData));
     894            0 :                 my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
     895            0 :                 my_extra->record_type = InvalidOid;
     896            0 :                 my_extra->record_typmod = 0;
     897            0 :         }
     898              : 
     899            0 :         if (my_extra->record_type != tupType ||
     900            0 :                 my_extra->record_typmod != tupTypmod)
     901              :         {
     902            0 :                 MemSet(my_extra, 0,
     903              :                            offsetof(RecordIOData, columns) +
     904              :                            ncolumns * sizeof(ColumnIOData));
     905            0 :                 my_extra->record_type = tupType;
     906            0 :                 my_extra->record_typmod = tupTypmod;
     907            0 :                 my_extra->ncolumns = ncolumns;
     908            0 :         }
     909              : 
     910            0 :         Assert(ncolumns <= MaxTupleAttributeNumber); /* thus, no overflow */
     911            0 :         pairs = palloc(ncolumns * sizeof(Pairs));
     912              : 
     913            0 :         if (rec)
     914              :         {
     915              :                 /* Build a temporary HeapTuple control structure */
     916            0 :                 tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
     917            0 :                 ItemPointerSetInvalid(&(tuple.t_self));
     918            0 :                 tuple.t_tableOid = InvalidOid;
     919            0 :                 tuple.t_data = rec;
     920              : 
     921            0 :                 values = (Datum *) palloc(ncolumns * sizeof(Datum));
     922            0 :                 nulls = (bool *) palloc(ncolumns * sizeof(bool));
     923              : 
     924              :                 /* Break down the tuple into fields */
     925            0 :                 heap_deform_tuple(&tuple, tupdesc, values, nulls);
     926            0 :         }
     927              :         else
     928              :         {
     929            0 :                 values = NULL;
     930            0 :                 nulls = NULL;
     931              :         }
     932              : 
     933            0 :         for (i = 0, j = 0; i < ncolumns; ++i)
     934              :         {
     935            0 :                 ColumnIOData *column_info = &my_extra->columns[i];
     936            0 :                 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
     937            0 :                 Oid                     column_type = att->atttypid;
     938            0 :                 char       *value;
     939              : 
     940              :                 /* Ignore dropped columns in datatype */
     941            0 :                 if (att->attisdropped)
     942            0 :                         continue;
     943              : 
     944            0 :                 pairs[j].key = NameStr(att->attname);
     945            0 :                 pairs[j].keylen = hstoreCheckKeyLen(strlen(NameStr(att->attname)));
     946              : 
     947            0 :                 if (!nulls || nulls[i])
     948              :                 {
     949            0 :                         pairs[j].val = NULL;
     950            0 :                         pairs[j].vallen = 4;
     951            0 :                         pairs[j].isnull = true;
     952            0 :                         pairs[j].needfree = false;
     953            0 :                         ++j;
     954            0 :                         continue;
     955              :                 }
     956              : 
     957              :                 /*
     958              :                  * Convert the column value to text
     959              :                  */
     960            0 :                 if (column_info->column_type != column_type)
     961              :                 {
     962            0 :                         bool            typIsVarlena;
     963              : 
     964            0 :                         getTypeOutputInfo(column_type,
     965            0 :                                                           &column_info->typiofunc,
     966              :                                                           &typIsVarlena);
     967            0 :                         fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
     968            0 :                                                   fcinfo->flinfo->fn_mcxt);
     969            0 :                         column_info->column_type = column_type;
     970            0 :                 }
     971              : 
     972            0 :                 value = OutputFunctionCall(&column_info->proc, values[i]);
     973              : 
     974            0 :                 pairs[j].val = value;
     975            0 :                 pairs[j].vallen = hstoreCheckValLen(strlen(value));
     976            0 :                 pairs[j].isnull = false;
     977            0 :                 pairs[j].needfree = false;
     978            0 :                 ++j;
     979            0 :         }
     980              : 
     981            0 :         ncolumns = hstoreUniquePairs(pairs, j, &buflen);
     982              : 
     983            0 :         out = hstorePairs(pairs, ncolumns, buflen);
     984              : 
     985            0 :         ReleaseTupleDesc(tupdesc);
     986              : 
     987            0 :         PG_RETURN_POINTER(out);
     988            0 : }
     989              : 
     990              : 
     991            0 : PG_FUNCTION_INFO_V1(hstore_populate_record);
     992              : Datum
     993            0 : hstore_populate_record(PG_FUNCTION_ARGS)
     994              : {
     995            0 :         Oid                     argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
     996            0 :         HStore     *hs;
     997            0 :         HEntry     *entries;
     998            0 :         char       *ptr;
     999            0 :         HeapTupleHeader rec;
    1000            0 :         Oid                     tupType;
    1001            0 :         int32           tupTypmod;
    1002            0 :         TupleDesc       tupdesc;
    1003            0 :         HeapTupleData tuple;
    1004            0 :         HeapTuple       rettuple;
    1005            0 :         RecordIOData *my_extra;
    1006            0 :         int                     ncolumns;
    1007            0 :         int                     i;
    1008            0 :         Datum      *values;
    1009            0 :         bool       *nulls;
    1010              : 
    1011            0 :         if (!type_is_rowtype(argtype))
    1012            0 :                 ereport(ERROR,
    1013              :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    1014              :                                  errmsg("first argument must be a rowtype")));
    1015              : 
    1016            0 :         if (PG_ARGISNULL(0))
    1017              :         {
    1018            0 :                 if (PG_ARGISNULL(1))
    1019            0 :                         PG_RETURN_NULL();
    1020              : 
    1021            0 :                 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            0 :                 tupType = argtype;
    1029            0 :                 tupTypmod = -1;
    1030            0 :         }
    1031              :         else
    1032              :         {
    1033            0 :                 rec = PG_GETARG_HEAPTUPLEHEADER(0);
    1034              : 
    1035            0 :                 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            0 :                 tupType = HeapTupleHeaderGetTypeId(rec);
    1043            0 :                 tupTypmod = HeapTupleHeaderGetTypMod(rec);
    1044              :         }
    1045              : 
    1046            0 :         hs = PG_GETARG_HSTORE_P(1);
    1047            0 :         entries = ARRPTR(hs);
    1048            0 :         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            0 :         if (HS_COUNT(hs) == 0 && rec)
    1057            0 :                 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            0 :         tupdesc = lookup_rowtype_tupdesc_domain(tupType, tupTypmod, false);
    1064            0 :         ncolumns = tupdesc->natts;
    1065              : 
    1066            0 :         if (rec)
    1067              :         {
    1068              :                 /* Build a temporary HeapTuple control structure */
    1069            0 :                 tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
    1070            0 :                 ItemPointerSetInvalid(&(tuple.t_self));
    1071            0 :                 tuple.t_tableOid = InvalidOid;
    1072            0 :                 tuple.t_data = rec;
    1073            0 :         }
    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            0 :         my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
    1080            0 :         if (my_extra == NULL ||
    1081            0 :                 my_extra->ncolumns != ncolumns)
    1082              :         {
    1083            0 :                 fcinfo->flinfo->fn_extra =
    1084            0 :                         MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
    1085            0 :                                                            offsetof(RecordIOData, columns) +
    1086            0 :                                                            ncolumns * sizeof(ColumnIOData));
    1087            0 :                 my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
    1088            0 :                 my_extra->record_type = InvalidOid;
    1089            0 :                 my_extra->record_typmod = 0;
    1090            0 :                 my_extra->domain_info = NULL;
    1091            0 :         }
    1092              : 
    1093            0 :         if (my_extra->record_type != tupType ||
    1094            0 :                 my_extra->record_typmod != tupTypmod)
    1095              :         {
    1096            0 :                 MemSet(my_extra, 0,
    1097              :                            offsetof(RecordIOData, columns) +
    1098              :                            ncolumns * sizeof(ColumnIOData));
    1099            0 :                 my_extra->record_type = tupType;
    1100            0 :                 my_extra->record_typmod = tupTypmod;
    1101            0 :                 my_extra->ncolumns = ncolumns;
    1102            0 :         }
    1103              : 
    1104            0 :         values = (Datum *) palloc(ncolumns * sizeof(Datum));
    1105            0 :         nulls = (bool *) palloc(ncolumns * sizeof(bool));
    1106              : 
    1107            0 :         if (rec)
    1108              :         {
    1109              :                 /* Break down the tuple into fields */
    1110            0 :                 heap_deform_tuple(&tuple, tupdesc, values, nulls);
    1111            0 :         }
    1112              :         else
    1113              :         {
    1114            0 :                 for (i = 0; i < ncolumns; ++i)
    1115              :                 {
    1116            0 :                         values[i] = (Datum) 0;
    1117            0 :                         nulls[i] = true;
    1118            0 :                 }
    1119              :         }
    1120              : 
    1121            0 :         for (i = 0; i < ncolumns; ++i)
    1122              :         {
    1123            0 :                 ColumnIOData *column_info = &my_extra->columns[i];
    1124            0 :                 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
    1125            0 :                 Oid                     column_type = att->atttypid;
    1126            0 :                 char       *value;
    1127            0 :                 int                     idx;
    1128            0 :                 int                     vallen;
    1129              : 
    1130              :                 /* Ignore dropped columns in datatype */
    1131            0 :                 if (att->attisdropped)
    1132              :                 {
    1133            0 :                         nulls[i] = true;
    1134            0 :                         continue;
    1135              :                 }
    1136              : 
    1137            0 :                 idx = hstoreFindKey(hs, 0,
    1138            0 :                                                         NameStr(att->attname),
    1139            0 :                                                         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            0 :                 if (idx < 0 && rec)
    1150            0 :                         continue;
    1151              : 
    1152              :                 /*
    1153              :                  * Prepare to convert the column value from text
    1154              :                  */
    1155            0 :                 if (column_info->column_type != column_type)
    1156              :                 {
    1157            0 :                         getTypeInputInfo(column_type,
    1158            0 :                                                          &column_info->typiofunc,
    1159            0 :                                                          &column_info->typioparam);
    1160            0 :                         fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
    1161            0 :                                                   fcinfo->flinfo->fn_mcxt);
    1162            0 :                         column_info->column_type = column_type;
    1163            0 :                 }
    1164              : 
    1165            0 :                 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            0 :                         values[i] = InputFunctionCall(&column_info->proc, NULL,
    1172            0 :                                                                                   column_info->typioparam,
    1173            0 :                                                                                   att->atttypmod);
    1174            0 :                         nulls[i] = true;
    1175            0 :                 }
    1176              :                 else
    1177              :                 {
    1178            0 :                         vallen = HSTORE_VALLEN(entries, idx);
    1179            0 :                         value = palloc(1 + vallen);
    1180            0 :                         memcpy(value, HSTORE_VAL(entries, ptr, idx), vallen);
    1181            0 :                         value[vallen] = 0;
    1182              : 
    1183            0 :                         values[i] = InputFunctionCall(&column_info->proc, value,
    1184            0 :                                                                                   column_info->typioparam,
    1185            0 :                                                                                   att->atttypmod);
    1186            0 :                         nulls[i] = false;
    1187              :                 }
    1188            0 :         }
    1189              : 
    1190            0 :         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            0 :         if (argtype != tupdesc->tdtypeid)
    1198            0 :                 domain_check(HeapTupleGetDatum(rettuple), false,
    1199            0 :                                          argtype,
    1200            0 :                                          &my_extra->domain_info,
    1201            0 :                                          fcinfo->flinfo->fn_mcxt);
    1202              : 
    1203            0 :         ReleaseTupleDesc(tupdesc);
    1204              : 
    1205            0 :         PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
    1206            0 : }
    1207              : 
    1208              : 
    1209              : static char *
    1210            0 : cpw(char *dst, char *src, int len)
    1211              : {
    1212            0 :         char       *ptr = src;
    1213              : 
    1214            0 :         while (ptr - src < len)
    1215              :         {
    1216            0 :                 if (*ptr == '"' || *ptr == '\\')
    1217            0 :                         *dst++ = '\\';
    1218            0 :                 *dst++ = *ptr++;
    1219              :         }
    1220            0 :         return dst;
    1221            0 : }
    1222              : 
    1223            0 : PG_FUNCTION_INFO_V1(hstore_out);
    1224              : Datum
    1225            0 : hstore_out(PG_FUNCTION_ARGS)
    1226              : {
    1227            0 :         HStore     *in = PG_GETARG_HSTORE_P(0);
    1228            0 :         int                     buflen,
    1229              :                                 i;
    1230            0 :         int                     count = HS_COUNT(in);
    1231            0 :         char       *out,
    1232              :                            *ptr;
    1233            0 :         char       *base = STRPTR(in);
    1234            0 :         HEntry     *entries = ARRPTR(in);
    1235              : 
    1236            0 :         if (count == 0)
    1237            0 :                 PG_RETURN_CSTRING(pstrdup(""));
    1238              : 
    1239            0 :         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            0 :         for (i = 0; i < count; i++)
    1250              :         {
    1251              :                 /* include "" and => and comma-space */
    1252            0 :                 buflen += 6 + 2 * HSTORE_KEYLEN(entries, i);
    1253              :                 /* include "" only if nonnull */
    1254            0 :                 buflen += 2 + (HSTORE_VALISNULL(entries, i)
    1255              :                                            ? 2
    1256            0 :                                            : 2 * HSTORE_VALLEN(entries, i));
    1257            0 :         }
    1258              : 
    1259            0 :         out = ptr = palloc(buflen);
    1260              : 
    1261            0 :         for (i = 0; i < count; i++)
    1262              :         {
    1263            0 :                 *ptr++ = '"';
    1264            0 :                 ptr = cpw(ptr, HSTORE_KEY(entries, base, i), HSTORE_KEYLEN(entries, i));
    1265            0 :                 *ptr++ = '"';
    1266            0 :                 *ptr++ = '=';
    1267            0 :                 *ptr++ = '>';
    1268            0 :                 if (HSTORE_VALISNULL(entries, i))
    1269              :                 {
    1270            0 :                         *ptr++ = 'N';
    1271            0 :                         *ptr++ = 'U';
    1272            0 :                         *ptr++ = 'L';
    1273            0 :                         *ptr++ = 'L';
    1274            0 :                 }
    1275              :                 else
    1276              :                 {
    1277            0 :                         *ptr++ = '"';
    1278            0 :                         ptr = cpw(ptr, HSTORE_VAL(entries, base, i), HSTORE_VALLEN(entries, i));
    1279            0 :                         *ptr++ = '"';
    1280              :                 }
    1281              : 
    1282            0 :                 if (i + 1 != count)
    1283              :                 {
    1284            0 :                         *ptr++ = ',';
    1285            0 :                         *ptr++ = ' ';
    1286            0 :                 }
    1287            0 :         }
    1288            0 :         *ptr = '\0';
    1289              : 
    1290            0 :         PG_RETURN_CSTRING(out);
    1291            0 : }
    1292              : 
    1293              : 
    1294            0 : 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            0 :         int                     i;
    1300            0 :         int                     count = HS_COUNT(in);
    1301            0 :         char       *base = STRPTR(in);
    1302            0 :         HEntry     *entries = ARRPTR(in);
    1303            0 :         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            0 :                 }
    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            0 :                 }
    1326            0 :         }
    1327              : 
    1328            0 :         PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
    1329            0 : }
    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            0 : PG_FUNCTION_INFO_V1(hstore_to_json_loose);
    1341              : Datum
    1342            0 : hstore_to_json_loose(PG_FUNCTION_ARGS)
    1343              : {
    1344            0 :         HStore     *in = PG_GETARG_HSTORE_P(0);
    1345            0 :         int                     i;
    1346            0 :         int                     count = HS_COUNT(in);
    1347            0 :         char       *base = STRPTR(in);
    1348            0 :         HEntry     *entries = ARRPTR(in);
    1349            0 :         StringInfoData dst;
    1350              : 
    1351            0 :         if (count == 0)
    1352            0 :                 PG_RETURN_TEXT_P(cstring_to_text_with_len("{}", 2));
    1353              : 
    1354            0 :         initStringInfo(&dst);
    1355              : 
    1356            0 :         appendStringInfoChar(&dst, '{');
    1357              : 
    1358            0 :         for (i = 0; i < count; i++)
    1359              :         {
    1360            0 :                 escape_json_with_len(&dst,
    1361            0 :                                                          HSTORE_KEY(entries, base, i),
    1362            0 :                                                          HSTORE_KEYLEN(entries, i));
    1363            0 :                 appendStringInfoString(&dst, ": ");
    1364            0 :                 if (HSTORE_VALISNULL(entries, i))
    1365            0 :                         appendStringInfoString(&dst, "null");
    1366              :                 /* guess that values of 't' or 'f' are booleans */
    1367            0 :                 else if (HSTORE_VALLEN(entries, i) == 1 &&
    1368            0 :                                  *(HSTORE_VAL(entries, base, i)) == 't')
    1369            0 :                         appendStringInfoString(&dst, "true");
    1370            0 :                 else if (HSTORE_VALLEN(entries, i) == 1 &&
    1371            0 :                                  *(HSTORE_VAL(entries, base, i)) == 'f')
    1372            0 :                         appendStringInfoString(&dst, "false");
    1373              :                 else
    1374              :                 {
    1375            0 :                         char       *str = HSTORE_VAL(entries, base, i);
    1376            0 :                         int                     len = HSTORE_VALLEN(entries, i);
    1377              : 
    1378            0 :                         if (IsValidJsonNumber(str, len))
    1379            0 :                                 appendBinaryStringInfo(&dst, str, len);
    1380              :                         else
    1381            0 :                                 escape_json_with_len(&dst, str, len);
    1382            0 :                 }
    1383              : 
    1384            0 :                 if (i + 1 != count)
    1385            0 :                         appendStringInfoString(&dst, ", ");
    1386            0 :         }
    1387            0 :         appendStringInfoChar(&dst, '}');
    1388              : 
    1389            0 :         PG_RETURN_TEXT_P(cstring_to_text_with_len(dst.data, dst.len));
    1390            0 : }
    1391              : 
    1392            0 : PG_FUNCTION_INFO_V1(hstore_to_json);
    1393              : Datum
    1394            0 : hstore_to_json(PG_FUNCTION_ARGS)
    1395              : {
    1396            0 :         HStore     *in = PG_GETARG_HSTORE_P(0);
    1397            0 :         int                     i;
    1398            0 :         int                     count = HS_COUNT(in);
    1399            0 :         char       *base = STRPTR(in);
    1400            0 :         HEntry     *entries = ARRPTR(in);
    1401            0 :         StringInfoData dst;
    1402              : 
    1403            0 :         if (count == 0)
    1404            0 :                 PG_RETURN_TEXT_P(cstring_to_text_with_len("{}", 2));
    1405              : 
    1406            0 :         initStringInfo(&dst);
    1407              : 
    1408            0 :         appendStringInfoChar(&dst, '{');
    1409              : 
    1410            0 :         for (i = 0; i < count; i++)
    1411              :         {
    1412            0 :                 escape_json_with_len(&dst,
    1413            0 :                                                          HSTORE_KEY(entries, base, i),
    1414            0 :                                                          HSTORE_KEYLEN(entries, i));
    1415            0 :                 appendStringInfoString(&dst, ": ");
    1416            0 :                 if (HSTORE_VALISNULL(entries, i))
    1417            0 :                         appendStringInfoString(&dst, "null");
    1418              :                 else
    1419              :                 {
    1420            0 :                         escape_json_with_len(&dst,
    1421            0 :                                                                  HSTORE_VAL(entries, base, i),
    1422            0 :                                                                  HSTORE_VALLEN(entries, i));
    1423              :                 }
    1424              : 
    1425            0 :                 if (i + 1 != count)
    1426            0 :                         appendStringInfoString(&dst, ", ");
    1427            0 :         }
    1428            0 :         appendStringInfoChar(&dst, '}');
    1429              : 
    1430            0 :         PG_RETURN_TEXT_P(cstring_to_text_with_len(dst.data, dst.len));
    1431            0 : }
    1432              : 
    1433            0 : PG_FUNCTION_INFO_V1(hstore_to_jsonb);
    1434              : Datum
    1435            0 : hstore_to_jsonb(PG_FUNCTION_ARGS)
    1436              : {
    1437            0 :         HStore     *in = PG_GETARG_HSTORE_P(0);
    1438            0 :         int                     i;
    1439            0 :         int                     count = HS_COUNT(in);
    1440            0 :         char       *base = STRPTR(in);
    1441            0 :         HEntry     *entries = ARRPTR(in);
    1442            0 :         JsonbInState state = {0};
    1443              : 
    1444            0 :         pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
    1445              : 
    1446            0 :         for (i = 0; i < count; i++)
    1447              :         {
    1448            0 :                 JsonbValue      key,
    1449              :                                         val;
    1450              : 
    1451            0 :                 key.type = jbvString;
    1452            0 :                 key.val.string.len = HSTORE_KEYLEN(entries, i);
    1453            0 :                 key.val.string.val = HSTORE_KEY(entries, base, i);
    1454              : 
    1455            0 :                 pushJsonbValue(&state, WJB_KEY, &key);
    1456              : 
    1457            0 :                 if (HSTORE_VALISNULL(entries, i))
    1458              :                 {
    1459            0 :                         val.type = jbvNull;
    1460            0 :                 }
    1461              :                 else
    1462              :                 {
    1463            0 :                         val.type = jbvString;
    1464            0 :                         val.val.string.len = HSTORE_VALLEN(entries, i);
    1465            0 :                         val.val.string.val = HSTORE_VAL(entries, base, i);
    1466              :                 }
    1467            0 :                 pushJsonbValue(&state, WJB_VALUE, &val);
    1468            0 :         }
    1469              : 
    1470            0 :         pushJsonbValue(&state, WJB_END_OBJECT, NULL);
    1471              : 
    1472            0 :         PG_RETURN_POINTER(JsonbValueToJsonb(state.result));
    1473            0 : }
    1474              : 
    1475            0 : PG_FUNCTION_INFO_V1(hstore_to_jsonb_loose);
    1476              : Datum
    1477            0 : hstore_to_jsonb_loose(PG_FUNCTION_ARGS)
    1478              : {
    1479            0 :         HStore     *in = PG_GETARG_HSTORE_P(0);
    1480            0 :         int                     i;
    1481            0 :         int                     count = HS_COUNT(in);
    1482            0 :         char       *base = STRPTR(in);
    1483            0 :         HEntry     *entries = ARRPTR(in);
    1484            0 :         JsonbInState state = {0};
    1485            0 :         StringInfoData tmp;
    1486              : 
    1487            0 :         initStringInfo(&tmp);
    1488              : 
    1489            0 :         pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
    1490              : 
    1491            0 :         for (i = 0; i < count; i++)
    1492              :         {
    1493            0 :                 JsonbValue      key,
    1494              :                                         val;
    1495              : 
    1496            0 :                 key.type = jbvString;
    1497            0 :                 key.val.string.len = HSTORE_KEYLEN(entries, i);
    1498            0 :                 key.val.string.val = HSTORE_KEY(entries, base, i);
    1499              : 
    1500            0 :                 pushJsonbValue(&state, WJB_KEY, &key);
    1501              : 
    1502            0 :                 if (HSTORE_VALISNULL(entries, i))
    1503              :                 {
    1504            0 :                         val.type = jbvNull;
    1505            0 :                 }
    1506              :                 /* guess that values of 't' or 'f' are booleans */
    1507            0 :                 else if (HSTORE_VALLEN(entries, i) == 1 &&
    1508            0 :                                  *(HSTORE_VAL(entries, base, i)) == 't')
    1509              :                 {
    1510            0 :                         val.type = jbvBool;
    1511            0 :                         val.val.boolean = true;
    1512            0 :                 }
    1513            0 :                 else if (HSTORE_VALLEN(entries, i) == 1 &&
    1514            0 :                                  *(HSTORE_VAL(entries, base, i)) == 'f')
    1515              :                 {
    1516            0 :                         val.type = jbvBool;
    1517            0 :                         val.val.boolean = false;
    1518            0 :                 }
    1519              :                 else
    1520              :                 {
    1521            0 :                         resetStringInfo(&tmp);
    1522            0 :                         appendBinaryStringInfo(&tmp, HSTORE_VAL(entries, base, i),
    1523            0 :                                                                    HSTORE_VALLEN(entries, i));
    1524            0 :                         if (IsValidJsonNumber(tmp.data, tmp.len))
    1525              :                         {
    1526            0 :                                 Datum           numd;
    1527              : 
    1528            0 :                                 val.type = jbvNumeric;
    1529            0 :                                 numd = DirectFunctionCall3(numeric_in,
    1530              :                                                                                    CStringGetDatum(tmp.data),
    1531              :                                                                                    ObjectIdGetDatum(InvalidOid),
    1532              :                                                                                    Int32GetDatum(-1));
    1533            0 :                                 val.val.numeric = DatumGetNumeric(numd);
    1534            0 :                         }
    1535              :                         else
    1536              :                         {
    1537            0 :                                 val.type = jbvString;
    1538            0 :                                 val.val.string.len = HSTORE_VALLEN(entries, i);
    1539            0 :                                 val.val.string.val = HSTORE_VAL(entries, base, i);
    1540              :                         }
    1541              :                 }
    1542            0 :                 pushJsonbValue(&state, WJB_VALUE, &val);
    1543            0 :         }
    1544              : 
    1545            0 :         pushJsonbValue(&state, WJB_END_OBJECT, NULL);
    1546              : 
    1547            0 :         PG_RETURN_POINTER(JsonbValueToJsonb(state.result));
    1548            0 : }
        

Generated by: LCOV version 2.3.2-1