Header And Logo

PostgreSQL
| The world's most advanced open source database.

hstore_io.c

Go to the documentation of this file.
00001 /*
00002  * contrib/hstore/hstore_io.c
00003  */
00004 #include "postgres.h"
00005 
00006 #include <ctype.h>
00007 
00008 #include "access/htup_details.h"
00009 #include "catalog/pg_type.h"
00010 #include "funcapi.h"
00011 #include "lib/stringinfo.h"
00012 #include "libpq/pqformat.h"
00013 #include "utils/builtins.h"
00014 #include "utils/json.h"
00015 #include "utils/lsyscache.h"
00016 #include "utils/typcache.h"
00017 
00018 #include "hstore.h"
00019 
00020 PG_MODULE_MAGIC;
00021 
00022 /* old names for C functions */
00023 HSTORE_POLLUTE(hstore_from_text, tconvert);
00024 
00025 
00026 typedef struct
00027 {
00028     char       *begin;
00029     char       *ptr;
00030     char       *cur;
00031     char       *word;
00032     int         wordlen;
00033 
00034     Pairs      *pairs;
00035     int         pcur;
00036     int         plen;
00037 } HSParser;
00038 
00039 #define RESIZEPRSBUF \
00040 do { \
00041         if ( state->cur - state->word + 1 >= state->wordlen ) \
00042         { \
00043                 int32 clen = state->cur - state->word; \
00044                 state->wordlen *= 2; \
00045                 state->word = (char*)repalloc( (void*)state->word, state->wordlen ); \
00046                 state->cur = state->word + clen; \
00047         } \
00048 } while (0)
00049 
00050 
00051 #define GV_WAITVAL 0
00052 #define GV_INVAL 1
00053 #define GV_INESCVAL 2
00054 #define GV_WAITESCIN 3
00055 #define GV_WAITESCESCIN 4
00056 
00057 static bool
00058 get_val(HSParser *state, bool ignoreeq, bool *escaped)
00059 {
00060     int         st = GV_WAITVAL;
00061 
00062     state->wordlen = 32;
00063     state->cur = state->word = palloc(state->wordlen);
00064     *escaped = false;
00065 
00066     while (1)
00067     {
00068         if (st == GV_WAITVAL)
00069         {
00070             if (*(state->ptr) == '"')
00071             {
00072                 *escaped = true;
00073                 st = GV_INESCVAL;
00074             }
00075             else if (*(state->ptr) == '\0')
00076             {
00077                 return false;
00078             }
00079             else if (*(state->ptr) == '=' && !ignoreeq)
00080             {
00081                 elog(ERROR, "Syntax error near '%c' at position %d", *(state->ptr), (int32) (state->ptr - state->begin));
00082             }
00083             else if (*(state->ptr) == '\\')
00084             {
00085                 st = GV_WAITESCIN;
00086             }
00087             else if (!isspace((unsigned char) *(state->ptr)))
00088             {
00089                 *(state->cur) = *(state->ptr);
00090                 state->cur++;
00091                 st = GV_INVAL;
00092             }
00093         }
00094         else if (st == GV_INVAL)
00095         {
00096             if (*(state->ptr) == '\\')
00097             {
00098                 st = GV_WAITESCIN;
00099             }
00100             else if (*(state->ptr) == '=' && !ignoreeq)
00101             {
00102                 state->ptr--;
00103                 return true;
00104             }
00105             else if (*(state->ptr) == ',' && ignoreeq)
00106             {
00107                 state->ptr--;
00108                 return true;
00109             }
00110             else if (isspace((unsigned char) *(state->ptr)))
00111             {
00112                 return true;
00113             }
00114             else if (*(state->ptr) == '\0')
00115             {
00116                 state->ptr--;
00117                 return true;
00118             }
00119             else
00120             {
00121                 RESIZEPRSBUF;
00122                 *(state->cur) = *(state->ptr);
00123                 state->cur++;
00124             }
00125         }
00126         else if (st == GV_INESCVAL)
00127         {
00128             if (*(state->ptr) == '\\')
00129             {
00130                 st = GV_WAITESCESCIN;
00131             }
00132             else if (*(state->ptr) == '"')
00133             {
00134                 return true;
00135             }
00136             else if (*(state->ptr) == '\0')
00137             {
00138                 elog(ERROR, "Unexpected end of string");
00139             }
00140             else
00141             {
00142                 RESIZEPRSBUF;
00143                 *(state->cur) = *(state->ptr);
00144                 state->cur++;
00145             }
00146         }
00147         else if (st == GV_WAITESCIN)
00148         {
00149             if (*(state->ptr) == '\0')
00150                 elog(ERROR, "Unexpected end of string");
00151             RESIZEPRSBUF;
00152             *(state->cur) = *(state->ptr);
00153             state->cur++;
00154             st = GV_INVAL;
00155         }
00156         else if (st == GV_WAITESCESCIN)
00157         {
00158             if (*(state->ptr) == '\0')
00159                 elog(ERROR, "Unexpected end of string");
00160             RESIZEPRSBUF;
00161             *(state->cur) = *(state->ptr);
00162             state->cur++;
00163             st = GV_INESCVAL;
00164         }
00165         else
00166             elog(ERROR, "Unknown state %d at position line %d in file '%s'", st, __LINE__, __FILE__);
00167 
00168         state->ptr++;
00169     }
00170 }
00171 
00172 #define WKEY    0
00173 #define WVAL    1
00174 #define WEQ 2
00175 #define WGT 3
00176 #define WDEL    4
00177 
00178 
00179 static void
00180 parse_hstore(HSParser *state)
00181 {
00182     int         st = WKEY;
00183     bool        escaped = false;
00184 
00185     state->plen = 16;
00186     state->pairs = (Pairs *) palloc(sizeof(Pairs) * state->plen);
00187     state->pcur = 0;
00188     state->ptr = state->begin;
00189     state->word = NULL;
00190 
00191     while (1)
00192     {
00193         if (st == WKEY)
00194         {
00195             if (!get_val(state, false, &escaped))
00196                 return;
00197             if (state->pcur >= state->plen)
00198             {
00199                 state->plen *= 2;
00200                 state->pairs = (Pairs *) repalloc(state->pairs, sizeof(Pairs) * state->plen);
00201             }
00202             state->pairs[state->pcur].key = state->word;
00203             state->pairs[state->pcur].keylen = hstoreCheckKeyLen(state->cur - state->word);
00204             state->pairs[state->pcur].val = NULL;
00205             state->word = NULL;
00206             st = WEQ;
00207         }
00208         else if (st == WEQ)
00209         {
00210             if (*(state->ptr) == '=')
00211             {
00212                 st = WGT;
00213             }
00214             else if (*(state->ptr) == '\0')
00215             {
00216                 elog(ERROR, "Unexpected end of string");
00217             }
00218             else if (!isspace((unsigned char) *(state->ptr)))
00219             {
00220                 elog(ERROR, "Syntax error near '%c' at position %d", *(state->ptr), (int32) (state->ptr - state->begin));
00221             }
00222         }
00223         else if (st == WGT)
00224         {
00225             if (*(state->ptr) == '>')
00226             {
00227                 st = WVAL;
00228             }
00229             else if (*(state->ptr) == '\0')
00230             {
00231                 elog(ERROR, "Unexpected end of string");
00232             }
00233             else
00234             {
00235                 elog(ERROR, "Syntax error near '%c' at position %d", *(state->ptr), (int32) (state->ptr - state->begin));
00236             }
00237         }
00238         else if (st == WVAL)
00239         {
00240             if (!get_val(state, true, &escaped))
00241                 elog(ERROR, "Unexpected end of string");
00242             state->pairs[state->pcur].val = state->word;
00243             state->pairs[state->pcur].vallen = hstoreCheckValLen(state->cur - state->word);
00244             state->pairs[state->pcur].isnull = false;
00245             state->pairs[state->pcur].needfree = true;
00246             if (state->cur - state->word == 4 && !escaped)
00247             {
00248                 state->word[4] = '\0';
00249                 if (0 == pg_strcasecmp(state->word, "null"))
00250                     state->pairs[state->pcur].isnull = true;
00251             }
00252             state->word = NULL;
00253             state->pcur++;
00254             st = WDEL;
00255         }
00256         else if (st == WDEL)
00257         {
00258             if (*(state->ptr) == ',')
00259             {
00260                 st = WKEY;
00261             }
00262             else if (*(state->ptr) == '\0')
00263             {
00264                 return;
00265             }
00266             else if (!isspace((unsigned char) *(state->ptr)))
00267             {
00268                 elog(ERROR, "Syntax error near '%c' at position %d", *(state->ptr), (int32) (state->ptr - state->begin));
00269             }
00270         }
00271         else
00272             elog(ERROR, "Unknown state %d at line %d in file '%s'", st, __LINE__, __FILE__);
00273 
00274         state->ptr++;
00275     }
00276 }
00277 
00278 static int
00279 comparePairs(const void *a, const void *b)
00280 {
00281     const Pairs *pa = a;
00282     const Pairs *pb = b;
00283 
00284     if (pa->keylen == pb->keylen)
00285     {
00286         int         res = memcmp(pa->key, pb->key, pa->keylen);
00287 
00288         if (res)
00289             return res;
00290 
00291         /* guarantee that needfree will be later */
00292         if (pb->needfree == pa->needfree)
00293             return 0;
00294         else if (pa->needfree)
00295             return 1;
00296         else
00297             return -1;
00298     }
00299     return (pa->keylen > pb->keylen) ? 1 : -1;
00300 }
00301 
00302 /*
00303  * this code still respects pairs.needfree, even though in general
00304  * it should never be called in a context where anything needs freeing.
00305  * we keep it because (a) those calls are in a rare code path anyway,
00306  * and (b) who knows whether they might be needed by some caller.
00307  */
00308 int
00309 hstoreUniquePairs(Pairs *a, int32 l, int32 *buflen)
00310 {
00311     Pairs      *ptr,
00312                *res;
00313 
00314     *buflen = 0;
00315     if (l < 2)
00316     {
00317         if (l == 1)
00318             *buflen = a->keylen + ((a->isnull) ? 0 : a->vallen);
00319         return l;
00320     }
00321 
00322     qsort((void *) a, l, sizeof(Pairs), comparePairs);
00323     ptr = a + 1;
00324     res = a;
00325     while (ptr - a < l)
00326     {
00327         if (ptr->keylen == res->keylen &&
00328             memcmp(ptr->key, res->key, res->keylen) == 0)
00329         {
00330             if (ptr->needfree)
00331             {
00332                 pfree(ptr->key);
00333                 pfree(ptr->val);
00334             }
00335         }
00336         else
00337         {
00338             *buflen += res->keylen + ((res->isnull) ? 0 : res->vallen);
00339             res++;
00340             memcpy(res, ptr, sizeof(Pairs));
00341         }
00342 
00343         ptr++;
00344     }
00345 
00346     *buflen += res->keylen + ((res->isnull) ? 0 : res->vallen);
00347     return res + 1 - a;
00348 }
00349 
00350 size_t
00351 hstoreCheckKeyLen(size_t len)
00352 {
00353     if (len > HSTORE_MAX_KEY_LEN)
00354         ereport(ERROR,
00355                 (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
00356                  errmsg("string too long for hstore key")));
00357     return len;
00358 }
00359 
00360 size_t
00361 hstoreCheckValLen(size_t len)
00362 {
00363     if (len > HSTORE_MAX_VALUE_LEN)
00364         ereport(ERROR,
00365                 (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
00366                  errmsg("string too long for hstore value")));
00367     return len;
00368 }
00369 
00370 
00371 HStore *
00372 hstorePairs(Pairs *pairs, int32 pcount, int32 buflen)
00373 {
00374     HStore     *out;
00375     HEntry     *entry;
00376     char       *ptr;
00377     char       *buf;
00378     int32       len;
00379     int32       i;
00380 
00381     len = CALCDATASIZE(pcount, buflen);
00382     out = palloc(len);
00383     SET_VARSIZE(out, len);
00384     HS_SETCOUNT(out, pcount);
00385 
00386     if (pcount == 0)
00387         return out;
00388 
00389     entry = ARRPTR(out);
00390     buf = ptr = STRPTR(out);
00391 
00392     for (i = 0; i < pcount; i++)
00393         HS_ADDITEM(entry, buf, ptr, pairs[i]);
00394 
00395     HS_FINALIZE(out, pcount, buf, ptr);
00396 
00397     return out;
00398 }
00399 
00400 
00401 PG_FUNCTION_INFO_V1(hstore_in);
00402 Datum       hstore_in(PG_FUNCTION_ARGS);
00403 Datum
00404 hstore_in(PG_FUNCTION_ARGS)
00405 {
00406     HSParser    state;
00407     int32       buflen;
00408     HStore     *out;
00409 
00410     state.begin = PG_GETARG_CSTRING(0);
00411 
00412     parse_hstore(&state);
00413 
00414     state.pcur = hstoreUniquePairs(state.pairs, state.pcur, &buflen);
00415 
00416     out = hstorePairs(state.pairs, state.pcur, buflen);
00417 
00418     PG_RETURN_POINTER(out);
00419 }
00420 
00421 
00422 PG_FUNCTION_INFO_V1(hstore_recv);
00423 Datum       hstore_recv(PG_FUNCTION_ARGS);
00424 Datum
00425 hstore_recv(PG_FUNCTION_ARGS)
00426 {
00427     int32       buflen;
00428     HStore     *out;
00429     Pairs      *pairs;
00430     int32       i;
00431     int32       pcount;
00432     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
00433 
00434     pcount = pq_getmsgint(buf, 4);
00435 
00436     if (pcount == 0)
00437     {
00438         out = hstorePairs(NULL, 0, 0);
00439         PG_RETURN_POINTER(out);
00440     }
00441 
00442     pairs = palloc(pcount * sizeof(Pairs));
00443 
00444     for (i = 0; i < pcount; ++i)
00445     {
00446         int         rawlen = pq_getmsgint(buf, 4);
00447         int         len;
00448 
00449         if (rawlen < 0)
00450             ereport(ERROR,
00451                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
00452                      errmsg("null value not allowed for hstore key")));
00453 
00454         pairs[i].key = pq_getmsgtext(buf, rawlen, &len);
00455         pairs[i].keylen = hstoreCheckKeyLen(len);
00456         pairs[i].needfree = true;
00457 
00458         rawlen = pq_getmsgint(buf, 4);
00459         if (rawlen < 0)
00460         {
00461             pairs[i].val = NULL;
00462             pairs[i].vallen = 0;
00463             pairs[i].isnull = true;
00464         }
00465         else
00466         {
00467             pairs[i].val = pq_getmsgtext(buf, rawlen, &len);
00468             pairs[i].vallen = hstoreCheckValLen(len);
00469             pairs[i].isnull = false;
00470         }
00471     }
00472 
00473     pcount = hstoreUniquePairs(pairs, pcount, &buflen);
00474 
00475     out = hstorePairs(pairs, pcount, buflen);
00476 
00477     PG_RETURN_POINTER(out);
00478 }
00479 
00480 
00481 PG_FUNCTION_INFO_V1(hstore_from_text);
00482 Datum       hstore_from_text(PG_FUNCTION_ARGS);
00483 Datum
00484 hstore_from_text(PG_FUNCTION_ARGS)
00485 {
00486     text       *key;
00487     text       *val = NULL;
00488     Pairs       p;
00489     HStore     *out;
00490 
00491     if (PG_ARGISNULL(0))
00492         PG_RETURN_NULL();
00493 
00494     p.needfree = false;
00495     key = PG_GETARG_TEXT_PP(0);
00496     p.key = VARDATA_ANY(key);
00497     p.keylen = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(key));
00498 
00499     if (PG_ARGISNULL(1))
00500     {
00501         p.vallen = 0;
00502         p.isnull = true;
00503     }
00504     else
00505     {
00506         val = PG_GETARG_TEXT_PP(1);
00507         p.val = VARDATA_ANY(val);
00508         p.vallen = hstoreCheckValLen(VARSIZE_ANY_EXHDR(val));
00509         p.isnull = false;
00510     }
00511 
00512     out = hstorePairs(&p, 1, p.keylen + p.vallen);
00513 
00514     PG_RETURN_POINTER(out);
00515 }
00516 
00517 
00518 PG_FUNCTION_INFO_V1(hstore_from_arrays);
00519 Datum       hstore_from_arrays(PG_FUNCTION_ARGS);
00520 Datum
00521 hstore_from_arrays(PG_FUNCTION_ARGS)
00522 {
00523     int32       buflen;
00524     HStore     *out;
00525     Pairs      *pairs;
00526     Datum      *key_datums;
00527     bool       *key_nulls;
00528     int         key_count;
00529     Datum      *value_datums;
00530     bool       *value_nulls;
00531     int         value_count;
00532     ArrayType  *key_array;
00533     ArrayType  *value_array;
00534     int         i;
00535 
00536     if (PG_ARGISNULL(0))
00537         PG_RETURN_NULL();
00538 
00539     key_array = PG_GETARG_ARRAYTYPE_P(0);
00540 
00541     Assert(ARR_ELEMTYPE(key_array) == TEXTOID);
00542 
00543     /*
00544      * must check >1 rather than != 1 because empty arrays have 0 dimensions,
00545      * not 1
00546      */
00547 
00548     if (ARR_NDIM(key_array) > 1)
00549         ereport(ERROR,
00550                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
00551                  errmsg("wrong number of array subscripts")));
00552 
00553     deconstruct_array(key_array,
00554                       TEXTOID, -1, false, 'i',
00555                       &key_datums, &key_nulls, &key_count);
00556 
00557     /* value_array might be NULL */
00558 
00559     if (PG_ARGISNULL(1))
00560     {
00561         value_array = NULL;
00562         value_count = key_count;
00563         value_datums = NULL;
00564         value_nulls = NULL;
00565     }
00566     else
00567     {
00568         value_array = PG_GETARG_ARRAYTYPE_P(1);
00569 
00570         Assert(ARR_ELEMTYPE(value_array) == TEXTOID);
00571 
00572         if (ARR_NDIM(value_array) > 1)
00573             ereport(ERROR,
00574                     (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
00575                      errmsg("wrong number of array subscripts")));
00576 
00577         if ((ARR_NDIM(key_array) > 0 || ARR_NDIM(value_array) > 0) &&
00578             (ARR_NDIM(key_array) != ARR_NDIM(value_array) ||
00579              ARR_DIMS(key_array)[0] != ARR_DIMS(value_array)[0] ||
00580              ARR_LBOUND(key_array)[0] != ARR_LBOUND(value_array)[0]))
00581             ereport(ERROR,
00582                     (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
00583                      errmsg("arrays must have same bounds")));
00584 
00585         deconstruct_array(value_array,
00586                           TEXTOID, -1, false, 'i',
00587                           &value_datums, &value_nulls, &value_count);
00588 
00589         Assert(key_count == value_count);
00590     }
00591 
00592     pairs = palloc(key_count * sizeof(Pairs));
00593 
00594     for (i = 0; i < key_count; ++i)
00595     {
00596         if (key_nulls[i])
00597             ereport(ERROR,
00598                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
00599                      errmsg("null value not allowed for hstore key")));
00600 
00601         if (!value_nulls || value_nulls[i])
00602         {
00603             pairs[i].key = VARDATA_ANY(key_datums[i]);
00604             pairs[i].val = NULL;
00605             pairs[i].keylen = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(key_datums[i]));
00606             pairs[i].vallen = 4;
00607             pairs[i].isnull = true;
00608             pairs[i].needfree = false;
00609         }
00610         else
00611         {
00612             pairs[i].key = VARDATA_ANY(key_datums[i]);
00613             pairs[i].val = VARDATA_ANY(value_datums[i]);
00614             pairs[i].keylen = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(key_datums[i]));
00615             pairs[i].vallen = hstoreCheckValLen(VARSIZE_ANY_EXHDR(value_datums[i]));
00616             pairs[i].isnull = false;
00617             pairs[i].needfree = false;
00618         }
00619     }
00620 
00621     key_count = hstoreUniquePairs(pairs, key_count, &buflen);
00622 
00623     out = hstorePairs(pairs, key_count, buflen);
00624 
00625     PG_RETURN_POINTER(out);
00626 }
00627 
00628 
00629 PG_FUNCTION_INFO_V1(hstore_from_array);
00630 Datum       hstore_from_array(PG_FUNCTION_ARGS);
00631 Datum
00632 hstore_from_array(PG_FUNCTION_ARGS)
00633 {
00634     ArrayType  *in_array = PG_GETARG_ARRAYTYPE_P(0);
00635     int         ndims = ARR_NDIM(in_array);
00636     int         count;
00637     int32       buflen;
00638     HStore     *out;
00639     Pairs      *pairs;
00640     Datum      *in_datums;
00641     bool       *in_nulls;
00642     int         in_count;
00643     int         i;
00644 
00645     Assert(ARR_ELEMTYPE(in_array) == TEXTOID);
00646 
00647     switch (ndims)
00648     {
00649         case 0:
00650             out = hstorePairs(NULL, 0, 0);
00651             PG_RETURN_POINTER(out);
00652 
00653         case 1:
00654             if ((ARR_DIMS(in_array)[0]) % 2)
00655                 ereport(ERROR,
00656                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
00657                          errmsg("array must have even number of elements")));
00658             break;
00659 
00660         case 2:
00661             if ((ARR_DIMS(in_array)[1]) != 2)
00662                 ereport(ERROR,
00663                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
00664                          errmsg("array must have two columns")));
00665             break;
00666 
00667         default:
00668             ereport(ERROR,
00669                     (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
00670                      errmsg("wrong number of array subscripts")));
00671     }
00672 
00673     deconstruct_array(in_array,
00674                       TEXTOID, -1, false, 'i',
00675                       &in_datums, &in_nulls, &in_count);
00676 
00677     count = in_count / 2;
00678 
00679     pairs = palloc(count * sizeof(Pairs));
00680 
00681     for (i = 0; i < count; ++i)
00682     {
00683         if (in_nulls[i * 2])
00684             ereport(ERROR,
00685                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
00686                      errmsg("null value not allowed for hstore key")));
00687 
00688         if (in_nulls[i * 2 + 1])
00689         {
00690             pairs[i].key = VARDATA_ANY(in_datums[i * 2]);
00691             pairs[i].val = NULL;
00692             pairs[i].keylen = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(in_datums[i * 2]));
00693             pairs[i].vallen = 4;
00694             pairs[i].isnull = true;
00695             pairs[i].needfree = false;
00696         }
00697         else
00698         {
00699             pairs[i].key = VARDATA_ANY(in_datums[i * 2]);
00700             pairs[i].val = VARDATA_ANY(in_datums[i * 2 + 1]);
00701             pairs[i].keylen = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(in_datums[i * 2]));
00702             pairs[i].vallen = hstoreCheckValLen(VARSIZE_ANY_EXHDR(in_datums[i * 2 + 1]));
00703             pairs[i].isnull = false;
00704             pairs[i].needfree = false;
00705         }
00706     }
00707 
00708     count = hstoreUniquePairs(pairs, count, &buflen);
00709 
00710     out = hstorePairs(pairs, count, buflen);
00711 
00712     PG_RETURN_POINTER(out);
00713 }
00714 
00715 /* most of hstore_from_record is shamelessly swiped from record_out */
00716 
00717 /*
00718  * structure to cache metadata needed for record I/O
00719  */
00720 typedef struct ColumnIOData
00721 {
00722     Oid         column_type;
00723     Oid         typiofunc;
00724     Oid         typioparam;
00725     FmgrInfo    proc;
00726 } ColumnIOData;
00727 
00728 typedef struct RecordIOData
00729 {
00730     Oid         record_type;
00731     int32       record_typmod;
00732     int         ncolumns;
00733     ColumnIOData columns[1];    /* VARIABLE LENGTH ARRAY */
00734 } RecordIOData;
00735 
00736 PG_FUNCTION_INFO_V1(hstore_from_record);
00737 Datum       hstore_from_record(PG_FUNCTION_ARGS);
00738 Datum
00739 hstore_from_record(PG_FUNCTION_ARGS)
00740 {
00741     HeapTupleHeader rec;
00742     int32       buflen;
00743     HStore     *out;
00744     Pairs      *pairs;
00745     Oid         tupType;
00746     int32       tupTypmod;
00747     TupleDesc   tupdesc;
00748     HeapTupleData tuple;
00749     RecordIOData *my_extra;
00750     int         ncolumns;
00751     int         i,
00752                 j;
00753     Datum      *values;
00754     bool       *nulls;
00755 
00756     if (PG_ARGISNULL(0))
00757     {
00758         Oid         argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
00759 
00760         /*
00761          * have no tuple to look at, so the only source of type info is the
00762          * argtype. The lookup_rowtype_tupdesc call below will error out if we
00763          * don't have a known composite type oid here.
00764          */
00765         tupType = argtype;
00766         tupTypmod = -1;
00767 
00768         rec = NULL;
00769     }
00770     else
00771     {
00772         rec = PG_GETARG_HEAPTUPLEHEADER(0);
00773 
00774         /* Extract type info from the tuple itself */
00775         tupType = HeapTupleHeaderGetTypeId(rec);
00776         tupTypmod = HeapTupleHeaderGetTypMod(rec);
00777     }
00778 
00779     tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
00780     ncolumns = tupdesc->natts;
00781 
00782     /*
00783      * We arrange to look up the needed I/O info just once per series of
00784      * calls, assuming the record type doesn't change underneath us.
00785      */
00786     my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
00787     if (my_extra == NULL ||
00788         my_extra->ncolumns != ncolumns)
00789     {
00790         fcinfo->flinfo->fn_extra =
00791             MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
00792                                sizeof(RecordIOData) - sizeof(ColumnIOData)
00793                                + ncolumns * sizeof(ColumnIOData));
00794         my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
00795         my_extra->record_type = InvalidOid;
00796         my_extra->record_typmod = 0;
00797     }
00798 
00799     if (my_extra->record_type != tupType ||
00800         my_extra->record_typmod != tupTypmod)
00801     {
00802         MemSet(my_extra, 0,
00803                sizeof(RecordIOData) - sizeof(ColumnIOData)
00804                + ncolumns * sizeof(ColumnIOData));
00805         my_extra->record_type = tupType;
00806         my_extra->record_typmod = tupTypmod;
00807         my_extra->ncolumns = ncolumns;
00808     }
00809 
00810     pairs = palloc(ncolumns * sizeof(Pairs));
00811 
00812     if (rec)
00813     {
00814         /* Build a temporary HeapTuple control structure */
00815         tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
00816         ItemPointerSetInvalid(&(tuple.t_self));
00817         tuple.t_tableOid = InvalidOid;
00818         tuple.t_data = rec;
00819 
00820         values = (Datum *) palloc(ncolumns * sizeof(Datum));
00821         nulls = (bool *) palloc(ncolumns * sizeof(bool));
00822 
00823         /* Break down the tuple into fields */
00824         heap_deform_tuple(&tuple, tupdesc, values, nulls);
00825     }
00826     else
00827     {
00828         values = NULL;
00829         nulls = NULL;
00830     }
00831 
00832     for (i = 0, j = 0; i < ncolumns; ++i)
00833     {
00834         ColumnIOData *column_info = &my_extra->columns[i];
00835         Oid         column_type = tupdesc->attrs[i]->atttypid;
00836         char       *value;
00837 
00838         /* Ignore dropped columns in datatype */
00839         if (tupdesc->attrs[i]->attisdropped)
00840             continue;
00841 
00842         pairs[j].key = NameStr(tupdesc->attrs[i]->attname);
00843         pairs[j].keylen = hstoreCheckKeyLen(strlen(NameStr(tupdesc->attrs[i]->attname)));
00844 
00845         if (!nulls || nulls[i])
00846         {
00847             pairs[j].val = NULL;
00848             pairs[j].vallen = 4;
00849             pairs[j].isnull = true;
00850             pairs[j].needfree = false;
00851             ++j;
00852             continue;
00853         }
00854 
00855         /*
00856          * Convert the column value to text
00857          */
00858         if (column_info->column_type != column_type)
00859         {
00860             bool        typIsVarlena;
00861 
00862             getTypeOutputInfo(column_type,
00863                               &column_info->typiofunc,
00864                               &typIsVarlena);
00865             fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
00866                           fcinfo->flinfo->fn_mcxt);
00867             column_info->column_type = column_type;
00868         }
00869 
00870         value = OutputFunctionCall(&column_info->proc, values[i]);
00871 
00872         pairs[j].val = value;
00873         pairs[j].vallen = hstoreCheckValLen(strlen(value));
00874         pairs[j].isnull = false;
00875         pairs[j].needfree = false;
00876         ++j;
00877     }
00878 
00879     ncolumns = hstoreUniquePairs(pairs, j, &buflen);
00880 
00881     out = hstorePairs(pairs, ncolumns, buflen);
00882 
00883     ReleaseTupleDesc(tupdesc);
00884 
00885     PG_RETURN_POINTER(out);
00886 }
00887 
00888 
00889 PG_FUNCTION_INFO_V1(hstore_populate_record);
00890 Datum       hstore_populate_record(PG_FUNCTION_ARGS);
00891 Datum
00892 hstore_populate_record(PG_FUNCTION_ARGS)
00893 {
00894     Oid         argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
00895     HStore     *hs;
00896     HEntry     *entries;
00897     char       *ptr;
00898     HeapTupleHeader rec;
00899     Oid         tupType;
00900     int32       tupTypmod;
00901     TupleDesc   tupdesc;
00902     HeapTupleData tuple;
00903     HeapTuple   rettuple;
00904     RecordIOData *my_extra;
00905     int         ncolumns;
00906     int         i;
00907     Datum      *values;
00908     bool       *nulls;
00909 
00910     if (!type_is_rowtype(argtype))
00911         ereport(ERROR,
00912                 (errcode(ERRCODE_DATATYPE_MISMATCH),
00913                  errmsg("first argument must be a rowtype")));
00914 
00915     if (PG_ARGISNULL(0))
00916     {
00917         if (PG_ARGISNULL(1))
00918             PG_RETURN_NULL();
00919 
00920         rec = NULL;
00921 
00922         /*
00923          * have no tuple to look at, so the only source of type info is the
00924          * argtype. The lookup_rowtype_tupdesc call below will error out if we
00925          * don't have a known composite type oid here.
00926          */
00927         tupType = argtype;
00928         tupTypmod = -1;
00929     }
00930     else
00931     {
00932         rec = PG_GETARG_HEAPTUPLEHEADER(0);
00933 
00934         if (PG_ARGISNULL(1))
00935             PG_RETURN_POINTER(rec);
00936 
00937         /* Extract type info from the tuple itself */
00938         tupType = HeapTupleHeaderGetTypeId(rec);
00939         tupTypmod = HeapTupleHeaderGetTypMod(rec);
00940     }
00941 
00942     hs = PG_GETARG_HS(1);
00943     entries = ARRPTR(hs);
00944     ptr = STRPTR(hs);
00945 
00946     /*
00947      * if the input hstore is empty, we can only skip the rest if we were
00948      * passed in a non-null record, since otherwise there may be issues with
00949      * domain nulls.
00950      */
00951 
00952     if (HS_COUNT(hs) == 0 && rec)
00953         PG_RETURN_POINTER(rec);
00954 
00955     tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
00956     ncolumns = tupdesc->natts;
00957 
00958     if (rec)
00959     {
00960         /* Build a temporary HeapTuple control structure */
00961         tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
00962         ItemPointerSetInvalid(&(tuple.t_self));
00963         tuple.t_tableOid = InvalidOid;
00964         tuple.t_data = rec;
00965     }
00966 
00967     /*
00968      * We arrange to look up the needed I/O info just once per series of
00969      * calls, assuming the record type doesn't change underneath us.
00970      */
00971     my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
00972     if (my_extra == NULL ||
00973         my_extra->ncolumns != ncolumns)
00974     {
00975         fcinfo->flinfo->fn_extra =
00976             MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
00977                                sizeof(RecordIOData) - sizeof(ColumnIOData)
00978                                + ncolumns * sizeof(ColumnIOData));
00979         my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
00980         my_extra->record_type = InvalidOid;
00981         my_extra->record_typmod = 0;
00982     }
00983 
00984     if (my_extra->record_type != tupType ||
00985         my_extra->record_typmod != tupTypmod)
00986     {
00987         MemSet(my_extra, 0,
00988                sizeof(RecordIOData) - sizeof(ColumnIOData)
00989                + ncolumns * sizeof(ColumnIOData));
00990         my_extra->record_type = tupType;
00991         my_extra->record_typmod = tupTypmod;
00992         my_extra->ncolumns = ncolumns;
00993     }
00994 
00995     values = (Datum *) palloc(ncolumns * sizeof(Datum));
00996     nulls = (bool *) palloc(ncolumns * sizeof(bool));
00997 
00998     if (rec)
00999     {
01000         /* Break down the tuple into fields */
01001         heap_deform_tuple(&tuple, tupdesc, values, nulls);
01002     }
01003     else
01004     {
01005         for (i = 0; i < ncolumns; ++i)
01006         {
01007             values[i] = (Datum) 0;
01008             nulls[i] = true;
01009         }
01010     }
01011 
01012     for (i = 0; i < ncolumns; ++i)
01013     {
01014         ColumnIOData *column_info = &my_extra->columns[i];
01015         Oid         column_type = tupdesc->attrs[i]->atttypid;
01016         char       *value;
01017         int         idx;
01018         int         vallen;
01019 
01020         /* Ignore dropped columns in datatype */
01021         if (tupdesc->attrs[i]->attisdropped)
01022         {
01023             nulls[i] = true;
01024             continue;
01025         }
01026 
01027         idx = hstoreFindKey(hs, 0,
01028                             NameStr(tupdesc->attrs[i]->attname),
01029                             strlen(NameStr(tupdesc->attrs[i]->attname)));
01030 
01031         /*
01032          * we can't just skip here if the key wasn't found since we might have
01033          * a domain to deal with. If we were passed in a non-null record
01034          * datum, we assume that the existing values are valid (if they're
01035          * not, then it's not our fault), but if we were passed in a null,
01036          * then every field which we don't populate needs to be run through
01037          * the input function just in case it's a domain type.
01038          */
01039         if (idx < 0 && rec)
01040             continue;
01041 
01042         /*
01043          * Prepare to convert the column value from text
01044          */
01045         if (column_info->column_type != column_type)
01046         {
01047             getTypeInputInfo(column_type,
01048                              &column_info->typiofunc,
01049                              &column_info->typioparam);
01050             fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
01051                           fcinfo->flinfo->fn_mcxt);
01052             column_info->column_type = column_type;
01053         }
01054 
01055         if (idx < 0 || HS_VALISNULL(entries, idx))
01056         {
01057             /*
01058              * need InputFunctionCall to happen even for nulls, so that domain
01059              * checks are done
01060              */
01061             values[i] = InputFunctionCall(&column_info->proc, NULL,
01062                                           column_info->typioparam,
01063                                           tupdesc->attrs[i]->atttypmod);
01064             nulls[i] = true;
01065         }
01066         else
01067         {
01068             vallen = HS_VALLEN(entries, idx);
01069             value = palloc(1 + vallen);
01070             memcpy(value, HS_VAL(entries, ptr, idx), vallen);
01071             value[vallen] = 0;
01072 
01073             values[i] = InputFunctionCall(&column_info->proc, value,
01074                                           column_info->typioparam,
01075                                           tupdesc->attrs[i]->atttypmod);
01076             nulls[i] = false;
01077         }
01078     }
01079 
01080     rettuple = heap_form_tuple(tupdesc, values, nulls);
01081 
01082     ReleaseTupleDesc(tupdesc);
01083 
01084     PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
01085 }
01086 
01087 
01088 static char *
01089 cpw(char *dst, char *src, int len)
01090 {
01091     char       *ptr = src;
01092 
01093     while (ptr - src < len)
01094     {
01095         if (*ptr == '"' || *ptr == '\\')
01096             *dst++ = '\\';
01097         *dst++ = *ptr++;
01098     }
01099     return dst;
01100 }
01101 
01102 PG_FUNCTION_INFO_V1(hstore_out);
01103 Datum       hstore_out(PG_FUNCTION_ARGS);
01104 Datum
01105 hstore_out(PG_FUNCTION_ARGS)
01106 {
01107     HStore     *in = PG_GETARG_HS(0);
01108     int         buflen,
01109                 i;
01110     int         count = HS_COUNT(in);
01111     char       *out,
01112                *ptr;
01113     char       *base = STRPTR(in);
01114     HEntry     *entries = ARRPTR(in);
01115 
01116     if (count == 0)
01117     {
01118         out = palloc(1);
01119         *out = '\0';
01120         PG_RETURN_CSTRING(out);
01121     }
01122 
01123     buflen = 0;
01124 
01125     /*
01126      * this loop overestimates due to pessimistic assumptions about escaping,
01127      * so very large hstore values can't be output. this could be fixed, but
01128      * many other data types probably have the same issue. This replaced code
01129      * that used the original varlena size for calculations, which was wrong
01130      * in some subtle ways.
01131      */
01132 
01133     for (i = 0; i < count; i++)
01134     {
01135         /* include "" and => and comma-space */
01136         buflen += 6 + 2 * HS_KEYLEN(entries, i);
01137         /* include "" only if nonnull */
01138         buflen += 2 + (HS_VALISNULL(entries, i)
01139                        ? 2
01140                        : 2 * HS_VALLEN(entries, i));
01141     }
01142 
01143     out = ptr = palloc(buflen);
01144 
01145     for (i = 0; i < count; i++)
01146     {
01147         *ptr++ = '"';
01148         ptr = cpw(ptr, HS_KEY(entries, base, i), HS_KEYLEN(entries, i));
01149         *ptr++ = '"';
01150         *ptr++ = '=';
01151         *ptr++ = '>';
01152         if (HS_VALISNULL(entries, i))
01153         {
01154             *ptr++ = 'N';
01155             *ptr++ = 'U';
01156             *ptr++ = 'L';
01157             *ptr++ = 'L';
01158         }
01159         else
01160         {
01161             *ptr++ = '"';
01162             ptr = cpw(ptr, HS_VAL(entries, base, i), HS_VALLEN(entries, i));
01163             *ptr++ = '"';
01164         }
01165 
01166         if (i + 1 != count)
01167         {
01168             *ptr++ = ',';
01169             *ptr++ = ' ';
01170         }
01171     }
01172     *ptr = '\0';
01173 
01174     PG_RETURN_CSTRING(out);
01175 }
01176 
01177 
01178 PG_FUNCTION_INFO_V1(hstore_send);
01179 Datum       hstore_send(PG_FUNCTION_ARGS);
01180 Datum
01181 hstore_send(PG_FUNCTION_ARGS)
01182 {
01183     HStore     *in = PG_GETARG_HS(0);
01184     int         i;
01185     int         count = HS_COUNT(in);
01186     char       *base = STRPTR(in);
01187     HEntry     *entries = ARRPTR(in);
01188     StringInfoData buf;
01189 
01190     pq_begintypsend(&buf);
01191 
01192     pq_sendint(&buf, count, 4);
01193 
01194     for (i = 0; i < count; i++)
01195     {
01196         int32       keylen = HS_KEYLEN(entries, i);
01197 
01198         pq_sendint(&buf, keylen, 4);
01199         pq_sendtext(&buf, HS_KEY(entries, base, i), keylen);
01200         if (HS_VALISNULL(entries, i))
01201         {
01202             pq_sendint(&buf, -1, 4);
01203         }
01204         else
01205         {
01206             int32       vallen = HS_VALLEN(entries, i);
01207 
01208             pq_sendint(&buf, vallen, 4);
01209             pq_sendtext(&buf, HS_VAL(entries, base, i), vallen);
01210         }
01211     }
01212 
01213     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
01214 }
01215 
01216 
01217 /*
01218  * hstore_to_json_loose
01219  *
01220  * This is a heuristic conversion to json which treats
01221  * 't' and 'f' as booleans and strings that look like numbers as numbers,
01222  * as long as they don't start with a leading zero followed by another digit
01223  * (think zip codes or phone numbers starting with 0).
01224  */
01225 PG_FUNCTION_INFO_V1(hstore_to_json_loose);
01226 Datum       hstore_to_json_loose(PG_FUNCTION_ARGS);
01227 Datum
01228 hstore_to_json_loose(PG_FUNCTION_ARGS)
01229 {
01230     HStore     *in = PG_GETARG_HS(0);
01231     int         buflen,
01232                 i;
01233     int         count = HS_COUNT(in);
01234     char       *out,
01235                *ptr;
01236     char       *base = STRPTR(in);
01237     HEntry     *entries = ARRPTR(in);
01238     bool        is_number;
01239     StringInfo  src,
01240                 dst;
01241 
01242     if (count == 0)
01243     {
01244         out = palloc(1);
01245         *out = '\0';
01246         PG_RETURN_TEXT_P(cstring_to_text(out));
01247     }
01248 
01249     buflen = 3;
01250 
01251     /*
01252      * Formula adjusted slightly from the logic in hstore_out. We have to take
01253      * account of out treatment of booleans to be a bit more pessimistic about
01254      * the length of values.
01255      */
01256 
01257     for (i = 0; i < count; i++)
01258     {
01259         /* include "" and colon-space and comma-space */
01260         buflen += 6 + 2 * HS_KEYLEN(entries, i);
01261         /* include "" only if nonnull */
01262         buflen += 3 + (HS_VALISNULL(entries, i)
01263                        ? 1
01264                        : 2 * HS_VALLEN(entries, i));
01265     }
01266 
01267     out = ptr = palloc(buflen);
01268 
01269     src = makeStringInfo();
01270     dst = makeStringInfo();
01271 
01272     *ptr++ = '{';
01273 
01274     for (i = 0; i < count; i++)
01275     {
01276         resetStringInfo(src);
01277         resetStringInfo(dst);
01278         appendBinaryStringInfo(src, HS_KEY(entries, base, i), HS_KEYLEN(entries, i));
01279         escape_json(dst, src->data);
01280         strncpy(ptr, dst->data, dst->len);
01281         ptr += dst->len;
01282         *ptr++ = ':';
01283         *ptr++ = ' ';
01284         resetStringInfo(dst);
01285         if (HS_VALISNULL(entries, i))
01286             appendStringInfoString(dst, "null");
01287         /* guess that values of 't' or 'f' are booleans */
01288         else if (HS_VALLEN(entries, i) == 1 && *(HS_VAL(entries, base, i)) == 't')
01289             appendStringInfoString(dst, "true");
01290         else if (HS_VALLEN(entries, i) == 1 && *(HS_VAL(entries, base, i)) == 'f')
01291             appendStringInfoString(dst, "false");
01292         else
01293         {
01294             is_number = false;
01295             resetStringInfo(src);
01296             appendBinaryStringInfo(src, HS_VAL(entries, base, i), HS_VALLEN(entries, i));
01297 
01298             /*
01299              * don't treat something with a leading zero followed by another
01300              * digit as numeric - could be a zip code or similar
01301              */
01302             if (src->len > 0 &&
01303                 !(src->data[0] == '0' && isdigit((unsigned char) src->data[1])) &&
01304                 strspn(src->data, "+-0123456789Ee.") == src->len)
01305             {
01306                 /*
01307                  * might be a number. See if we can input it as a numeric
01308                  * value. Ignore any actual parsed value.
01309                  */
01310                 char       *endptr = "junk";
01311                 long        lval;
01312 
01313                 lval =  strtol(src->data, &endptr, 10);
01314                 (void) lval;
01315                 if (*endptr == '\0')
01316                 {
01317                     /*
01318                      * strol man page says this means the whole string is
01319                      * valid
01320                      */
01321                     is_number = true;
01322                 }
01323                 else
01324                 {
01325                     /* not an int - try a double */
01326                     double dval;
01327 
01328                     dval = strtod(src->data, &endptr);
01329                     (void) dval;
01330                     if (*endptr == '\0')
01331                         is_number = true;
01332                 }
01333             }
01334             if (is_number)
01335                 appendBinaryStringInfo(dst, src->data, src->len);
01336             else
01337                 escape_json(dst, src->data);
01338         }
01339         strncpy(ptr, dst->data, dst->len);
01340         ptr += dst->len;
01341 
01342         if (i + 1 != count)
01343         {
01344             *ptr++ = ',';
01345             *ptr++ = ' ';
01346         }
01347     }
01348     *ptr++ = '}';
01349     *ptr = '\0';
01350 
01351     PG_RETURN_TEXT_P(cstring_to_text(out));
01352 }
01353 
01354 PG_FUNCTION_INFO_V1(hstore_to_json);
01355 Datum       hstore_to_json(PG_FUNCTION_ARGS);
01356 Datum
01357 hstore_to_json(PG_FUNCTION_ARGS)
01358 {
01359     HStore     *in = PG_GETARG_HS(0);
01360     int         buflen,
01361                 i;
01362     int         count = HS_COUNT(in);
01363     char       *out,
01364                *ptr;
01365     char       *base = STRPTR(in);
01366     HEntry     *entries = ARRPTR(in);
01367     StringInfo  src,
01368                 dst;
01369 
01370     if (count == 0)
01371     {
01372         out = palloc(1);
01373         *out = '\0';
01374         PG_RETURN_TEXT_P(cstring_to_text(out));
01375     }
01376 
01377     buflen = 3;
01378 
01379     /*
01380      * Formula adjusted slightly from the logic in hstore_out. We have to take
01381      * account of out treatment of booleans to be a bit more pessimistic about
01382      * the length of values.
01383      */
01384 
01385     for (i = 0; i < count; i++)
01386     {
01387         /* include "" and colon-space and comma-space */
01388         buflen += 6 + 2 * HS_KEYLEN(entries, i);
01389         /* include "" only if nonnull */
01390         buflen += 3 + (HS_VALISNULL(entries, i)
01391                        ? 1
01392                        : 2 * HS_VALLEN(entries, i));
01393     }
01394 
01395     out = ptr = palloc(buflen);
01396 
01397     src = makeStringInfo();
01398     dst = makeStringInfo();
01399 
01400     *ptr++ = '{';
01401 
01402     for (i = 0; i < count; i++)
01403     {
01404         resetStringInfo(src);
01405         resetStringInfo(dst);
01406         appendBinaryStringInfo(src, HS_KEY(entries, base, i), HS_KEYLEN(entries, i));
01407         escape_json(dst, src->data);
01408         strncpy(ptr, dst->data, dst->len);
01409         ptr += dst->len;
01410         *ptr++ = ':';
01411         *ptr++ = ' ';
01412         resetStringInfo(dst);
01413         if (HS_VALISNULL(entries, i))
01414             appendStringInfoString(dst, "null");
01415         else
01416         {
01417             resetStringInfo(src);
01418             appendBinaryStringInfo(src, HS_VAL(entries, base, i), HS_VALLEN(entries, i));
01419             escape_json(dst, src->data);
01420         }
01421         strncpy(ptr, dst->data, dst->len);
01422         ptr += dst->len;
01423 
01424         if (i + 1 != count)
01425         {
01426             *ptr++ = ',';
01427             *ptr++ = ' ';
01428         }
01429     }
01430     *ptr++ = '}';
01431     *ptr = '\0';
01432 
01433     PG_RETURN_TEXT_P(cstring_to_text(out));
01434 }