Age Owner TLA Line data Source code
1 : /*
2 : * contrib/hstore/hstore_gin.c
3 : */
4 : #include "postgres.h"
5 :
6 : #include "access/gin.h"
7 : #include "access/stratnum.h"
8 : #include "catalog/pg_type.h"
9 :
10 : #include "hstore.h"
11 :
12 :
13 : /*
14 : * When using a GIN index for hstore, we choose to index both keys and values.
15 : * The storage format is "text" values, with K, V, or N prepended to the string
16 : * to indicate key, value, or null values. (As of 9.1 it might be better to
17 : * store null values as nulls, but we'll keep it this way for on-disk
18 : * compatibility.)
19 : */
20 : #define KEYFLAG 'K'
21 : #define VALFLAG 'V'
22 : #define NULLFLAG 'N'
23 :
5870 teodor 24 CBC 8 : PG_FUNCTION_INFO_V1(gin_extract_hstore);
25 :
26 : /* Build an indexable text value */
27 : static text *
4473 tgl 28 9588 : makeitem(char *str, int len, char flag)
29 : {
30 : text *item;
31 :
5624 bruce 32 9588 : item = (text *) palloc(VARHDRSZ + len + 1);
5870 teodor 33 9588 : SET_VARSIZE(item, VARHDRSZ + len + 1);
34 :
4473 tgl 35 9588 : *VARDATA(item) = flag;
36 :
5624 bruce 37 9588 : if (str && len > 0)
38 9585 : memcpy(VARDATA(item) + 1, str, len);
39 :
5870 teodor 40 9588 : return item;
41 : }
42 :
43 : Datum
44 1007 : gin_extract_hstore(PG_FUNCTION_ARGS)
45 : {
2029 tgl 46 1007 : HStore *hs = PG_GETARG_HSTORE_P(0);
5624 bruce 47 1007 : int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
48 1007 : Datum *entries = NULL;
4790 49 1007 : HEntry *hsent = ARRPTR(hs);
50 1007 : char *ptr = STRPTR(hs);
51 1007 : int count = HS_COUNT(hs);
52 : int i;
53 :
4939 tgl 54 1007 : *nentries = 2 * count;
55 1007 : if (count)
56 890 : entries = (Datum *) palloc(sizeof(Datum) * 2 * count);
57 :
58 5796 : for (i = 0; i < count; ++i)
59 : {
60 : text *item;
61 :
2698 62 4789 : item = makeitem(HSTORE_KEY(hsent, ptr, i),
63 4789 : HSTORE_KEYLEN(hsent, i),
64 : KEYFLAG);
4790 bruce 65 4789 : entries[2 * i] = PointerGetDatum(item);
66 :
2698 tgl 67 4789 : if (HSTORE_VALISNULL(hsent, i))
4473 68 3 : item = makeitem(NULL, 0, NULLFLAG);
69 : else
2698 70 4786 : item = makeitem(HSTORE_VAL(hsent, ptr, i),
71 4786 : HSTORE_VALLEN(hsent, i),
72 : VALFLAG);
4790 bruce 73 4789 : entries[2 * i + 1] = PointerGetDatum(item);
74 : }
75 :
5870 teodor 76 1007 : PG_RETURN_POINTER(entries);
77 : }
78 :
79 8 : PG_FUNCTION_INFO_V1(gin_extract_hstore_query);
80 :
81 : Datum
82 12 : gin_extract_hstore_query(PG_FUNCTION_ARGS)
83 : {
4473 tgl 84 12 : int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
5870 teodor 85 12 : StrategyNumber strategy = PG_GETARG_UINT16(2);
4473 tgl 86 12 : int32 *searchMode = (int32 *) PG_GETARG_POINTER(6);
87 : Datum *entries;
88 :
5624 bruce 89 12 : if (strategy == HStoreContainsStrategyNumber)
90 : {
91 : /* Query is an hstore, so just apply gin_extract_hstore... */
92 : entries = (Datum *)
4473 tgl 93 6 : DatumGetPointer(DirectFunctionCall2(gin_extract_hstore,
94 : PG_GETARG_DATUM(0),
95 : PointerGetDatum(nentries)));
96 : /* ... except that "contains {}" requires a full index scan */
97 6 : if (entries == NULL)
4473 tgl 98 UBC 0 : *searchMode = GIN_SEARCH_MODE_ALL;
99 : }
5624 bruce 100 CBC 6 : else if (strategy == HStoreExistsStrategyNumber)
101 : {
4473 tgl 102 2 : text *query = PG_GETARG_TEXT_PP(0);
103 : text *item;
104 :
5870 teodor 105 2 : *nentries = 1;
5624 bruce 106 2 : entries = (Datum *) palloc(sizeof(Datum));
4473 tgl 107 2 : item = makeitem(VARDATA_ANY(query), VARSIZE_ANY_EXHDR(query), KEYFLAG);
5870 teodor 108 2 : entries[0] = PointerGetDatum(item);
109 : }
4939 tgl 110 4 : else if (strategy == HStoreExistsAnyStrategyNumber ||
111 : strategy == HStoreExistsAllStrategyNumber)
112 4 : {
4790 bruce 113 4 : ArrayType *query = PG_GETARG_ARRAYTYPE_P(0);
114 : Datum *key_datums;
115 : bool *key_nulls;
116 : int key_count;
117 : int i,
118 : j;
119 : text *item;
120 :
282 peter 121 GNC 4 : deconstruct_array_builtin(query, TEXTOID, &key_datums, &key_nulls, &key_count);
122 :
4939 tgl 123 CBC 4 : entries = (Datum *) palloc(sizeof(Datum) * key_count);
124 :
4939 tgl 125 GIC 12 : for (i = 0, j = 0; i < key_count; ++i)
4939 tgl 126 ECB : {
4473 tgl 127 EUB : /* Nulls in the array are ignored, cf hstoreArrayToPairs */
4939 tgl 128 CBC 8 : if (key_nulls[i])
4939 tgl 129 LBC 0 : continue;
4473 tgl 130 GIC 8 : item = makeitem(VARDATA(key_datums[i]), VARSIZE(key_datums[i]) - VARHDRSZ, KEYFLAG);
4939 131 8 : entries[j++] = PointerGetDatum(item);
4939 tgl 132 ECB : }
133 :
4473 tgl 134 CBC 4 : *nentries = j;
4473 tgl 135 EUB : /* ExistsAll with no keys should match everything */
4473 tgl 136 GIC 4 : if (j == 0 && strategy == HStoreExistsAllStrategyNumber)
4473 tgl 137 UIC 0 : *searchMode = GIN_SEARCH_MODE_ALL;
138 : }
5870 teodor 139 EUB : else
140 : {
4473 tgl 141 UIC 0 : elog(ERROR, "unrecognized strategy number: %d", strategy);
142 : entries = NULL; /* keep compiler quiet */
4473 tgl 143 ECB : }
144 :
4473 tgl 145 GIC 12 : PG_RETURN_POINTER(entries);
5870 teodor 146 ECB : }
147 :
5870 teodor 148 GIC 8 : PG_FUNCTION_INFO_V1(gin_consistent_hstore);
5870 teodor 149 ECB :
150 : Datum
5870 teodor 151 CBC 955 : gin_consistent_hstore(PG_FUNCTION_ARGS)
5870 teodor 152 ECB : {
5473 tgl 153 GIC 955 : bool *check = (bool *) PG_GETARG_POINTER(0);
5870 teodor 154 955 : StrategyNumber strategy = PG_GETARG_UINT16(1);
4790 bruce 155 ECB :
156 : /* HStore *query = PG_GETARG_HSTORE_P(2); */
4939 tgl 157 GIC 955 : int32 nkeys = PG_GETARG_INT32(3);
4790 bruce 158 ECB :
5128 tgl 159 : /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
5128 tgl 160 GIC 955 : bool *recheck = (bool *) PG_GETARG_POINTER(5);
5624 bruce 161 955 : bool res = true;
4473 tgl 162 ECB : int32 i;
163 :
5624 bruce 164 GIC 955 : if (strategy == HStoreContainsStrategyNumber)
165 : {
166 : /*
167 : * Index doesn't have information about correspondence of keys and
168 : * values, so we need recheck. However, if not all the keys are
4473 tgl 169 ECB : * present, we can fail at once.
5473 170 : */
5473 tgl 171 GIC 235 : *recheck = true;
4473 tgl 172 CBC 375 : for (i = 0; i < nkeys; i++)
173 : {
174 339 : if (!check[i])
4473 tgl 175 ECB : {
5870 teodor 176 GIC 199 : res = false;
4473 tgl 177 199 : break;
178 : }
4473 tgl 179 ECB : }
180 : }
5624 bruce 181 GIC 720 : else if (strategy == HStoreExistsStrategyNumber)
5473 tgl 182 ECB : {
4473 183 : /* Existence of key is guaranteed in default search mode */
4473 tgl 184 GIC 194 : *recheck = false;
5870 teodor 185 CBC 194 : res = true;
186 : }
4939 tgl 187 GIC 526 : else if (strategy == HStoreExistsAnyStrategyNumber)
4939 tgl 188 ECB : {
4473 189 : /* Existence of key is guaranteed in default search mode */
4473 tgl 190 GIC 339 : *recheck = false;
4939 tgl 191 CBC 339 : res = true;
192 : }
4939 tgl 193 GIC 187 : else if (strategy == HStoreExistsAllStrategyNumber)
4939 tgl 194 ECB : {
4473 195 : /* Testing for all the keys being present gives an exact result */
4473 tgl 196 GIC 187 : *recheck = false;
4473 tgl 197 CBC 272 : for (i = 0; i < nkeys; i++)
198 : {
4939 199 230 : if (!check[i])
4473 tgl 200 ECB : {
4939 tgl 201 GIC 145 : res = false;
4473 202 145 : break;
203 : }
204 : }
4939 tgl 205 EUB : }
206 : else
4473 tgl 207 LBC 0 : elog(ERROR, "unrecognized strategy number: %d", strategy);
208 :
5870 teodor 209 GIC 955 : PG_RETURN_BOOL(res);
210 : }
|