LCOV - code coverage report
Current view: top level - contrib/hstore - hstore_io.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 84.6 % 670 567
Test Date: 2026-07-03 19:57:34 Functions: 90.2 % 41 37
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 65.4 % 500 327

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

Generated by: LCOV version 2.0-1