PostgreSQL Source Code git master
Loading...
Searching...
No Matches
gistscan.c File Reference
#include "postgres.h"
#include "access/gist_private.h"
#include "access/gistscan.h"
#include "access/relscan.h"
#include "utils/float.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
Include dependency graph for gistscan.c:

Go to the source code of this file.

Functions

static int pairingheap_GISTSearchItem_cmp (const pairingheap_node *a, const pairingheap_node *b, void *arg)
 
IndexScanDesc gistbeginscan (Relation r, int nkeys, int norderbys)
 
void gistrescan (IndexScanDesc scan, ScanKey key, int nkeys, ScanKey orderbys, int norderbys)
 
void gistendscan (IndexScanDesc scan)
 

Function Documentation

◆ gistbeginscan()

IndexScanDesc gistbeginscan ( Relation  r,
int  nkeys,
int  norderbys 
)

Definition at line 74 of file gistscan.c.

75{
76 IndexScanDesc scan;
77 GISTSTATE *giststate;
80
81 scan = RelationGetIndexScan(r, nkeys, norderbys);
82
83 /* First, set up a GISTSTATE with a scan-lifespan memory context */
84 giststate = initGISTstate(scan->indexRelation);
85
86 /*
87 * Everything made below is in the scanCxt, or is a child of the scanCxt,
88 * so it'll all go away automatically in gistendscan.
89 */
91
92 /* initialize opaque data */
94 so->giststate = giststate;
95 giststate->tempCxt = createTempGistContext();
96 so->queue = NULL;
97 so->queueCxt = giststate->scanCxt; /* see gistrescan */
98
99 /* workspaces with size dependent on numberOfOrderBys: */
100 so->distances = palloc(sizeof(so->distances[0]) * scan->numberOfOrderBys);
101 so->qual_ok = true; /* in case there are zero keys */
102 if (scan->numberOfOrderBys > 0)
103 {
105 scan->xs_orderbynulls = palloc_array(bool, scan->numberOfOrderBys);
106 memset(scan->xs_orderbynulls, true, sizeof(bool) * scan->numberOfOrderBys);
107 }
108
109 so->killedItems = NULL; /* until needed */
110 so->numKilled = 0;
111 so->curBlkno = InvalidBlockNumber;
112 so->curPageLSN = InvalidXLogRecPtr;
113
114 scan->opaque = so;
115
116 /*
117 * All fields required for index-only scans are initialized in gistrescan,
118 * as we don't know yet if we're doing an index-only scan or not.
119 */
120
122
123 return scan;
124}
#define InvalidBlockNumber
Definition block.h:33
#define palloc_array(type, count)
Definition fe_memutils.h:76
#define palloc0_array(type, count)
Definition fe_memutils.h:77
#define palloc0_object(type)
Definition fe_memutils.h:75
IndexScanDesc RelationGetIndexScan(Relation indexRelation, int nkeys, int norderbys)
Definition genam.c:80
GISTSTATE * initGISTstate(Relation index)
Definition gist.c:1537
MemoryContext createTempGistContext(void)
Definition gist.c:129
void * palloc(Size size)
Definition mcxt.c:1387
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
uint64_t Datum
Definition postgres.h:70
static int fb(int x)
MemoryContext tempCxt
MemoryContext scanCxt
bool * xs_orderbynulls
Definition relscan.h:188
Relation indexRelation
Definition relscan.h:138
Datum * xs_orderbyvals
Definition relscan.h:187
#define InvalidXLogRecPtr
Definition xlogdefs.h:28

References createTempGistContext(), fb(), IndexScanDescData::indexRelation, initGISTstate(), InvalidBlockNumber, InvalidXLogRecPtr, MemoryContextSwitchTo(), IndexScanDescData::numberOfOrderBys, IndexScanDescData::opaque, palloc(), palloc0_array, palloc0_object, palloc_array, RelationGetIndexScan(), GISTSTATE::scanCxt, GISTSTATE::tempCxt, IndexScanDescData::xs_orderbynulls, and IndexScanDescData::xs_orderbyvals.

Referenced by gisthandler().

◆ gistendscan()

void gistendscan ( IndexScanDesc  scan)

Definition at line 348 of file gistscan.c.

