LCOV - code coverage report
Current view: top level - contrib/hstore - hstore_io.c (source / functions) Hit Total Coverage
Test: PostgreSQL 14devel Lines: 550 649 84.7 %
Date: 2020-09-25 16:06:32 Functions: 33 37 89.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13