00001
00002
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
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
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
00304
00305
00306
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
00545
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
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
00716
00717
00718
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];
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
00762
00763
00764
00765 tupType = argtype;
00766 tupTypmod = -1;
00767
00768 rec = NULL;
00769 }
00770 else
00771 {
00772 rec = PG_GETARG_HEAPTUPLEHEADER(0);
00773
00774
00775 tupType = HeapTupleHeaderGetTypeId(rec);
00776 tupTypmod = HeapTupleHeaderGetTypMod(rec);
00777 }
00778
00779 tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
00780 ncolumns = tupdesc->natts;
00781
00782
00783
00784
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
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
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
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
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
00924
00925
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
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
00948
00949
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
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
00969
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
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
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
01033
01034
01035
01036
01037
01038
01039 if (idx < 0 && rec)
01040 continue;
01041
01042
01043
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
01059
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
01127
01128
01129
01130
01131
01132
01133 for (i = 0; i < count; i++)
01134 {
01135
01136 buflen += 6 + 2 * HS_KEYLEN(entries, i);
01137
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
01219
01220
01221
01222
01223
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
01253
01254
01255
01256
01257 for (i = 0; i < count; i++)
01258 {
01259
01260 buflen += 6 + 2 * HS_KEYLEN(entries, i);
01261
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
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
01300
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
01308
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
01319
01320
01321 is_number = true;
01322 }
01323 else
01324 {
01325
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
01381
01382
01383
01384
01385 for (i = 0; i < count; i++)
01386 {
01387
01388 buflen += 6 + 2 * HS_KEYLEN(entries, i);
01389
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 }