349{
351
352 /*
353 * freeGISTstate is enough to clean up everything made by gistbeginscan,
354 * as well as the queueCxt if there is a separate context for it.
355 */
356 freeGISTstate(so->giststate);
357}
void freeGISTstate(GISTSTATE *giststate)
Definition gist.c:1664
GISTScanOpaqueData * GISTScanOpaque

References fb(), freeGISTstate(), and IndexScanDescData::opaque.

Referenced by gisthandler().

◆ gistrescan()

void gistrescan ( IndexScanDesc  scan,
ScanKey  key,
int  nkeys,
ScanKey  orderbys,
int  norderbys 
)

Definition at line 127 of file gistscan.c.

129{
130 /* nkeys and norderbys arguments are ignored */
132 bool first_time;
133 int i;
135
136 /* rescan an existing indexscan --- reset state */
137
138 /*
139 * The first time through, we create the search queue in the scanCxt.
140 * Subsequent times through, we create the queue in a separate queueCxt,
141 * which is created on the second call and reset on later calls. Thus, in
142 * the common case where a scan is only rescan'd once, we just put the
143 * queue in scanCxt and don't pay the overhead of making a second memory
144 * context. If we do rescan more than once, the first queue is just left
145 * for dead until end of scan; this small wastage seems worth the savings
146 * in the common case.
147 */
148 if (so->queue == NULL)
149 {
150 /* first time through */
151 Assert(so->queueCxt == so->giststate->scanCxt);
152 first_time = true;
153 }
154 else if (so->queueCxt == so->giststate->scanCxt)
155 {
156 /* second time through */
157 so->queueCxt = AllocSetContextCreate(so->giststate->scanCxt,
158 "GiST queue context",
160 first_time = false;
161 }
162 else
163 {
164 /* third or later time through */
165 MemoryContextReset(so->queueCxt);
166 first_time = false;
167 }
168
169 /*
170 * If we're doing an index-only scan, on the first call, also initialize a
171 * tuple descriptor to represent the returned index tuples and create a
172 * memory context to hold them during the scan.
173 */
174 if (scan->xs_want_itup && !scan->xs_hitupdesc)
175 {
176 int natts;
177 int nkeyatts;
178 int attno;
179
180 /*
181 * The storage type of the index can be different from the original
182 * datatype being indexed, so we cannot just grab the index's tuple
183 * descriptor. Instead, construct a descriptor with the original data
184 * types.
185 */
188 so->giststate->fetchTupdesc = CreateTemplateTupleDesc(natts);
189 for (attno = 1; attno <= nkeyatts; attno++)
190 {
191 TupleDescInitEntry(so->giststate->fetchTupdesc, attno, NULL,
192 scan->indexRelation->rd_opcintype[attno - 1],
193 -1, 0);
194 }
195
196 for (; attno <= natts; attno++)
197 {
198 /* taking opcintype from giststate->tupdesc */
199 TupleDescInitEntry(so->giststate->fetchTupdesc, attno, NULL,
200 TupleDescAttr(so->giststate->leafTupdesc,
201 attno - 1)->atttypid,
202 -1, 0);
203 }
204 TupleDescFinalize(so->giststate->fetchTupdesc);
205 scan->xs_hitupdesc = so->giststate->fetchTupdesc;
206
207 /* Also create a memory context that will hold the returned tuples */
208 so->pageDataCxt = AllocSetContextCreate(so->giststate->scanCxt,
209 "GiST page data context",
211 }
212
213 /* create new, empty pairing heap for search queue */
214 oldCxt = MemoryContextSwitchTo(so->queueCxt);
217
218 so->firstCall = true;
219
220 /* Update scan key, if a new one is given */
221 if (key && scan->numberOfKeys > 0)
222 {
223 void **fn_extras = NULL;
224
225 /*
226 * If this isn't the first time through, preserve the fn_extra
227 * pointers, so that if the consistentFns are using them to cache
228 * data, that data is not leaked across a rescan.
229 */
230 if (!first_time)
231 {
232 fn_extras = (void **) palloc(scan->numberOfKeys * sizeof(void *));
233 for (i = 0; i < scan->numberOfKeys; i++)
235 }
236
237 memcpy(scan->keyData, key, scan->numberOfKeys * sizeof(ScanKeyData));
238
239 /*
240 * Modify the scan key so that the Consistent method is called for all
241 * comparisons. The original operator is passed to the Consistent
242 * function in the form of its strategy number, which is available
243 * from the sk_strategy field, and its subtype from the sk_subtype
244 * field.
245 *
246 * Next, if any of keys is a NULL and that key is not marked with
247 * SK_SEARCHNULL/SK_SEARCHNOTNULL then nothing can be found (ie, we
248 * assume all indexable operators are strict).
249 */
250 so->qual_ok = true;
251
252 for (i = 0; i < scan->numberOfKeys; i++)
253 {
254 ScanKey skey = scan->keyData + i;
255
256 /*
257 * Copy consistent support function to ScanKey structure instead
258 * of function implementing filtering operator.
259 */
260 fmgr_info_copy(&(skey->sk_func),
261 &(so->giststate->consistentFn[skey->sk_attno - 1]),
262 so->giststate->scanCxt);
263
264 /* Restore prior fn_extra pointers, if not first time */
265 if (!first_time)
266 skey->sk_func.fn_extra = fn_extras[i];
267
268 if (skey->sk_flags & SK_ISNULL)
269 {
270 if (!(skey->sk_flags & (SK_SEARCHNULL | SK_SEARCHNOTNULL)))
271 so->qual_ok = false;
272 }
273 }
274
275 if (!first_time)
277 }
278
279 /* Update order-by key, if a new one is given */
280 if (orderbys && scan->numberOfOrderBys > 0)
281 {
282 void **fn_extras = NULL;
283
284 /* As above, preserve fn_extra if not first time through */
285 if (!first_time)
286 {
287 fn_extras = (void **) palloc(scan->numberOfOrderBys * sizeof(void *));
288 for (i = 0; i < scan->numberOfOrderBys; i++)
290 }
291
292 memcpy(scan->orderByData, orderbys, scan->numberOfOrderBys * sizeof(ScanKeyData));
293
294 so->orderByTypes = (Oid *) palloc(scan->numberOfOrderBys * sizeof(Oid));
295
296 /*
297 * Modify the order-by key so that the Distance method is called for
298 * all comparisons. The original operator is passed to the Distance
299 * function in the form of its strategy number, which is available
300 * from the sk_strategy field, and its subtype from the sk_subtype
301 * field.
302 */
303 for (i = 0; i < scan->numberOfOrderBys; i++)
304 {
305 ScanKey skey = scan->orderByData + i;
306 FmgrInfo *finfo = &(so->giststate->distanceFn[skey->sk_attno - 1]);
307
308 /* Check we actually have a distance function ... */
309 if (!OidIsValid(finfo->fn_oid))
310 elog(ERROR, "missing support function %d for attribute %d of index \"%s\"",
311 GIST_DISTANCE_PROC, skey->sk_attno,
313
314 /*
315 * Look up the datatype returned by the original ordering
316 * operator. GiST always uses a float8 for the distance function,
317 * but the ordering operator could be anything else.
318 *
319 * XXX: The distance function is only allowed to be lossy if the
320 * ordering operator's result type is float4 or float8. Otherwise
321 * we don't know how to return the distance to the executor. But
322 * we cannot check that here, as we won't know if the distance
323 * function is lossy until it returns *recheck = true for the
324 * first time.
325 */
326 so->orderByTypes[i] = get_func_rettype(skey->sk_func.fn_oid);
327
328 /*
329 * Copy distance support function to ScanKey structure instead of
330 * function implementing ordering operator.
331 */
332 fmgr_info_copy(&(skey->sk_func), finfo, so->giststate->scanCxt);
333
334 /* Restore prior fn_extra pointers, if not first time */
335 if (!first_time)
336 skey->sk_func.fn_extra = fn_extras[i];
337 }
338
339 if (!first_time)
341 }
342
343 /* any previous xs_hitup will have been pfree'd in context resets above */
344 scan->xs_hitup = NULL;
345}
#define Assert(condition)
Definition c.h:945
#define OidIsValid(objectId)
Definition c.h:860
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
Definition fmgr.c:582
#define GIST_DISTANCE_PROC
Definition gist.h:39
static int pairingheap_GISTSearchItem_cmp(const pairingheap_node *a, const pairingheap_node *b, void *arg)
Definition gistscan.c:30
int i
Definition isn.c:77
Oid get_func_rettype(Oid funcid)
Definition lsyscache.c:1875
void MemoryContextReset(MemoryContext context)
Definition mcxt.c:403
void pfree(void *pointer)
Definition mcxt.c:1616
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
pairingheap * pairingheap_allocate(pairingheap_comparator compare, void *arg)
Definition pairingheap.c:42
unsigned int Oid
#define RelationGetNumberOfAttributes(relation)
Definition rel.h:520
#define RelationGetRelationName(relation)
Definition rel.h:548
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition rel.h:533
#define SK_SEARCHNOTNULL
Definition skey.h:122
#define SK_SEARCHNULL
Definition skey.h:121
#define SK_ISNULL
Definition skey.h:115
void * fn_extra
Definition fmgr.h:64
Oid fn_oid
Definition fmgr.h:59
struct ScanKeyData * keyData
Definition relscan.h:142
struct ScanKeyData * orderByData
Definition relscan.h:143
HeapTuple xs_hitup
Definition relscan.h:170
struct TupleDescData * xs_hitupdesc
Definition relscan.h:171
Oid * rd_opcintype
Definition rel.h:208
FmgrInfo sk_func
Definition skey.h:71
TupleDesc CreateTemplateTupleDesc(int natts)
Definition tupdesc.c:165
void TupleDescFinalize(TupleDesc tupdesc)
Definition tupdesc.c:508
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition tupdesc.c:897
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:178

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, CreateTemplateTupleDesc(), elog, ERROR, fb(), fmgr_info_copy(), FmgrInfo::fn_extra, FmgrInfo::fn_oid, get_func_rettype(), GIST_DISTANCE_PROC, i, IndexScanDescData::indexRelation, IndexRelationGetNumberOfKeyAttributes, IndexScanDescData::keyData, MemoryContextReset(), MemoryContextSwitchTo(), IndexScanDescData::numberOfKeys, IndexScanDescData::numberOfOrderBys, OidIsValid, IndexScanDescData::opaque, IndexScanDescData::orderByData, pairingheap_allocate(), pairingheap_GISTSearchItem_cmp(), palloc(), pfree(), RelationData::rd_opcintype, RelationGetNumberOfAttributes, RelationGetRelationName, ScanKeyData::sk_func, SK_ISNULL, SK_SEARCHNOTNULL, SK_SEARCHNULL, TupleDescAttr(), TupleDescFinalize(), TupleDescInitEntry(), IndexScanDescData::xs_hitup, IndexScanDescData::xs_hitupdesc, and IndexScanDescData::xs_want_itup.

Referenced by gisthandler().

◆ pairingheap_GISTSearchItem_cmp()

static int pairingheap_GISTSearchItem_cmp ( const pairingheap_node a,
const pairingheap_node b,
void arg 
)
static

Definition at line 30 of file gistscan.c.

31{
32 const GISTSearchItem *sa = (const GISTSearchItem *) a;
33 const GISTSearchItem *sb = (const GISTSearchItem *) b;
35 int i;
36
37 /* Order according to distance comparison */
38 for (i = 0; i < scan->numberOfOrderBys; i++)
39 {
40 if (sa->distances[i].isnull)
41 {
42 if (!sb->distances[i].isnull)
43 return -1;
44 }
45 else if (sb->distances[i].isnull)
46 {
47 return 1;
48 }
49 else
50 {
51 int cmp = -float8_cmp_internal(sa->distances[i].value,
52 sb->distances[i].value);
53
54 if (cmp != 0)
55 return cmp;
56 }
57 }
58
59 /* Heap items go before inner pages, to ensure a depth-first search */
61 return 1;
63 return -1;
64
65 return 0;
66}
Datum arg
Definition elog.c:1322
int float8_cmp_internal(float8 a, float8 b)
Definition float.c:927
struct IndexScanDescData * IndexScanDesc
Definition genam.h:98
#define GISTSearchItemIsHeap(item)
int b
Definition isn.c:74
int a
Definition isn.c:73
static int cmp(const chr *x, const chr *y, size_t len)

References a, arg, b, cmp(), fb(), float8_cmp_internal(), GISTSearchItemIsHeap, i, and IndexScanDescData::numberOfOrderBys.

Referenced by gistrescan().