00001
00002
00003
00004 #include "postgres.h"
00005
00006 #include "access/hash.h"
00007 #include "access/htup_details.h"
00008 #include "catalog/pg_type.h"
00009 #include "funcapi.h"
00010 #include "utils/builtins.h"
00011
00012 #include "hstore.h"
00013
00014
00015 HSTORE_POLLUTE(hstore_fetchval, fetchval);
00016 HSTORE_POLLUTE(hstore_exists, exists);
00017 HSTORE_POLLUTE(hstore_defined, defined);
00018 HSTORE_POLLUTE(hstore_delete, delete);
00019 HSTORE_POLLUTE(hstore_concat, hs_concat);
00020 HSTORE_POLLUTE(hstore_contains, hs_contains);
00021 HSTORE_POLLUTE(hstore_contained, hs_contained);
00022 HSTORE_POLLUTE(hstore_akeys, akeys);
00023 HSTORE_POLLUTE(hstore_avals, avals);
00024 HSTORE_POLLUTE(hstore_skeys, skeys);
00025 HSTORE_POLLUTE(hstore_svals, svals);
00026 HSTORE_POLLUTE(hstore_each, each);
00027
00028
00029
00030
00031
00032
00033
00034
00035 int
00036 hstoreFindKey(HStore *hs, int *lowbound, char *key, int keylen)
00037 {
00038 HEntry *entries = ARRPTR(hs);
00039 int stopLow = lowbound ? *lowbound : 0;
00040 int stopHigh = HS_COUNT(hs);
00041 int stopMiddle;
00042 char *base = STRPTR(hs);
00043
00044 while (stopLow < stopHigh)
00045 {
00046 int difference;
00047
00048 stopMiddle = stopLow + (stopHigh - stopLow) / 2;
00049
00050 if (HS_KEYLEN(entries, stopMiddle) == keylen)
00051 difference = memcmp(HS_KEY(entries, base, stopMiddle), key, keylen);
00052 else
00053 difference = (HS_KEYLEN(entries, stopMiddle) > keylen) ? 1 : -1;
00054
00055 if (difference == 0)
00056 {
00057 if (lowbound)
00058 *lowbound = stopMiddle + 1;
00059 return stopMiddle;
00060 }
00061 else if (difference < 0)
00062 stopLow = stopMiddle + 1;
00063 else
00064 stopHigh = stopMiddle;
00065 }
00066
00067 if (lowbound)
00068 *lowbound = stopLow;
00069 return -1;
00070 }
00071
00072 Pairs *
00073 hstoreArrayToPairs(ArrayType *a, int *npairs)
00074 {
00075 Datum *key_datums;
00076 bool *key_nulls;
00077 int key_count;
00078 Pairs *key_pairs;
00079 int bufsiz;
00080 int i,
00081 j;
00082
00083 deconstruct_array(a,
00084 TEXTOID, -1, false, 'i',
00085 &key_datums, &key_nulls, &key_count);
00086
00087 if (key_count == 0)
00088 {
00089 *npairs = 0;
00090 return NULL;
00091 }
00092
00093 key_pairs = palloc(sizeof(Pairs) * key_count);
00094
00095 for (i = 0, j = 0; i < key_count; i++)
00096 {
00097 if (!key_nulls[i])
00098 {
00099 key_pairs[j].key = VARDATA(key_datums[i]);
00100 key_pairs[j].keylen = VARSIZE(key_datums[i]) - VARHDRSZ;
00101 key_pairs[j].val = NULL;
00102 key_pairs[j].vallen = 0;
00103 key_pairs[j].needfree = 0;
00104 key_pairs[j].isnull = 1;
00105 j++;
00106 }
00107 }
00108
00109 *npairs = hstoreUniquePairs(key_pairs, j, &bufsiz);
00110
00111 return key_pairs;
00112 }
00113
00114
00115 PG_FUNCTION_INFO_V1(hstore_fetchval);
00116 Datum hstore_fetchval(PG_FUNCTION_ARGS);
00117 Datum
00118 hstore_fetchval(PG_FUNCTION_ARGS)
00119 {
00120 HStore *hs = PG_GETARG_HS(0);
00121 text *key = PG_GETARG_TEXT_PP(1);
00122 HEntry *entries = ARRPTR(hs);
00123 text *out;
00124 int idx = hstoreFindKey(hs, NULL,
00125 VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
00126
00127 if (idx < 0 || HS_VALISNULL(entries, idx))
00128 PG_RETURN_NULL();
00129
00130 out = cstring_to_text_with_len(HS_VAL(entries, STRPTR(hs), idx),
00131 HS_VALLEN(entries, idx));
00132
00133 PG_RETURN_TEXT_P(out);
00134 }
00135
00136
00137 PG_FUNCTION_INFO_V1(hstore_exists);
00138 Datum hstore_exists(PG_FUNCTION_ARGS);
00139 Datum
00140 hstore_exists(PG_FUNCTION_ARGS)
00141 {
00142 HStore *hs = PG_GETARG_HS(0);
00143 text *key = PG_GETARG_TEXT_PP(1);
00144 int idx = hstoreFindKey(hs, NULL,
00145 VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
00146
00147 PG_RETURN_BOOL(idx >= 0);
00148 }
00149
00150
00151 PG_FUNCTION_INFO_V1(hstore_exists_any);
00152 Datum hstore_exists_any(PG_FUNCTION_ARGS);
00153 Datum
00154 hstore_exists_any(PG_FUNCTION_ARGS)
00155 {
00156 HStore *hs = PG_GETARG_HS(0);
00157 ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1);
00158 int nkeys;
00159 Pairs *key_pairs = hstoreArrayToPairs(keys, &nkeys);
00160 int i;
00161 int lowbound = 0;
00162 bool res = false;
00163
00164
00165
00166
00167
00168
00169
00170 for (i = 0; i < nkeys; i++)
00171 {
00172 int idx = hstoreFindKey(hs, &lowbound,
00173 key_pairs[i].key, key_pairs[i].keylen);
00174
00175 if (idx >= 0)
00176 {
00177 res = true;
00178 break;
00179 }
00180 }
00181
00182 PG_RETURN_BOOL(res);
00183 }
00184
00185
00186 PG_FUNCTION_INFO_V1(hstore_exists_all);
00187 Datum hstore_exists_all(PG_FUNCTION_ARGS);
00188 Datum
00189 hstore_exists_all(PG_FUNCTION_ARGS)
00190 {
00191 HStore *hs = PG_GETARG_HS(0);
00192 ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1);
00193 int nkeys;
00194 Pairs *key_pairs = hstoreArrayToPairs(keys, &nkeys);
00195 int i;
00196 int lowbound = 0;
00197 bool res = true;
00198
00199
00200
00201
00202
00203
00204
00205 for (i = 0; i < nkeys; i++)
00206 {
00207 int idx = hstoreFindKey(hs, &lowbound,
00208 key_pairs[i].key, key_pairs[i].keylen);
00209
00210 if (idx < 0)
00211 {
00212 res = false;
00213 break;
00214 }
00215 }
00216
00217 PG_RETURN_BOOL(res);
00218 }
00219
00220
00221 PG_FUNCTION_INFO_V1(hstore_defined);
00222 Datum hstore_defined(PG_FUNCTION_ARGS);
00223 Datum
00224 hstore_defined(PG_FUNCTION_ARGS)
00225 {
00226 HStore *hs = PG_GETARG_HS(0);
00227 text *key = PG_GETARG_TEXT_PP(1);
00228 HEntry *entries = ARRPTR(hs);
00229 int idx = hstoreFindKey(hs, NULL,
00230 VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
00231 bool res = (idx >= 0 && !HS_VALISNULL(entries, idx));
00232
00233 PG_RETURN_BOOL(res);
00234 }
00235
00236
00237 PG_FUNCTION_INFO_V1(hstore_delete);
00238 Datum hstore_delete(PG_FUNCTION_ARGS);
00239 Datum
00240 hstore_delete(PG_FUNCTION_ARGS)
00241 {
00242 HStore *hs = PG_GETARG_HS(0);
00243 text *key = PG_GETARG_TEXT_PP(1);
00244 char *keyptr = VARDATA_ANY(key);
00245 int keylen = VARSIZE_ANY_EXHDR(key);
00246 HStore *out = palloc(VARSIZE(hs));
00247 char *bufs,
00248 *bufd,
00249 *ptrd;
00250 HEntry *es,
00251 *ed;
00252 int i;
00253 int count = HS_COUNT(hs);
00254 int outcount = 0;
00255
00256 SET_VARSIZE(out, VARSIZE(hs));
00257 HS_SETCOUNT(out, count);
00258
00259 bufs = STRPTR(hs);
00260 es = ARRPTR(hs);
00261 bufd = ptrd = STRPTR(out);
00262 ed = ARRPTR(out);
00263
00264 for (i = 0; i < count; ++i)
00265 {
00266 int len = HS_KEYLEN(es, i);
00267 char *ptrs = HS_KEY(es, bufs, i);
00268
00269 if (!(len == keylen && memcmp(ptrs, keyptr, keylen) == 0))
00270 {
00271 int vallen = HS_VALLEN(es, i);
00272
00273 HS_COPYITEM(ed, bufd, ptrd, ptrs, len, vallen, HS_VALISNULL(es, i));
00274 ++outcount;
00275 }
00276 }
00277
00278 HS_FINALIZE(out, outcount, bufd, ptrd);
00279
00280 PG_RETURN_POINTER(out);
00281 }
00282
00283
00284 PG_FUNCTION_INFO_V1(hstore_delete_array);
00285 Datum hstore_delete_array(PG_FUNCTION_ARGS);
00286 Datum
00287 hstore_delete_array(PG_FUNCTION_ARGS)
00288 {
00289 HStore *hs = PG_GETARG_HS(0);
00290 HStore *out = palloc(VARSIZE(hs));
00291 int hs_count = HS_COUNT(hs);
00292 char *ps,
00293 *bufd,
00294 *pd;
00295 HEntry *es,
00296 *ed;
00297 int i,
00298 j;
00299 int outcount = 0;
00300 ArrayType *key_array = PG_GETARG_ARRAYTYPE_P(1);
00301 int nkeys;
00302 Pairs *key_pairs = hstoreArrayToPairs(key_array, &nkeys);
00303
00304 SET_VARSIZE(out, VARSIZE(hs));
00305 HS_SETCOUNT(out, hs_count);
00306
00307 ps = STRPTR(hs);
00308 es = ARRPTR(hs);
00309 bufd = pd = STRPTR(out);
00310 ed = ARRPTR(out);
00311
00312 if (nkeys == 0)
00313 {
00314
00315 memcpy(out, hs, VARSIZE(hs));
00316 HS_FIXSIZE(out, hs_count);
00317 HS_SETCOUNT(out, hs_count);
00318 PG_RETURN_POINTER(out);
00319 }
00320
00321
00322
00323
00324
00325
00326 for (i = j = 0; i < hs_count;)
00327 {
00328 int difference;
00329
00330 if (j >= nkeys)
00331 difference = -1;
00332 else
00333 {
00334 int skeylen = HS_KEYLEN(es, i);
00335
00336 if (skeylen == key_pairs[j].keylen)
00337 difference = memcmp(HS_KEY(es, ps, i),
00338 key_pairs[j].key,
00339 key_pairs[j].keylen);
00340 else
00341 difference = (skeylen > key_pairs[j].keylen) ? 1 : -1;
00342 }
00343
00344 if (difference > 0)
00345 ++j;
00346 else if (difference == 0)
00347 ++i, ++j;
00348 else
00349 {
00350 HS_COPYITEM(ed, bufd, pd,
00351 HS_KEY(es, ps, i), HS_KEYLEN(es, i),
00352 HS_VALLEN(es, i), HS_VALISNULL(es, i));
00353 ++outcount;
00354 ++i;
00355 }
00356 }
00357
00358 HS_FINALIZE(out, outcount, bufd, pd);
00359
00360 PG_RETURN_POINTER(out);
00361 }
00362
00363
00364 PG_FUNCTION_INFO_V1(hstore_delete_hstore);
00365 Datum hstore_delete_hstore(PG_FUNCTION_ARGS);
00366 Datum
00367 hstore_delete_hstore(PG_FUNCTION_ARGS)
00368 {
00369 HStore *hs = PG_GETARG_HS(0);
00370 HStore *hs2 = PG_GETARG_HS(1);
00371 HStore *out = palloc(VARSIZE(hs));
00372 int hs_count = HS_COUNT(hs);
00373 int hs2_count = HS_COUNT(hs2);
00374 char *ps,
00375 *ps2,
00376 *bufd,
00377 *pd;
00378 HEntry *es,
00379 *es2,
00380 *ed;
00381 int i,
00382 j;
00383 int outcount = 0;
00384
00385 SET_VARSIZE(out, VARSIZE(hs));
00386 HS_SETCOUNT(out, hs_count);
00387
00388 ps = STRPTR(hs);
00389 es = ARRPTR(hs);
00390 ps2 = STRPTR(hs2);
00391 es2 = ARRPTR(hs2);
00392 bufd = pd = STRPTR(out);
00393 ed = ARRPTR(out);
00394
00395 if (hs2_count == 0)
00396 {
00397
00398 memcpy(out, hs, VARSIZE(hs));
00399 HS_FIXSIZE(out, hs_count);
00400 HS_SETCOUNT(out, hs_count);
00401 PG_RETURN_POINTER(out);
00402 }
00403
00404
00405
00406
00407
00408
00409
00410 for (i = j = 0; i < hs_count;)
00411 {
00412 int difference;
00413
00414 if (j >= hs2_count)
00415 difference = -1;
00416 else
00417 {
00418 int skeylen = HS_KEYLEN(es, i);
00419 int s2keylen = HS_KEYLEN(es2, j);
00420
00421 if (skeylen == s2keylen)
00422 difference = memcmp(HS_KEY(es, ps, i),
00423 HS_KEY(es2, ps2, j),
00424 skeylen);
00425 else
00426 difference = (skeylen > s2keylen) ? 1 : -1;
00427 }
00428
00429 if (difference > 0)
00430 ++j;
00431 else if (difference == 0)
00432 {
00433 int svallen = HS_VALLEN(es, i);
00434 int snullval = HS_VALISNULL(es, i);
00435
00436 if (snullval != HS_VALISNULL(es2, j)
00437 || (!snullval
00438 && (svallen != HS_VALLEN(es2, j)
00439 || memcmp(HS_VAL(es, ps, i), HS_VAL(es2, ps2, j), svallen) != 0)))
00440 {
00441 HS_COPYITEM(ed, bufd, pd,
00442 HS_KEY(es, ps, i), HS_KEYLEN(es, i),
00443 svallen, snullval);
00444 ++outcount;
00445 }
00446 ++i, ++j;
00447 }
00448 else
00449 {
00450 HS_COPYITEM(ed, bufd, pd,
00451 HS_KEY(es, ps, i), HS_KEYLEN(es, i),
00452 HS_VALLEN(es, i), HS_VALISNULL(es, i));
00453 ++outcount;
00454 ++i;
00455 }
00456 }
00457
00458 HS_FINALIZE(out, outcount, bufd, pd);
00459
00460 PG_RETURN_POINTER(out);
00461 }
00462
00463
00464 PG_FUNCTION_INFO_V1(hstore_concat);
00465 Datum hstore_concat(PG_FUNCTION_ARGS);
00466 Datum
00467 hstore_concat(PG_FUNCTION_ARGS)
00468 {
00469 HStore *s1 = PG_GETARG_HS(0);
00470 HStore *s2 = PG_GETARG_HS(1);
00471 HStore *out = palloc(VARSIZE(s1) + VARSIZE(s2));
00472 char *ps1,
00473 *ps2,
00474 *bufd,
00475 *pd;
00476 HEntry *es1,
00477 *es2,
00478 *ed;
00479 int s1idx;
00480 int s2idx;
00481 int s1count = HS_COUNT(s1);
00482 int s2count = HS_COUNT(s2);
00483 int outcount = 0;
00484
00485 SET_VARSIZE(out, VARSIZE(s1) + VARSIZE(s2) - HSHRDSIZE);
00486 HS_SETCOUNT(out, s1count + s2count);
00487
00488 if (s1count == 0)
00489 {
00490
00491 memcpy(out, s2, VARSIZE(s2));
00492 HS_FIXSIZE(out, s2count);
00493 HS_SETCOUNT(out, s2count);
00494 PG_RETURN_POINTER(out);
00495 }
00496
00497 if (s2count == 0)
00498 {
00499
00500 memcpy(out, s1, VARSIZE(s1));
00501 HS_FIXSIZE(out, s1count);
00502 HS_SETCOUNT(out, s1count);
00503 PG_RETURN_POINTER(out);
00504 }
00505
00506 ps1 = STRPTR(s1);
00507 ps2 = STRPTR(s2);
00508 bufd = pd = STRPTR(out);
00509 es1 = ARRPTR(s1);
00510 es2 = ARRPTR(s2);
00511 ed = ARRPTR(out);
00512
00513
00514
00515
00516
00517
00518 for (s1idx = s2idx = 0; s1idx < s1count || s2idx < s2count; ++outcount)
00519 {
00520 int difference;
00521
00522 if (s1idx >= s1count)
00523 difference = 1;
00524 else if (s2idx >= s2count)
00525 difference = -1;
00526 else
00527 {
00528 int s1keylen = HS_KEYLEN(es1, s1idx);
00529 int s2keylen = HS_KEYLEN(es2, s2idx);
00530
00531 if (s1keylen == s2keylen)
00532 difference = memcmp(HS_KEY(es1, ps1, s1idx),
00533 HS_KEY(es2, ps2, s2idx),
00534 s1keylen);
00535 else
00536 difference = (s1keylen > s2keylen) ? 1 : -1;
00537 }
00538
00539 if (difference >= 0)
00540 {
00541 HS_COPYITEM(ed, bufd, pd,
00542 HS_KEY(es2, ps2, s2idx), HS_KEYLEN(es2, s2idx),
00543 HS_VALLEN(es2, s2idx), HS_VALISNULL(es2, s2idx));
00544 ++s2idx;
00545 if (difference == 0)
00546 ++s1idx;
00547 }
00548 else
00549 {
00550 HS_COPYITEM(ed, bufd, pd,
00551 HS_KEY(es1, ps1, s1idx), HS_KEYLEN(es1, s1idx),
00552 HS_VALLEN(es1, s1idx), HS_VALISNULL(es1, s1idx));
00553 ++s1idx;
00554 }
00555 }
00556
00557 HS_FINALIZE(out, outcount, bufd, pd);
00558
00559 PG_RETURN_POINTER(out);
00560 }
00561
00562
00563 PG_FUNCTION_INFO_V1(hstore_slice_to_array);
00564 Datum hstore_slice_to_array(PG_FUNCTION_ARGS);
00565 Datum
00566 hstore_slice_to_array(PG_FUNCTION_ARGS)
00567 {
00568 HStore *hs = PG_GETARG_HS(0);
00569 HEntry *entries = ARRPTR(hs);
00570 char *ptr = STRPTR(hs);
00571 ArrayType *key_array = PG_GETARG_ARRAYTYPE_P(1);
00572 ArrayType *aout;
00573 Datum *key_datums;
00574 bool *key_nulls;
00575 Datum *out_datums;
00576 bool *out_nulls;
00577 int key_count;
00578 int i;
00579
00580 deconstruct_array(key_array,
00581 TEXTOID, -1, false, 'i',
00582 &key_datums, &key_nulls, &key_count);
00583
00584 if (key_count == 0)
00585 {
00586 aout = construct_empty_array(TEXTOID);
00587 PG_RETURN_POINTER(aout);
00588 }
00589
00590 out_datums = palloc(sizeof(Datum) * key_count);
00591 out_nulls = palloc(sizeof(bool) * key_count);
00592
00593 for (i = 0; i < key_count; ++i)
00594 {
00595 text *key = (text *) DatumGetPointer(key_datums[i]);
00596 int idx;
00597
00598 if (key_nulls[i])
00599 idx = -1;
00600 else
00601 idx = hstoreFindKey(hs, NULL, VARDATA(key), VARSIZE(key) - VARHDRSZ);
00602
00603 if (idx < 0 || HS_VALISNULL(entries, idx))
00604 {
00605 out_nulls[i] = true;
00606 out_datums[i] = (Datum) 0;
00607 }
00608 else
00609 {
00610 out_datums[i] = PointerGetDatum(
00611 cstring_to_text_with_len(HS_VAL(entries, ptr, idx),
00612 HS_VALLEN(entries, idx)));
00613 out_nulls[i] = false;
00614 }
00615 }
00616
00617 aout = construct_md_array(out_datums, out_nulls,
00618 ARR_NDIM(key_array),
00619 ARR_DIMS(key_array),
00620 ARR_LBOUND(key_array),
00621 TEXTOID, -1, false, 'i');
00622
00623 PG_RETURN_POINTER(aout);
00624 }
00625
00626
00627 PG_FUNCTION_INFO_V1(hstore_slice_to_hstore);
00628 Datum hstore_slice_to_hstore(PG_FUNCTION_ARGS);
00629 Datum
00630 hstore_slice_to_hstore(PG_FUNCTION_ARGS)
00631 {
00632 HStore *hs = PG_GETARG_HS(0);
00633 HEntry *entries = ARRPTR(hs);
00634 char *ptr = STRPTR(hs);
00635 ArrayType *key_array = PG_GETARG_ARRAYTYPE_P(1);
00636 HStore *out;
00637 int nkeys;
00638 Pairs *key_pairs = hstoreArrayToPairs(key_array, &nkeys);
00639 Pairs *out_pairs;
00640 int bufsiz;
00641 int lastidx = 0;
00642 int i;
00643 int out_count = 0;
00644
00645 if (nkeys == 0)
00646 {
00647 out = hstorePairs(NULL, 0, 0);
00648 PG_RETURN_POINTER(out);
00649 }
00650
00651 out_pairs = palloc(sizeof(Pairs) * nkeys);
00652 bufsiz = 0;
00653
00654
00655
00656
00657
00658
00659
00660
00661 for (i = 0; i < nkeys; ++i)
00662 {
00663 int idx = hstoreFindKey(hs, &lastidx,
00664 key_pairs[i].key, key_pairs[i].keylen);
00665
00666 if (idx >= 0)
00667 {
00668 out_pairs[out_count].key = key_pairs[i].key;
00669 bufsiz += (out_pairs[out_count].keylen = key_pairs[i].keylen);
00670 out_pairs[out_count].val = HS_VAL(entries, ptr, idx);
00671 bufsiz += (out_pairs[out_count].vallen = HS_VALLEN(entries, idx));
00672 out_pairs[out_count].isnull = HS_VALISNULL(entries, idx);
00673 out_pairs[out_count].needfree = false;
00674 ++out_count;
00675 }
00676 }
00677
00678
00679
00680
00681
00682
00683 out = hstorePairs(out_pairs, out_count, bufsiz);
00684
00685 PG_RETURN_POINTER(out);
00686 }
00687
00688
00689 PG_FUNCTION_INFO_V1(hstore_akeys);
00690 Datum hstore_akeys(PG_FUNCTION_ARGS);
00691 Datum
00692 hstore_akeys(PG_FUNCTION_ARGS)
00693 {
00694 HStore *hs = PG_GETARG_HS(0);
00695 Datum *d;
00696 ArrayType *a;
00697 HEntry *entries = ARRPTR(hs);
00698 char *base = STRPTR(hs);
00699 int count = HS_COUNT(hs);
00700 int i;
00701
00702 if (count == 0)
00703 {
00704 a = construct_empty_array(TEXTOID);
00705 PG_RETURN_POINTER(a);
00706 }
00707
00708 d = (Datum *) palloc(sizeof(Datum) * count);
00709
00710 for (i = 0; i < count; ++i)
00711 {
00712 text *item = cstring_to_text_with_len(HS_KEY(entries, base, i),
00713 HS_KEYLEN(entries, i));
00714
00715 d[i] = PointerGetDatum(item);
00716 }
00717
00718 a = construct_array(d, count,
00719 TEXTOID, -1, false, 'i');
00720
00721 PG_RETURN_POINTER(a);
00722 }
00723
00724
00725 PG_FUNCTION_INFO_V1(hstore_avals);
00726 Datum hstore_avals(PG_FUNCTION_ARGS);
00727 Datum
00728 hstore_avals(PG_FUNCTION_ARGS)
00729 {
00730 HStore *hs = PG_GETARG_HS(0);
00731 Datum *d;
00732 bool *nulls;
00733 ArrayType *a;
00734 HEntry *entries = ARRPTR(hs);
00735 char *base = STRPTR(hs);
00736 int count = HS_COUNT(hs);
00737 int lb = 1;
00738 int i;
00739
00740 if (count == 0)
00741 {
00742 a = construct_empty_array(TEXTOID);
00743 PG_RETURN_POINTER(a);
00744 }
00745
00746 d = (Datum *) palloc(sizeof(Datum) * count);
00747 nulls = (bool *) palloc(sizeof(bool) * count);
00748
00749 for (i = 0; i < count; ++i)
00750 {
00751 if (HS_VALISNULL(entries, i))
00752 {
00753 d[i] = (Datum) 0;
00754 nulls[i] = true;
00755 }
00756 else
00757 {
00758 text *item = cstring_to_text_with_len(HS_VAL(entries, base, i),
00759 HS_VALLEN(entries, i));
00760
00761 d[i] = PointerGetDatum(item);
00762 nulls[i] = false;
00763 }
00764 }
00765
00766 a = construct_md_array(d, nulls, 1, &count, &lb,
00767 TEXTOID, -1, false, 'i');
00768
00769 PG_RETURN_POINTER(a);
00770 }
00771
00772
00773 static ArrayType *
00774 hstore_to_array_internal(HStore *hs, int ndims)
00775 {
00776 HEntry *entries = ARRPTR(hs);
00777 char *base = STRPTR(hs);
00778 int count = HS_COUNT(hs);
00779 int out_size[2] = {0, 2};
00780 int lb[2] = {1, 1};
00781 Datum *out_datums;
00782 bool *out_nulls;
00783 int i;
00784
00785 Assert(ndims < 3);
00786
00787 if (count == 0 || ndims == 0)
00788 return construct_empty_array(TEXTOID);
00789
00790 out_size[0] = count * 2 / ndims;
00791 out_datums = palloc(sizeof(Datum) * count * 2);
00792 out_nulls = palloc(sizeof(bool) * count * 2);
00793
00794 for (i = 0; i < count; ++i)
00795 {
00796 text *key = cstring_to_text_with_len(HS_KEY(entries, base, i),
00797 HS_KEYLEN(entries, i));
00798
00799 out_datums[i * 2] = PointerGetDatum(key);
00800 out_nulls[i * 2] = false;
00801
00802 if (HS_VALISNULL(entries, i))
00803 {
00804 out_datums[i * 2 + 1] = (Datum) 0;
00805 out_nulls[i * 2 + 1] = true;
00806 }
00807 else
00808 {
00809 text *item = cstring_to_text_with_len(HS_VAL(entries, base, i),
00810 HS_VALLEN(entries, i));
00811
00812 out_datums[i * 2 + 1] = PointerGetDatum(item);
00813 out_nulls[i * 2 + 1] = false;
00814 }
00815 }
00816
00817 return construct_md_array(out_datums, out_nulls,
00818 ndims, out_size, lb,
00819 TEXTOID, -1, false, 'i');
00820 }
00821
00822 PG_FUNCTION_INFO_V1(hstore_to_array);
00823 Datum hstore_to_array(PG_FUNCTION_ARGS);
00824 Datum
00825 hstore_to_array(PG_FUNCTION_ARGS)
00826 {
00827 HStore *hs = PG_GETARG_HS(0);
00828 ArrayType *out = hstore_to_array_internal(hs, 1);
00829
00830 PG_RETURN_POINTER(out);
00831 }
00832
00833 PG_FUNCTION_INFO_V1(hstore_to_matrix);
00834 Datum hstore_to_matrix(PG_FUNCTION_ARGS);
00835 Datum
00836 hstore_to_matrix(PG_FUNCTION_ARGS)
00837 {
00838 HStore *hs = PG_GETARG_HS(0);
00839 ArrayType *out = hstore_to_array_internal(hs, 2);
00840
00841 PG_RETURN_POINTER(out);
00842 }
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853 static void
00854 setup_firstcall(FuncCallContext *funcctx, HStore *hs,
00855 FunctionCallInfoData *fcinfo)
00856 {
00857 MemoryContext oldcontext;
00858 HStore *st;
00859
00860 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
00861
00862 st = (HStore *) palloc(VARSIZE(hs));
00863 memcpy(st, hs, VARSIZE(hs));
00864
00865 funcctx->user_fctx = (void *) st;
00866
00867 if (fcinfo)
00868 {
00869 TupleDesc tupdesc;
00870
00871
00872 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
00873 elog(ERROR, "return type must be a row type");
00874
00875 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
00876 }
00877
00878 MemoryContextSwitchTo(oldcontext);
00879 }
00880
00881
00882 PG_FUNCTION_INFO_V1(hstore_skeys);
00883 Datum hstore_skeys(PG_FUNCTION_ARGS);
00884 Datum
00885 hstore_skeys(PG_FUNCTION_ARGS)
00886 {
00887 FuncCallContext *funcctx;
00888 HStore *hs;
00889 int i;
00890
00891 if (SRF_IS_FIRSTCALL())
00892 {
00893 hs = PG_GETARG_HS(0);
00894 funcctx = SRF_FIRSTCALL_INIT();
00895 setup_firstcall(funcctx, hs, NULL);
00896 }
00897
00898 funcctx = SRF_PERCALL_SETUP();
00899 hs = (HStore *) funcctx->user_fctx;
00900 i = funcctx->call_cntr;
00901
00902 if (i < HS_COUNT(hs))
00903 {
00904 HEntry *entries = ARRPTR(hs);
00905 text *item;
00906
00907 item = cstring_to_text_with_len(HS_KEY(entries, STRPTR(hs), i),
00908 HS_KEYLEN(entries, i));
00909
00910 SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
00911 }
00912
00913 SRF_RETURN_DONE(funcctx);
00914 }
00915
00916
00917 PG_FUNCTION_INFO_V1(hstore_svals);
00918 Datum hstore_svals(PG_FUNCTION_ARGS);
00919 Datum
00920 hstore_svals(PG_FUNCTION_ARGS)
00921 {
00922 FuncCallContext *funcctx;
00923 HStore *hs;
00924 int i;
00925
00926 if (SRF_IS_FIRSTCALL())
00927 {
00928 hs = PG_GETARG_HS(0);
00929 funcctx = SRF_FIRSTCALL_INIT();
00930 setup_firstcall(funcctx, hs, NULL);
00931 }
00932
00933 funcctx = SRF_PERCALL_SETUP();
00934 hs = (HStore *) funcctx->user_fctx;
00935 i = funcctx->call_cntr;
00936
00937 if (i < HS_COUNT(hs))
00938 {
00939 HEntry *entries = ARRPTR(hs);
00940
00941 if (HS_VALISNULL(entries, i))
00942 {
00943 ReturnSetInfo *rsi;
00944
00945
00946 (funcctx)->call_cntr++;
00947 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
00948 rsi->isDone = ExprMultipleResult;
00949 PG_RETURN_NULL();
00950 }
00951 else
00952 {
00953 text *item;
00954
00955 item = cstring_to_text_with_len(HS_VAL(entries, STRPTR(hs), i),
00956 HS_VALLEN(entries, i));
00957
00958 SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
00959 }
00960 }
00961
00962 SRF_RETURN_DONE(funcctx);
00963 }
00964
00965
00966 PG_FUNCTION_INFO_V1(hstore_contains);
00967 Datum hstore_contains(PG_FUNCTION_ARGS);
00968 Datum
00969 hstore_contains(PG_FUNCTION_ARGS)
00970 {
00971 HStore *val = PG_GETARG_HS(0);
00972 HStore *tmpl = PG_GETARG_HS(1);
00973 bool res = true;
00974 HEntry *te = ARRPTR(tmpl);
00975 char *tstr = STRPTR(tmpl);
00976 HEntry *ve = ARRPTR(val);
00977 char *vstr = STRPTR(val);
00978 int tcount = HS_COUNT(tmpl);
00979 int lastidx = 0;
00980 int i;
00981
00982
00983
00984
00985
00986
00987
00988
00989 for (i = 0; res && i < tcount; ++i)
00990 {
00991 int idx = hstoreFindKey(val, &lastidx,
00992 HS_KEY(te, tstr, i), HS_KEYLEN(te, i));
00993
00994 if (idx >= 0)
00995 {
00996 bool nullval = HS_VALISNULL(te, i);
00997 int vallen = HS_VALLEN(te, i);
00998
00999 if (nullval != HS_VALISNULL(ve, idx)
01000 || (!nullval
01001 && (vallen != HS_VALLEN(ve, idx)
01002 || memcmp(HS_VAL(te, tstr, i), HS_VAL(ve, vstr, idx), vallen))))
01003 res = false;
01004 }
01005 else
01006 res = false;
01007 }
01008
01009 PG_RETURN_BOOL(res);
01010 }
01011
01012
01013 PG_FUNCTION_INFO_V1(hstore_contained);
01014 Datum hstore_contained(PG_FUNCTION_ARGS);
01015 Datum
01016 hstore_contained(PG_FUNCTION_ARGS)
01017 {
01018 PG_RETURN_DATUM(DirectFunctionCall2(hstore_contains,
01019 PG_GETARG_DATUM(1),
01020 PG_GETARG_DATUM(0)
01021 ));
01022 }
01023
01024
01025 PG_FUNCTION_INFO_V1(hstore_each);
01026 Datum hstore_each(PG_FUNCTION_ARGS);
01027 Datum
01028 hstore_each(PG_FUNCTION_ARGS)
01029 {
01030 FuncCallContext *funcctx;
01031 HStore *hs;
01032 int i;
01033
01034 if (SRF_IS_FIRSTCALL())
01035 {
01036 hs = PG_GETARG_HS(0);
01037 funcctx = SRF_FIRSTCALL_INIT();
01038 setup_firstcall(funcctx, hs, fcinfo);
01039 }
01040
01041 funcctx = SRF_PERCALL_SETUP();
01042 hs = (HStore *) funcctx->user_fctx;
01043 i = funcctx->call_cntr;
01044
01045 if (i < HS_COUNT(hs))
01046 {
01047 HEntry *entries = ARRPTR(hs);
01048 char *ptr = STRPTR(hs);
01049 Datum res,
01050 dvalues[2];
01051 bool nulls[2] = {false, false};
01052 text *item;
01053 HeapTuple tuple;
01054
01055 item = cstring_to_text_with_len(HS_KEY(entries, ptr, i),
01056 HS_KEYLEN(entries, i));
01057 dvalues[0] = PointerGetDatum(item);
01058
01059 if (HS_VALISNULL(entries, i))
01060 {
01061 dvalues[1] = (Datum) 0;
01062 nulls[1] = true;
01063 }
01064 else
01065 {
01066 item = cstring_to_text_with_len(HS_VAL(entries, ptr, i),
01067 HS_VALLEN(entries, i));
01068 dvalues[1] = PointerGetDatum(item);
01069 }
01070
01071 tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
01072 res = HeapTupleGetDatum(tuple);
01073
01074 SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
01075 }
01076
01077 SRF_RETURN_DONE(funcctx);
01078 }
01079
01080
01081
01082
01083
01084
01085
01086
01087 PG_FUNCTION_INFO_V1(hstore_cmp);
01088 Datum hstore_cmp(PG_FUNCTION_ARGS);
01089 Datum
01090 hstore_cmp(PG_FUNCTION_ARGS)
01091 {
01092 HStore *hs1 = PG_GETARG_HS(0);
01093 HStore *hs2 = PG_GETARG_HS(1);
01094 int hcount1 = HS_COUNT(hs1);
01095 int hcount2 = HS_COUNT(hs2);
01096 int res = 0;
01097
01098 if (hcount1 == 0 || hcount2 == 0)
01099 {
01100
01101
01102
01103
01104 if (hcount1 > 0)
01105 res = 1;
01106 else if (hcount2 > 0)
01107 res = -1;
01108 }
01109 else
01110 {
01111
01112 char *str1 = STRPTR(hs1);
01113 char *str2 = STRPTR(hs2);
01114 HEntry *ent1 = ARRPTR(hs1);
01115 HEntry *ent2 = ARRPTR(hs2);
01116 size_t len1 = HSE_ENDPOS(ent1[2 * hcount1 - 1]);
01117 size_t len2 = HSE_ENDPOS(ent2[2 * hcount2 - 1]);
01118
01119 res = memcmp(str1, str2, Min(len1, len2));
01120
01121 if (res == 0)
01122 {
01123 if (len1 > len2)
01124 res = 1;
01125 else if (len1 < len2)
01126 res = -1;
01127 else if (hcount1 > hcount2)
01128 res = 1;
01129 else if (hcount2 > hcount1)
01130 res = -1;
01131 else
01132 {
01133 int count = hcount1 * 2;
01134 int i;
01135
01136 for (i = 0; i < count; ++i)
01137 if (HSE_ENDPOS(ent1[i]) != HSE_ENDPOS(ent2[i]) ||
01138 HSE_ISNULL(ent1[i]) != HSE_ISNULL(ent2[i]))
01139 break;
01140 if (i < count)
01141 {
01142 if (HSE_ENDPOS(ent1[i]) < HSE_ENDPOS(ent2[i]))
01143 res = -1;
01144 else if (HSE_ENDPOS(ent1[i]) > HSE_ENDPOS(ent2[i]))
01145 res = 1;
01146 else if (HSE_ISNULL(ent1[i]))
01147 res = 1;
01148 else if (HSE_ISNULL(ent2[i]))
01149 res = -1;
01150 }
01151 }
01152 }
01153 else
01154 {
01155 res = (res > 0) ? 1 : -1;
01156 }
01157 }
01158
01159
01160
01161
01162
01163 PG_FREE_IF_COPY(hs1, 0);
01164 PG_FREE_IF_COPY(hs2, 1);
01165 PG_RETURN_INT32(res);
01166 }
01167
01168
01169 PG_FUNCTION_INFO_V1(hstore_eq);
01170 Datum hstore_eq(PG_FUNCTION_ARGS);
01171 Datum
01172 hstore_eq(PG_FUNCTION_ARGS)
01173 {
01174 int res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
01175 PG_GETARG_DATUM(0),
01176 PG_GETARG_DATUM(1)));
01177
01178 PG_RETURN_BOOL(res == 0);
01179 }
01180
01181 PG_FUNCTION_INFO_V1(hstore_ne);
01182 Datum hstore_ne(PG_FUNCTION_ARGS);
01183 Datum
01184 hstore_ne(PG_FUNCTION_ARGS)
01185 {
01186 int res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
01187 PG_GETARG_DATUM(0),
01188 PG_GETARG_DATUM(1)));
01189
01190 PG_RETURN_BOOL(res != 0);
01191 }
01192
01193 PG_FUNCTION_INFO_V1(hstore_gt);
01194 Datum hstore_gt(PG_FUNCTION_ARGS);
01195 Datum
01196 hstore_gt(PG_FUNCTION_ARGS)
01197 {
01198 int res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
01199 PG_GETARG_DATUM(0),
01200 PG_GETARG_DATUM(1)));
01201
01202 PG_RETURN_BOOL(res > 0);
01203 }
01204
01205 PG_FUNCTION_INFO_V1(hstore_ge);
01206 Datum hstore_ge(PG_FUNCTION_ARGS);
01207 Datum
01208 hstore_ge(PG_FUNCTION_ARGS)
01209 {
01210 int res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
01211 PG_GETARG_DATUM(0),
01212 PG_GETARG_DATUM(1)));
01213
01214 PG_RETURN_BOOL(res >= 0);
01215 }
01216
01217 PG_FUNCTION_INFO_V1(hstore_lt);
01218 Datum hstore_lt(PG_FUNCTION_ARGS);
01219 Datum
01220 hstore_lt(PG_FUNCTION_ARGS)
01221 {
01222 int res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
01223 PG_GETARG_DATUM(0),
01224 PG_GETARG_DATUM(1)));
01225
01226 PG_RETURN_BOOL(res < 0);
01227 }
01228
01229 PG_FUNCTION_INFO_V1(hstore_le);
01230 Datum hstore_le(PG_FUNCTION_ARGS);
01231 Datum
01232 hstore_le(PG_FUNCTION_ARGS)
01233 {
01234 int res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
01235 PG_GETARG_DATUM(0),
01236 PG_GETARG_DATUM(1)));
01237
01238 PG_RETURN_BOOL(res <= 0);
01239 }
01240
01241
01242 PG_FUNCTION_INFO_V1(hstore_hash);
01243 Datum hstore_hash(PG_FUNCTION_ARGS);
01244 Datum
01245 hstore_hash(PG_FUNCTION_ARGS)
01246 {
01247 HStore *hs = PG_GETARG_HS(0);
01248 Datum hval = hash_any((unsigned char *) VARDATA(hs),
01249 VARSIZE(hs) - VARHDRSZ);
01250
01251
01252
01253
01254
01255
01256 Assert(VARSIZE(hs) ==
01257 (HS_COUNT(hs) != 0 ?
01258 CALCDATASIZE(HS_COUNT(hs),
01259 HSE_ENDPOS(ARRPTR(hs)[2 * HS_COUNT(hs) - 1])) :
01260 HSHRDSIZE));
01261
01262 PG_FREE_IF_COPY(hs, 0);
01263 PG_RETURN_DATUM(hval);
01264 }