LCOV - differential code coverage report
Current view: top level - contrib/hstore - hstore_io.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 85.0 % 680 578 16 28 56 2 36 283 35 224 60 313 4 13
Current Date: 2023-04-08 15:15:32 Functions: 90.2 % 41 37 4 33 4 4 37
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a