Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * ginarrayproc.c
4 : * support functions for GIN's indexing of any array
5 : *
6 : *
7 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
8 : * Portions Copyright (c) 1994, Regents of the University of California
9 : *
10 : * IDENTIFICATION
11 : * src/backend/access/gin/ginarrayproc.c
12 : *-------------------------------------------------------------------------
13 : */
14 : #include "postgres.h"
15 :
16 : #include "access/gin.h"
17 : #include "access/stratnum.h"
18 : #include "utils/array.h"
19 : #include "utils/builtins.h"
20 : #include "utils/lsyscache.h"
21 :
22 :
23 : #define GinOverlapStrategy 1
24 : #define GinContainsStrategy 2
25 : #define GinContainedStrategy 3
26 : #define GinEqualStrategy 4
27 :
28 :
29 : /*
30 : * extractValue support function
31 : */
32 : Datum
6031 bruce 33 CBC 528039 : ginarrayextract(PG_FUNCTION_ARGS)
34 : {
35 : /* Make copy of array input to ensure it doesn't disappear while in use */
4475 tgl 36 528039 : ArrayType *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
37 528039 : int32 *nkeys = (int32 *) PG_GETARG_POINTER(1);
38 528039 : bool **nullFlags = (bool **) PG_GETARG_POINTER(2);
39 : int16 elmlen;
40 : bool elmbyval;
41 : char elmalign;
42 : Datum *elems;
43 : bool *nulls;
44 : int nelems;
45 :
6186 teodor 46 528039 : get_typlenbyvalalign(ARR_ELEMTYPE(array),
47 : &elmlen, &elmbyval, &elmalign);
48 :
49 528039 : deconstruct_array(array,
50 : ARR_ELEMTYPE(array),
51 : elmlen, elmbyval, elmalign,
52 : &elems, &nulls, &nelems);
53 :
4475 tgl 54 528039 : *nkeys = nelems;
55 528039 : *nullFlags = nulls;
56 :
57 : /* we should not free array, elems[i] points into it */
58 528039 : PG_RETURN_POINTER(elems);
59 : }
60 :
61 : /*
62 : * Formerly, ginarrayextract had only two arguments. Now it has three,
63 : * but we still need a pg_proc entry with two args to support reloading
64 : * pre-9.1 contrib/intarray opclass declarations. This compatibility
65 : * function should go away eventually.
66 : */
67 : Datum
4435 tgl 68 UBC 0 : ginarrayextract_2args(PG_FUNCTION_ARGS)
69 : {
70 0 : if (PG_NARGS() < 3) /* should not happen */
71 0 : elog(ERROR, "ginarrayextract requires three arguments");
72 0 : return ginarrayextract(fcinfo);
73 : }
74 :
75 : /*
76 : * extractQuery support function
77 : */
78 : Datum
5710 tgl 79 CBC 653 : ginqueryarrayextract(PG_FUNCTION_ARGS)
80 : {
81 : /* Make copy of array input to ensure it doesn't disappear while in use */
4475 82 653 : ArrayType *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
83 653 : int32 *nkeys = (int32 *) PG_GETARG_POINTER(1);
84 653 : StrategyNumber strategy = PG_GETARG_UINT16(2);
85 :
86 : /* bool **pmatch = (bool **) PG_GETARG_POINTER(3); */
87 : /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
88 653 : bool **nullFlags = (bool **) PG_GETARG_POINTER(5);
89 653 : int32 *searchMode = (int32 *) PG_GETARG_POINTER(6);
90 : int16 elmlen;
91 : bool elmbyval;
92 : char elmalign;
93 : Datum *elems;
94 : bool *nulls;
95 : int nelems;
96 :
97 653 : get_typlenbyvalalign(ARR_ELEMTYPE(array),
98 : &elmlen, &elmbyval, &elmalign);
99 :
100 653 : deconstruct_array(array,
101 : ARR_ELEMTYPE(array),
102 : elmlen, elmbyval, elmalign,
103 : &elems, &nulls, &nelems);
104 :
105 653 : *nkeys = nelems;
106 653 : *nullFlags = nulls;
107 :
108 653 : switch (strategy)
109 : {
110 72 : case GinOverlapStrategy:
111 72 : *searchMode = GIN_SEARCH_MODE_DEFAULT;
112 72 : break;
113 527 : case GinContainsStrategy:
114 527 : if (nelems > 0)
115 335 : *searchMode = GIN_SEARCH_MODE_DEFAULT;
116 : else /* everything contains the empty set */
117 192 : *searchMode = GIN_SEARCH_MODE_ALL;
118 527 : break;
119 24 : case GinContainedStrategy:
120 : /* empty set is contained in everything */
121 24 : *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
122 24 : break;
123 30 : case GinEqualStrategy:
124 30 : if (nelems > 0)
125 12 : *searchMode = GIN_SEARCH_MODE_DEFAULT;
126 : else
127 18 : *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
128 30 : break;
4475 tgl 129 UBC 0 : default:
130 0 : elog(ERROR, "ginqueryarrayextract: unknown strategy number: %d",
131 : strategy);
132 : }
133 :
134 : /* we should not free array, elems[i] points into it */
4475 tgl 135 CBC 653 : PG_RETURN_POINTER(elems);
136 : }
137 :
138 : /*
139 : * consistent support function
140 : */
141 : Datum
6031 bruce 142 405 : ginarrayconsistent(PG_FUNCTION_ARGS)
143 : {
144 405 : bool *check = (bool *) PG_GETARG_POINTER(0);
145 405 : StrategyNumber strategy = PG_GETARG_UINT16(1);
146 :
147 : /* ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); */
4475 tgl 148 405 : int32 nkeys = PG_GETARG_INT32(3);
149 :
150 : /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
5128 151 405 : bool *recheck = (bool *) PG_GETARG_POINTER(5);
152 :
153 : /* Datum *queryKeys = (Datum *) PG_GETARG_POINTER(6); */
4475 154 405 : bool *nullFlags = (bool *) PG_GETARG_POINTER(7);
155 : bool res;
156 : int32 i;
157 :
6031 bruce 158 405 : switch (strategy)
159 : {
6186 teodor 160 UBC 0 : case GinOverlapStrategy:
161 : /* result is not lossy */
5473 tgl 162 0 : *recheck = false;
163 : /* must have a match for at least one non-null element */
4475 164 0 : res = false;
165 0 : for (i = 0; i < nkeys; i++)
166 : {
167 0 : if (check[i] && !nullFlags[i])
168 : {
169 0 : res = true;
170 0 : break;
171 : }
172 : }
6186 teodor 173 0 : break;
6186 teodor 174 CBC 405 : case GinContainsStrategy:
175 : /* result is not lossy */
5473 tgl 176 405 : *recheck = false;
177 : /* must have all elements in check[] true, and no nulls */
178 405 : res = true;
4475 179 555 : for (i = 0; i < nkeys; i++)
180 : {
181 150 : if (!check[i] || nullFlags[i])
182 : {
5473 tgl 183 UBC 0 : res = false;
184 0 : break;
185 : }
186 : }
5473 tgl 187 CBC 405 : break;
4475 tgl 188 UBC 0 : case GinContainedStrategy:
189 : /* we will need recheck */
190 0 : *recheck = true;
191 : /* can't do anything else useful here */
192 0 : res = true;
193 0 : break;
6116 teodor 194 0 : case GinEqualStrategy:
195 : /* we will need recheck */
5473 tgl 196 0 : *recheck = true;
197 :
198 : /*
199 : * Must have all elements in check[] true; no discrimination
200 : * against nulls here. This is because array_contain_compare and
201 : * array_eq handle nulls differently ...
202 : */
203 0 : res = true;
4475 204 0 : for (i = 0; i < nkeys; i++)
205 : {
6031 bruce 206 0 : if (!check[i])
207 : {
5473 tgl 208 0 : res = false;
6186 teodor 209 0 : break;
210 : }
211 : }
212 0 : break;
213 0 : default:
6055 tgl 214 0 : elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
215 : strategy);
216 : res = false;
217 : }
218 :
6186 teodor 219 CBC 405 : PG_RETURN_BOOL(res);
220 : }
221 :
222 : /*
223 : * triconsistent support function
224 : */
225 : Datum
3315 heikki.linnakangas 226 402716 : ginarraytriconsistent(PG_FUNCTION_ARGS)
227 : {
3296 228 402716 : GinTernaryValue *check = (GinTernaryValue *) PG_GETARG_POINTER(0);
3315 229 402716 : StrategyNumber strategy = PG_GETARG_UINT16(1);
230 :
231 : /* ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); */
232 402716 : int32 nkeys = PG_GETARG_INT32(3);
233 :
234 : /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
235 : /* Datum *queryKeys = (Datum *) PG_GETARG_POINTER(5); */
236 402716 : bool *nullFlags = (bool *) PG_GETARG_POINTER(6);
237 : GinTernaryValue res;
238 : int32 i;
239 :
240 402716 : switch (strategy)
241 : {
242 186 : case GinOverlapStrategy:
243 : /* must have a match for at least one non-null element */
244 186 : res = GIN_FALSE;
245 219 : for (i = 0; i < nkeys; i++)
246 : {
247 213 : if (!nullFlags[i])
248 : {
249 213 : if (check[i] == GIN_TRUE)
250 : {
251 180 : res = GIN_TRUE;
252 180 : break;
253 : }
254 33 : else if (check[i] == GIN_MAYBE && res == GIN_FALSE)
255 : {
256 6 : res = GIN_MAYBE;
257 : }
258 : }
259 : }
260 186 : break;
261 402326 : case GinContainsStrategy:
262 : /* must have all elements in check[] true, and no nulls */
263 402326 : res = GIN_TRUE;
264 744022 : for (i = 0; i < nkeys; i++)
265 : {
266 341720 : if (check[i] == GIN_FALSE || nullFlags[i])
267 : {
268 24 : res = GIN_FALSE;
269 24 : break;
270 : }
271 341696 : if (check[i] == GIN_MAYBE)
272 : {
273 6 : res = GIN_MAYBE;
274 : }
275 : }
276 402326 : break;
277 168 : case GinContainedStrategy:
278 : /* can't do anything else useful here */
279 168 : res = GIN_MAYBE;
280 168 : break;
281 36 : case GinEqualStrategy:
282 :
283 : /*
284 : * Must have all elements in check[] true; no discrimination
285 : * against nulls here. This is because array_contain_compare and
286 : * array_eq handle nulls differently ...
287 : */
288 36 : res = GIN_MAYBE;
289 66 : for (i = 0; i < nkeys; i++)
290 : {
291 51 : if (check[i] == GIN_FALSE)
292 : {
293 21 : res = GIN_FALSE;
294 21 : break;
295 : }
296 : }
297 36 : break;
3315 heikki.linnakangas 298 UBC 0 : default:
299 0 : elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
300 : strategy);
301 : res = false;
302 : }
303 :
3296 heikki.linnakangas 304 CBC 402716 : PG_RETURN_GIN_TERNARY_VALUE(res);
305 : }
|