Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * ginlogic.c
4 : * routines for performing binary- and ternary-logic consistent checks.
5 : *
6 : * A GIN operator class can provide a boolean or ternary consistent
7 : * function, or both. This file provides both boolean and ternary
8 : * interfaces to the rest of the GIN code, even if only one of them is
9 : * implemented by the opclass.
10 : *
11 : * Providing a boolean interface when the opclass implements only the
12 : * ternary function is straightforward - just call the ternary function
13 : * with the check-array as is, and map the GIN_TRUE, GIN_FALSE, GIN_MAYBE
14 : * return codes to TRUE, FALSE and TRUE+recheck, respectively. Providing
15 : * a ternary interface when the opclass only implements a boolean function
16 : * is implemented by calling the boolean function many times, with all the
17 : * MAYBE arguments set to all combinations of TRUE and FALSE (up to a
18 : * certain number of MAYBE arguments).
19 : *
20 : * (A boolean function is enough to determine if an item matches, but a
21 : * GIN scan can apply various optimizations if it can determine that an
22 : * item matches or doesn't match, even if it doesn't know if some of the
23 : * keys are present or not. That's what the ternary consistent function
24 : * is used for.)
25 : *
26 : *
27 : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
28 : * Portions Copyright (c) 1994, Regents of the University of California
29 : *
30 : * IDENTIFICATION
31 : * src/backend/access/gin/ginlogic.c
32 : *-------------------------------------------------------------------------
33 : */
34 :
35 : #include "postgres.h"
36 :
37 : #include "access/gin_private.h"
38 :
39 :
40 : /*
41 : * Maximum number of MAYBE inputs that shimTriConsistentFn will try to
42 : * resolve by calling all combinations.
43 : */
44 : #define MAX_MAYBE_ENTRIES 4
45 :
46 : /*
47 : * Dummy consistent functions for an EVERYTHING key. Just claim it matches.
48 : */
49 : static bool
50 0 : trueConsistentFn(GinScanKey key)
51 : {
52 0 : key->recheckCurItem = false;
53 0 : return true;
54 : }
55 : static GinTernaryValue
56 0 : trueTriConsistentFn(GinScanKey key)
57 : {
58 0 : return GIN_TRUE;
59 : }
60 :
61 : /*
62 : * A helper function for calling a regular, binary logic, consistent function.
63 : */
64 : static bool
65 37454 : directBoolConsistentFn(GinScanKey key)
66 : {
67 : /*
68 : * Initialize recheckCurItem in case the consistentFn doesn't know it
69 : * should set it. The safe assumption in that case is to force recheck.
70 : */
71 37454 : key->recheckCurItem = true;
72 :
73 74908 : return DatumGetBool(FunctionCall8Coll(key->consistentFmgrInfo,
74 : key->collation,
75 37454 : PointerGetDatum(key->entryRes),
76 37454 : UInt16GetDatum(key->strategy),
77 : key->query,
78 : UInt32GetDatum(key->nuserentries),
79 37454 : PointerGetDatum(key->extra_data),
80 37454 : PointerGetDatum(&key->recheckCurItem),
81 37454 : PointerGetDatum(key->queryValues),
82 37454 : PointerGetDatum(key->queryCategories)));
83 : }
84 :
85 : /*
86 : * A helper function for calling a native ternary logic consistent function.
87 : */
88 : static GinTernaryValue
89 969084 : directTriConsistentFn(GinScanKey key)
90 : {
91 1938168 : return DatumGetGinTernaryValue(FunctionCall7Coll(key->triConsistentFmgrInfo,
92 : key->collation,
93 969084 : PointerGetDatum(key->entryRes),
94 969084 : UInt16GetDatum(key->strategy),
95 : key->query,
96 : UInt32GetDatum(key->nuserentries),
97 969084 : PointerGetDatum(key->extra_data),
98 969084 : PointerGetDatum(key->queryValues),
99 969084 : PointerGetDatum(key->queryCategories)));
100 : }
101 :
102 : /*
103 : * This function implements a binary logic consistency check, using a ternary
104 : * logic consistent function provided by the opclass. GIN_MAYBE return value
105 : * is interpreted as true with recheck flag.
106 : */
107 : static bool
108 0 : shimBoolConsistentFn(GinScanKey key)
109 : {
110 : GinTernaryValue result;
111 :
112 0 : result = DatumGetGinTernaryValue(FunctionCall7Coll(key->triConsistentFmgrInfo,
113 : key->collation,
114 0 : PointerGetDatum(key->entryRes),
115 0 : UInt16GetDatum(key->strategy),
116 : key->query,
117 : UInt32GetDatum(key->nuserentries),
118 0 : PointerGetDatum(key->extra_data),
119 0 : PointerGetDatum(key->queryValues),
120 0 : PointerGetDatum(key->queryCategories)));
121 0 : if (result == GIN_MAYBE)
122 : {
123 0 : key->recheckCurItem = true;
124 0 : return true;
125 : }
126 : else
127 : {
128 0 : key->recheckCurItem = false;
129 0 : return result;
130 : }
131 : }
132 :
133 : /*
134 : * This function implements a tri-state consistency check, using a boolean
135 : * consistent function provided by the opclass.
136 : *
137 : * Our strategy is to call consistentFn with MAYBE inputs replaced with every
138 : * combination of TRUE/FALSE. If consistentFn returns the same value for every
139 : * combination, that's the overall result. Otherwise, return MAYBE. Testing
140 : * every combination is O(n^2), so this is only feasible for a small number of
141 : * MAYBE inputs.
142 : *
143 : * NB: This function modifies the key->entryRes array!
144 : */
145 : static GinTernaryValue
146 36512 : shimTriConsistentFn(GinScanKey key)
147 : {
148 : int nmaybe;
149 : int maybeEntries[MAX_MAYBE_ENTRIES];
150 : int i;
151 : bool boolResult;
152 36512 : bool recheck = false;
153 : GinTernaryValue curResult;
154 :
155 : /*
156 : * Count how many MAYBE inputs there are, and store their indexes in
157 : * maybeEntries. If there are too many MAYBE inputs, it's not feasible to
158 : * test all combinations, so give up and return MAYBE.
159 : */
160 36512 : nmaybe = 0;
161 141042 : for (i = 0; i < key->nentries; i++)
162 : {
163 104530 : if (key->entryRes[i] == GIN_MAYBE)
164 : {
165 70 : if (nmaybe >= MAX_MAYBE_ENTRIES)
166 0 : return GIN_MAYBE;
167 70 : maybeEntries[nmaybe++] = i;
168 : }
169 : }
170 :
171 : /*
172 : * If none of the inputs were MAYBE, so we can just call consistent
173 : * function as is.
174 : */
175 36512 : if (nmaybe == 0)
176 36464 : return directBoolConsistentFn(key);
177 :
178 : /* First call consistent function with all the maybe-inputs set FALSE */
179 118 : for (i = 0; i < nmaybe; i++)
180 70 : key->entryRes[maybeEntries[i]] = GIN_FALSE;
181 48 : curResult = directBoolConsistentFn(key);
182 :
183 : for (;;)
184 : {
185 : /* Twiddle the entries for next combination. */
186 212 : for (i = 0; i < nmaybe; i++)
187 : {
188 172 : if (key->entryRes[maybeEntries[i]] == GIN_FALSE)
189 : {
190 92 : key->entryRes[maybeEntries[i]] = GIN_TRUE;
191 92 : break;
192 : }
193 : else
194 80 : key->entryRes[maybeEntries[i]] = GIN_FALSE;
195 : }
196 132 : if (i == nmaybe)
197 40 : break;
198 :
199 92 : boolResult = directBoolConsistentFn(key);
200 92 : recheck |= key->recheckCurItem;
201 :
202 92 : if (curResult != boolResult)
203 8 : return GIN_MAYBE;
204 : }
205 :
206 : /* TRUE with recheck is taken to mean MAYBE */
207 40 : if (curResult == GIN_TRUE && recheck)
208 6 : curResult = GIN_MAYBE;
209 :
210 40 : return curResult;
211 : }
212 :
213 : /*
214 : * Set up the implementation of the consistent functions for a scan key.
215 : */
216 : void
217 1714 : ginInitConsistentFunction(GinState *ginstate, GinScanKey key)
218 : {
219 1714 : if (key->searchMode == GIN_SEARCH_MODE_EVERYTHING)
220 : {
221 0 : key->boolConsistentFn = trueConsistentFn;
222 0 : key->triConsistentFn = trueTriConsistentFn;
223 : }
224 : else
225 : {
226 1714 : key->consistentFmgrInfo = &ginstate->consistentFn[key->attnum - 1];
227 1714 : key->triConsistentFmgrInfo = &ginstate->triConsistentFn[key->attnum - 1];
228 1714 : key->collation = ginstate->supportCollation[key->attnum - 1];
229 :
230 1714 : if (OidIsValid(ginstate->consistentFn[key->attnum - 1].fn_oid))
231 1714 : key->boolConsistentFn = directBoolConsistentFn;
232 : else
233 0 : key->boolConsistentFn = shimBoolConsistentFn;
234 :
235 1714 : if (OidIsValid(ginstate->triConsistentFn[key->attnum - 1].fn_oid))
236 1374 : key->triConsistentFn = directTriConsistentFn;
237 : else
238 340 : key->triConsistentFn = shimTriConsistentFn;
239 : }
240 1714 : }
|