PostgreSQL Source Code git master
Loading...
Searching...
No Matches
ginlogic.c
Go to the documentation of this file.
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-2026, 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 */
49static bool
51{
52 key->recheckCurItem = false;
53 return true;
54}
55static GinTernaryValue
57{
58 return GIN_TRUE;
59}
60
61/*
62 * A helper function for calling a regular, binary logic, consistent function.
63 */
64static bool
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 key->recheckCurItem = true;
72
73 return DatumGetBool(FunctionCall8Coll(key->consistentFmgrInfo,
74 key->collation,
75 PointerGetDatum(key->entryRes),
76 UInt16GetDatum(key->strategy),
77 key->query,
78 Int32GetDatum(key->nuserentries),
79 PointerGetDatum(key->extra_data),
80 PointerGetDatum(&key->recheckCurItem),
81 PointerGetDatum(key->queryValues),
82 PointerGetDatum(key->queryCategories)));
83}
84
85/*
86 * A helper function for calling a native ternary logic consistent function.
87 */
88static GinTernaryValue
90{
91 return DatumGetGinTernaryValue(FunctionCall7Coll(key->triConsistentFmgrInfo,
92 key->collation,
93 PointerGetDatum(key->entryRes),
94 UInt16GetDatum(key->strategy),
95 key->query,
96 Int32GetDatum(key->nuserentries),
97 PointerGetDatum(key->extra_data),
98 PointerGetDatum(key->queryValues),
99 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 */
107static bool
109{
111
112 result = DatumGetGinTernaryValue(FunctionCall7Coll(key->triConsistentFmgrInfo,
113 key->collation,
114 PointerGetDatum(key->entryRes),
115 UInt16GetDatum(key->strategy),
116 key->query,
117 Int32GetDatum(key->nuserentries),
118 PointerGetDatum(key->extra_data),
119 PointerGetDatum(key->queryValues),
120 PointerGetDatum(key->queryCategories)));
121 if (result == GIN_MAYBE)
122 {
123 key->recheckCurItem = true;
124 return true;
125 }
126 else
127 {
128 key->recheckCurItem = false;
129 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. For now that's okay
144 * so long as we restore the entry-time contents before returning. This may
145 * need revisiting if we ever invent multithreaded GIN scans, though.
146 */
147static GinTernaryValue
149{
150 int nmaybe;
152 bool boolResult;
153 bool recheck;
155
156 /*
157 * Count how many MAYBE inputs there are, and store their indexes in
158 * maybeEntries. If there are too many MAYBE inputs, it's not feasible to
159 * test all combinations, so give up and return MAYBE.
160 */
161 nmaybe = 0;
162 for (uint32 i = 0; i < key->nentries; i++)
163 {
164 if (key->entryRes[i] == GIN_MAYBE)
165 {
167 return GIN_MAYBE;
168 maybeEntries[nmaybe++] = i;
169 }
170 }
171
172 /*
173 * If none of the inputs were MAYBE, we can just call the consistent
174 * function as-is.
175 */
176 if (nmaybe == 0)
177 return directBoolConsistentFn(key);
178
179 /* First call consistent function with all the maybe-inputs set FALSE */
180 for (int i = 0; i < nmaybe; i++)
181 key->entryRes[maybeEntries[i]] = GIN_FALSE;
183 recheck = key->recheckCurItem;
184
185 for (;;)
186 {
187 int i;
188
189 /* Twiddle the entries for next combination. */
190 for (i = 0; i < nmaybe; i++)
191 {
192 if (key->entryRes[maybeEntries[i]] == GIN_FALSE)
193 {
194 key->entryRes[maybeEntries[i]] = GIN_TRUE;
195 break;
196 }
197 else
198 key->entryRes[maybeEntries[i]] = GIN_FALSE;
199 }
200 if (i == nmaybe)
201 break;
202
204 recheck |= key->recheckCurItem;
205
206 if (curResult != boolResult)
207 {
209 break;
210 }
211 }
212
213 /* TRUE with recheck is taken to mean MAYBE */
214 if (curResult == GIN_TRUE && recheck)
216
217 /* We must restore the original state of the entryRes array */
218 for (int i = 0; i < nmaybe; i++)
219 key->entryRes[maybeEntries[i]] = GIN_MAYBE;
220
221 return curResult;
222}
223
224/*
225 * Set up the implementation of the consistent functions for a scan key.
226 */
227void
229{
230 if (key->searchMode == GIN_SEARCH_MODE_EVERYTHING)
231 {
232 key->boolConsistentFn = trueConsistentFn;
233 key->triConsistentFn = trueTriConsistentFn;
234 }
235 else
236 {
237 key->consistentFmgrInfo = &ginstate->consistentFn[key->attnum - 1];
238 key->triConsistentFmgrInfo = &ginstate->triConsistentFn[key->attnum - 1];
239 key->collation = ginstate->supportCollation[key->attnum - 1];
240
241 if (OidIsValid(ginstate->consistentFn[key->attnum - 1].fn_oid))
242 key->boolConsistentFn = directBoolConsistentFn;
243 else
244 key->boolConsistentFn = shimBoolConsistentFn;
245
246 if (OidIsValid(ginstate->triConsistentFn[key->attnum - 1].fn_oid))
247 key->triConsistentFn = directTriConsistentFn;
248 else
249 key->triConsistentFn = shimTriConsistentFn;
250 }
251}
uint32_t uint32
Definition c.h:683
#define OidIsValid(objectId)
Definition c.h:917
uint32 result
Datum FunctionCall8Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7, Datum arg8)
Definition fmgr.c:1320
Datum FunctionCall7Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7)
Definition fmgr.c:1286
#define GIN_SEARCH_MODE_EVERYTHING
Definition gin.h:39
#define GIN_FALSE
Definition gin.h:76
static GinTernaryValue DatumGetGinTernaryValue(Datum X)
Definition gin.h:81
char GinTernaryValue
Definition gin.h:71
#define GIN_MAYBE
Definition gin.h:78
#define GIN_TRUE
Definition gin.h:77
static GinTernaryValue trueTriConsistentFn(GinScanKey key)
Definition ginlogic.c:56
static GinTernaryValue shimTriConsistentFn(GinScanKey key)
Definition ginlogic.c:148
static GinTernaryValue directTriConsistentFn(GinScanKey key)
Definition ginlogic.c:89
static bool trueConsistentFn(GinScanKey key)
Definition ginlogic.c:50
static bool directBoolConsistentFn(GinScanKey key)
Definition ginlogic.c:65
void ginInitConsistentFunction(GinState *ginstate, GinScanKey key)
Definition ginlogic.c:228
#define MAX_MAYBE_ENTRIES
Definition ginlogic.c:44
static bool shimBoolConsistentFn(GinScanKey key)
Definition ginlogic.c:108
int i
Definition isn.c:77
static bool DatumGetBool(Datum X)
Definition postgres.h:100
static Datum UInt16GetDatum(uint16 X)
Definition postgres.h:192
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212
#define PointerGetDatum(X)
Definition postgres.h:354
static int fb(int x)
Oid fn_oid
Definition fmgr.h:59
FmgrInfo triConsistentFn[INDEX_MAX_KEYS]
Definition gin_private.h:85
FmgrInfo consistentFn[INDEX_MAX_KEYS]
Definition gin_private.h:84
Oid supportCollation[INDEX_MAX_KEYS]
Definition gin_private.h:90