LCOV - code coverage report
Current view: top level - contrib/hstore - hstore_io.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 84.8 % 677 574
Test Date: 2026-09-05 06:15:58 Functions: 90.5 % 42 38
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 65.1 % 496 323

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

Generated by: LCOV version 2.0-1