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 :
24 0 : PG_FUNCTION_INFO_V1(gin_extract_hstore);
25 :
26 : /* Build an indexable text value */
27 : static text *
28 0 : makeitem(char *str, int len, char flag)
29 : {
30 0 : text *item;
31 :
32 0 : item = (text *) palloc(VARHDRSZ + len + 1);
33 0 : SET_VARSIZE(item, VARHDRSZ + len + 1);
34 :
35 0 : *VARDATA(item) = flag;
36 :
37 0 : if (str && len > 0)
38 0 : memcpy(VARDATA(item) + 1, str, len);
39 :
40 0 : return item;
41 0 : }
42 :
43 : Datum
44 0 : gin_extract_hstore(PG_FUNCTION_ARGS)
45 : {
46 0 : HStore *hs = PG_GETARG_HSTORE_P(0);
47 0 : int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
48 0 : Datum *entries = NULL;
49 0 : HEntry *hsent = ARRPTR(hs);
50 0 : char *ptr = STRPTR(hs);
51 0 : int count = HS_COUNT(hs);
52 0 : int i;
53 :
54 0 : *nentries = 2 * count;
55 0 : if (count)
56 0 : entries = (Datum *) palloc(sizeof(Datum) * 2 * count);
57 :
58 0 : for (i = 0; i < count; ++i)
59 : {
60 0 : text *item;
61 :
62 0 : item = makeitem(HSTORE_KEY(hsent, ptr, i),
63 0 : HSTORE_KEYLEN(hsent, i),
64 : KEYFLAG);
65 0 : entries[2 * i] = PointerGetDatum(item);
66 :
67 0 : if (HSTORE_VALISNULL(hsent, i))
68 0 : item = makeitem(NULL, 0, NULLFLAG);
69 : else
70 0 : item = makeitem(HSTORE_VAL(hsent, ptr, i),
71 0 : HSTORE_VALLEN(hsent, i),
72 : VALFLAG);
73 0 : entries[2 * i + 1] = PointerGetDatum(item);
74 0 : }
75 :
76 0 : PG_RETURN_POINTER(entries);
77 0 : }
78 :
79 0 : PG_FUNCTION_INFO_V1(gin_extract_hstore_query);
80 :
81 : Datum
82 0 : gin_extract_hstore_query(PG_FUNCTION_ARGS)
83 : {
84 0 : int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
85 0 : StrategyNumber strategy = PG_GETARG_UINT16(2);
86 0 : int32 *searchMode = (int32 *) PG_GETARG_POINTER(6);
87 0 : Datum *entries;
88 :
89 0 : if (strategy == HStoreContainsStrategyNumber)
90 : {
91 : /* Query is an hstore, so just apply gin_extract_hstore... */
92 0 : entries = (Datum *)
93 0 : DatumGetPointer(DirectFunctionCall2(gin_extract_hstore,
94 : PG_GETARG_DATUM(0),
95 : PointerGetDatum(nentries)));
96 : /* ... except that "contains {}" requires a full index scan */
97 0 : if (entries == NULL)
98 0 : *searchMode = GIN_SEARCH_MODE_ALL;
99 0 : }
100 0 : else if (strategy == HStoreExistsStrategyNumber)
101 : {
102 0 : text *query = PG_GETARG_TEXT_PP(0);
103 0 : text *item;
104 :
105 0 : *nentries = 1;
106 0 : entries = (Datum *) palloc(sizeof(Datum));
107 0 : item = makeitem(VARDATA_ANY(query), VARSIZE_ANY_EXHDR(query), KEYFLAG);
108 0 : entries[0] = PointerGetDatum(item);
109 0 : }
110 0 : else if (strategy == HStoreExistsAnyStrategyNumber ||
111 0 : strategy == HStoreExistsAllStrategyNumber)
112 : {
113 0 : ArrayType *query = PG_GETARG_ARRAYTYPE_P(0);
114 0 : Datum *key_datums;
115 0 : bool *key_nulls;
116 0 : int key_count;
117 0 : int i,
118 : j;
119 0 : text *item;
120 :
121 0 : deconstruct_array_builtin(query, TEXTOID, &key_datums, &key_nulls, &key_count);
122 :
123 0 : entries = (Datum *) palloc(sizeof(Datum) * key_count);
124 :
125 0 : for (i = 0, j = 0; i < key_count; ++i)
126 : {
127 : /* Nulls in the array are ignored, cf hstoreArrayToPairs */
128 0 : if (key_nulls[i])
129 0 : continue;
130 0 : item = makeitem(VARDATA(DatumGetPointer(key_datums[i])), VARSIZE(DatumGetPointer(key_datums[i])) - VARHDRSZ, KEYFLAG);
131 0 : entries[j++] = PointerGetDatum(item);
132 0 : }
133 :
134 0 : *nentries = j;
135 : /* ExistsAll with no keys should match everything */
136 0 : if (j == 0 && strategy == HStoreExistsAllStrategyNumber)
137 0 : *searchMode = GIN_SEARCH_MODE_ALL;
138 0 : }
139 : else
140 : {
141 0 : elog(ERROR, "unrecognized strategy number: %d", strategy);
142 0 : entries = NULL; /* keep compiler quiet */
143 : }
144 :
145 0 : PG_RETURN_POINTER(entries);
146 0 : }
147 :
148 0 : PG_FUNCTION_INFO_V1(gin_consistent_hstore);
149 :
150 : Datum
151 0 : gin_consistent_hstore(PG_FUNCTION_ARGS)
152 : {
153 0 : bool *check = (bool *) PG_GETARG_POINTER(0);
154 0 : StrategyNumber strategy = PG_GETARG_UINT16(1);
155 : #ifdef NOT_USED
156 : HStore *query = PG_GETARG_HSTORE_P(2);
157 : #endif
158 0 : int32 nkeys = PG_GETARG_INT32(3);
159 : #ifdef NOT_USED
160 : Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4);
161 : #endif
162 0 : bool *recheck = (bool *) PG_GETARG_POINTER(5);
163 0 : bool res = true;
164 0 : int32 i;
165 :
166 0 : if (strategy == HStoreContainsStrategyNumber)
167 : {
168 : /*
169 : * Index doesn't have information about correspondence of keys and
170 : * values, so we need recheck. However, if not all the keys are
171 : * present, we can fail at once.
172 : */
173 0 : *recheck = true;
174 0 : for (i = 0; i < nkeys; i++)
175 : {
176 0 : if (!check[i])
177 : {
178 0 : res = false;
179 0 : break;
180 : }
181 0 : }
182 0 : }
183 0 : else if (strategy == HStoreExistsStrategyNumber)
184 : {
185 : /* Existence of key is guaranteed in default search mode */
186 0 : *recheck = false;
187 0 : res = true;
188 0 : }
189 0 : else if (strategy == HStoreExistsAnyStrategyNumber)
190 : {
191 : /* Existence of key is guaranteed in default search mode */
192 0 : *recheck = false;
193 0 : res = true;
194 0 : }
195 0 : else if (strategy == HStoreExistsAllStrategyNumber)
196 : {
197 : /* Testing for all the keys being present gives an exact result */
198 0 : *recheck = false;
199 0 : for (i = 0; i < nkeys; i++)
200 : {
201 0 : if (!check[i])
202 : {
203 0 : res = false;
204 0 : break;
205 : }
206 0 : }
207 0 : }
208 : else
209 0 : elog(ERROR, "unrecognized strategy number: %d", strategy);
210 :
211 0 : PG_RETURN_BOOL(res);
212 0 : }
|