Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 91715e8

Browse files
committed
Fix management of fn_extra caching during repeated GiST index scans.
Commit d22a09d introduced official support for GiST consistentFns that want to cache data using the FmgrInfo fn_extra pointer: the idea was to preserve the cached values across gistrescan(), whereas formerly they'd been leaked. However, there was an oversight in that, namely that multiple scan keys might reference the same column's consistentFn; the code would result in propagating the same cache value into multiple scan keys, resulting in crashes or wrong answers. Use a separate array instead to ensure that each scan key keeps its own state. Per bug #8143 from Joel Roller. Back-patch to 9.2 where the bug was introduced.
1 parent cda7ace commit 91715e8

File tree

1 file changed

+29
-22
lines changed

1 file changed

+29
-22
lines changed

src/backend/access/gist/gistscan.c

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -202,20 +202,18 @@ gistrescan(PG_FUNCTION_ARGS)
202202
/* Update scan key, if a new one is given */
203203
if (key && scan->numberOfKeys > 0)
204204
{
205+
void **fn_extras = NULL;
206+
205207
/*
206208
* If this isn't the first time through, preserve the fn_extra
207209
* pointers, so that if the consistentFns are using them to cache
208210
* data, that data is not leaked across a rescan.
209211
*/
210212
if (!first_time)
211213
{
214+
fn_extras = (void **) palloc(scan->numberOfKeys * sizeof(void *));
212215
for (i = 0; i < scan->numberOfKeys; i++)
213-
{
214-
ScanKey skey = scan->keyData + i;
215-
216-
so->giststate->consistentFn[skey->sk_attno - 1].fn_extra =
217-
skey->sk_func.fn_extra;
218-
}
216+
fn_extras[i] = scan->keyData[i].sk_func.fn_extra;
219217
}
220218

221219
memmove(scan->keyData, key,
@@ -231,40 +229,43 @@ gistrescan(PG_FUNCTION_ARGS)
231229
* Next, if any of keys is a NULL and that key is not marked with
232230
* SK_SEARCHNULL/SK_SEARCHNOTNULL then nothing can be found (ie, we
233231
* assume all indexable operators are strict).
234-
*
235-
* Note: we intentionally memcpy the FmgrInfo to sk_func rather than
236-
* using fmgr_info_copy. This is so that the fn_extra field gets
237-
* preserved across multiple rescans.
238232
*/
239233
so->qual_ok = true;
240234

241235
for (i = 0; i < scan->numberOfKeys; i++)
242236
{
243237
ScanKey skey = scan->keyData + i;
244238

245-
skey->sk_func = so->giststate->consistentFn[skey->sk_attno - 1];
239+
fmgr_info_copy(&(skey->sk_func),
240+
&(so->giststate->consistentFn[skey->sk_attno - 1]),
241+
so->giststate->scanCxt);
242+
243+
/* Restore prior fn_extra pointers, if not first time */
244+
if (!first_time)
245+
skey->sk_func.fn_extra = fn_extras[i];
246246

247247
if (skey->sk_flags & SK_ISNULL)
248248
{
249249
if (!(skey->sk_flags & (SK_SEARCHNULL | SK_SEARCHNOTNULL)))
250250
so->qual_ok = false;
251251
}
252252
}
253+
254+
if (!first_time)
255+
pfree(fn_extras);
253256
}
254257

255258
/* Update order-by key, if a new one is given */
256259
if (orderbys && scan->numberOfOrderBys > 0)
257260
{
261+
void **fn_extras = NULL;
262+
258263
/* As above, preserve fn_extra if not first time through */
259264
if (!first_time)
260265
{
266+
fn_extras = (void **) palloc(scan->numberOfOrderBys * sizeof(void *));
261267
for (i = 0; i < scan->numberOfOrderBys; i++)
262-
{
263-
ScanKey skey = scan->orderByData + i;
264-
265-
so->giststate->distanceFn[skey->sk_attno - 1].fn_extra =
266-
skey->sk_func.fn_extra;
267-
}
268+
fn_extras[i] = scan->orderByData[i].sk_func.fn_extra;
268269
}
269270

270271
memmove(scan->orderByData, orderbys,
@@ -276,21 +277,27 @@ gistrescan(PG_FUNCTION_ARGS)
276277
* function in the form of its strategy number, which is available
277278
* from the sk_strategy field, and its subtype from the sk_subtype
278279
* field.
279-
*
280-
* See above comment about why we don't use fmgr_info_copy here.
281280
*/
282281
for (i = 0; i < scan->numberOfOrderBys; i++)
283282
{
284283
ScanKey skey = scan->orderByData + i;
285-
286-
skey->sk_func = so->giststate->distanceFn[skey->sk_attno - 1];
284+
FmgrInfo *finfo = &(so->giststate->distanceFn[skey->sk_attno - 1]);
287285

288286
/* Check we actually have a distance function ... */
289-
if (!OidIsValid(skey->sk_func.fn_oid))
287+
if (!OidIsValid(finfo->fn_oid))
290288
elog(ERROR, "missing support function %d for attribute %d of index \"%s\"",
291289
GIST_DISTANCE_PROC, skey->sk_attno,
292290
RelationGetRelationName(scan->indexRelation));
291+
292+
fmgr_info_copy(&(skey->sk_func), finfo, so->giststate->scanCxt);
293+
294+
/* Restore prior fn_extra pointers, if not first time */
295+
if (!first_time)
296+
skey->sk_func.fn_extra = fn_extras[i];
293297
}
298+
299+
if (!first_time)
300+
pfree(fn_extras);
294301
}
295302

296303
PG_RETURN_VOID();

0 commit comments

Comments
 (0)