Age Owner Branch data 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 : :
6941 teodor@sigaev.ru 24 :CBC 8 : PG_FUNCTION_INFO_V1(gin_extract_hstore);
25 : :
26 : : /* Build an indexable text value */
27 : : static text *
5544 tgl@sss.pgh.pa.us 28 : 9588 : makeitem(char *str, int len, char flag)
29 : : {
30 : : text *item;
31 : :
6695 bruce@momjian.us 32 : 9588 : item = (text *) palloc(VARHDRSZ + len + 1);
6941 teodor@sigaev.ru 33 : 9588 : SET_VARSIZE(item, VARHDRSZ + len + 1);
34 : :
5544 tgl@sss.pgh.pa.us 35 : 9588 : *VARDATA(item) = flag;
36 : :
6695 bruce@momjian.us 37 [ + + + - ]: 9588 : if (str && len > 0)
38 : 9585 : memcpy(VARDATA(item) + 1, str, len);
39 : :
6941 teodor@sigaev.ru 40 : 9588 : return item;
41 : : }
42 : :
43 : : Datum
44 : 1007 : gin_extract_hstore(PG_FUNCTION_ARGS)
45 : : {
3100 tgl@sss.pgh.pa.us 46 : 1007 : HStore *hs = PG_GETARG_HSTORE_P(0);
6695 bruce@momjian.us 47 : 1007 : int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
48 : 1007 : Datum *entries = NULL;
5861 49 : 1007 : HEntry *hsent = ARRPTR(hs);
50 : 1007 : char *ptr = STRPTR(hs);
51 : 1007 : int count = HS_COUNT(hs);
52 : : int i;
53 : :
6010 tgl@sss.pgh.pa.us 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 : :
3769 62 [ + + ]: 4789 : item = makeitem(HSTORE_KEY(hsent, ptr, i),
63 [ + + ]: 4789 : HSTORE_KEYLEN(hsent, i),
64 : : KEYFLAG);
5861 bruce@momjian.us 65 : 4789 : entries[2 * i] = PointerGetDatum(item);
66 : :
3769 tgl@sss.pgh.pa.us 67 [ + + ]: 4789 : if (HSTORE_VALISNULL(hsent, i))
5544 68 : 3 : item = makeitem(NULL, 0, NULLFLAG);
69 : : else
3769 70 [ + - ]: 4786 : item = makeitem(HSTORE_VAL(hsent, ptr, i),
71 [ - + ]: 4786 : HSTORE_VALLEN(hsent, i),
72 : : VALFLAG);
5861 bruce@momjian.us 73 : 4789 : entries[2 * i + 1] = PointerGetDatum(item);
74 : : }
75 : :
6941 teodor@sigaev.ru 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 : : {
5544 tgl@sss.pgh.pa.us 84 : 12 : int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
6941 teodor@sigaev.ru 85 : 12 : StrategyNumber strategy = PG_GETARG_UINT16(2);
5544 tgl@sss.pgh.pa.us 86 : 12 : int32 *searchMode = (int32 *) PG_GETARG_POINTER(6);
87 : : Datum *entries;
88 : :
6695 bruce@momjian.us 89 [ + + ]: 12 : if (strategy == HStoreContainsStrategyNumber)
90 : : {
91 : : /* Query is an hstore, so just apply gin_extract_hstore... */
92 : : entries = (Datum *)
5544 tgl@sss.pgh.pa.us 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)
5544 tgl@sss.pgh.pa.us 98 :UBC 0 : *searchMode = GIN_SEARCH_MODE_ALL;
99 : : }
6695 bruce@momjian.us 100 [ + + ]:CBC 6 : else if (strategy == HStoreExistsStrategyNumber)
101 : : {
5544 tgl@sss.pgh.pa.us 102 : 2 : text *query = PG_GETARG_TEXT_PP(0);
103 : : text *item;
104 : :
6941 teodor@sigaev.ru 105 : 2 : *nentries = 1;
6695 bruce@momjian.us 106 : 2 : entries = (Datum *) palloc(sizeof(Datum));
5544 tgl@sss.pgh.pa.us 107 [ - + - - : 2 : item = makeitem(VARDATA_ANY(query), VARSIZE_ANY_EXHDR(query), KEYFLAG);
- - - - -
+ - + ]
6941 teodor@sigaev.ru 108 : 2 : entries[0] = PointerGetDatum(item);
109 : : }
6010 tgl@sss.pgh.pa.us 110 [ + + + - ]: 4 : else if (strategy == HStoreExistsAnyStrategyNumber ||
111 : : strategy == HStoreExistsAllStrategyNumber)
112 : 4 : {
5861 bruce@momjian.us 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 : :
1353 peter@eisentraut.org 121 : 4 : deconstruct_array_builtin(query, TEXTOID, &key_datums, &key_nulls, &key_count);
122 : :
6010 tgl@sss.pgh.pa.us 123 : 4 : entries = (Datum *) palloc(sizeof(Datum) * key_count);
124 : :
125 [ + + ]: 12 : for (i = 0, j = 0; i < key_count; ++i)
126 : : {
127 : : /* Nulls in the array are ignored, cf hstoreArrayToPairs */
128 [ - + ]: 8 : if (key_nulls[i])
6010 tgl@sss.pgh.pa.us 129 :UBC 0 : continue;
222 peter@eisentraut.org 130 :GNC 8 : item = makeitem(VARDATA(DatumGetPointer(key_datums[i])), VARSIZE(DatumGetPointer(key_datums[i])) - VARHDRSZ, KEYFLAG);
6010 tgl@sss.pgh.pa.us 131 :CBC 8 : entries[j++] = PointerGetDatum(item);
132 : : }
133 : :
5544 134 : 4 : *nentries = j;
135 : : /* ExistsAll with no keys should match everything */
136 [ - + - - ]: 4 : if (j == 0 && strategy == HStoreExistsAllStrategyNumber)
5544 tgl@sss.pgh.pa.us 137 :UBC 0 : *searchMode = GIN_SEARCH_MODE_ALL;
138 : : }
139 : : else
140 : : {
141 [ # # ]: 0 : elog(ERROR, "unrecognized strategy number: %d", strategy);
142 : : entries = NULL; /* keep compiler quiet */
143 : : }
144 : :
5544 tgl@sss.pgh.pa.us 145 :CBC 12 : PG_RETURN_POINTER(entries);
146 : : }
147 : :
6941 teodor@sigaev.ru 148 : 8 : PG_FUNCTION_INFO_V1(gin_consistent_hstore);
149 : :
150 : : Datum
151 : 955 : gin_consistent_hstore(PG_FUNCTION_ARGS)
152 : : {
6544 tgl@sss.pgh.pa.us 153 : 955 : bool *check = (bool *) PG_GETARG_POINTER(0);
6941 teodor@sigaev.ru 154 : 955 : StrategyNumber strategy = PG_GETARG_UINT16(1);
155 : : #ifdef NOT_USED
156 : : HStore *query = PG_GETARG_HSTORE_P(2);
157 : : #endif
6010 tgl@sss.pgh.pa.us 158 : 955 : int32 nkeys = PG_GETARG_INT32(3);
159 : : #ifdef NOT_USED
160 : : Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4);
161 : : #endif
6199 162 : 955 : bool *recheck = (bool *) PG_GETARG_POINTER(5);
6695 bruce@momjian.us 163 : 955 : bool res = true;
164 : : int32 i;
165 : :
166 [ + + ]: 955 : 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 : : */
6544 tgl@sss.pgh.pa.us 173 : 235 : *recheck = true;
5544 174 [ + + ]: 375 : for (i = 0; i < nkeys; i++)
175 : : {
176 [ + + ]: 339 : if (!check[i])
177 : : {
6941 teodor@sigaev.ru 178 : 199 : res = false;
5544 tgl@sss.pgh.pa.us 179 : 199 : break;
180 : : }
181 : : }
182 : : }
6695 bruce@momjian.us 183 [ + + ]: 720 : else if (strategy == HStoreExistsStrategyNumber)
184 : : {
185 : : /* Existence of key is guaranteed in default search mode */
5544 tgl@sss.pgh.pa.us 186 : 194 : *recheck = false;
6941 teodor@sigaev.ru 187 : 194 : res = true;
188 : : }
6010 tgl@sss.pgh.pa.us 189 [ + + ]: 526 : else if (strategy == HStoreExistsAnyStrategyNumber)
190 : : {
191 : : /* Existence of key is guaranteed in default search mode */
5544 192 : 339 : *recheck = false;
6010 193 : 339 : res = true;
194 : : }
195 [ + - ]: 187 : else if (strategy == HStoreExistsAllStrategyNumber)
196 : : {
197 : : /* Testing for all the keys being present gives an exact result */
5544 198 : 187 : *recheck = false;
199 [ + + ]: 272 : for (i = 0; i < nkeys; i++)
200 : : {
6010 201 [ + + ]: 230 : if (!check[i])
202 : : {
203 : 145 : res = false;
5544 204 : 145 : break;
205 : : }
206 : : }
207 : : }
208 : : else
5544 tgl@sss.pgh.pa.us 209 [ # # ]:UBC 0 : elog(ERROR, "unrecognized strategy number: %d", strategy);
210 : :
6941 teodor@sigaev.ru 211 :CBC 955 : PG_RETURN_BOOL(res);
212 : : }
|