PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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;
79 MemoryContext oldCxt;
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 */
90 oldCxt = MemoryContextSwitchTo(giststate->scanCxt);
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 {
104 scan->xs_orderbyvals = palloc0(sizeof(Datum) * scan->numberOfOrderBys);
105 scan->xs_orderbynulls = palloc(sizeof(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;
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
121 MemoryContextSwitchTo(oldCxt);
122
123 return scan;
124}
#define InvalidBlockNumber
Definition: block.h:33
IndexScanDesc RelationGetIndexScan(Relation indexRelation, int nkeys, int norderbys)
Definition: genam.c:80
GISTSTATE * initGISTstate(Relation index)
Definition: gist.c:1525
MemoryContext createTempGistContext(void)
Definition: gist.c:123
GISTScanOpaqueData * GISTScanOpaque
Definition: gist_private.h:181
void * palloc0(Size size)
Definition: mcxt.c:1347
void * palloc(Size size)
Definition: mcxt.c:1317
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
uintptr_t Datum
Definition: postgres.h:69
MemoryContext tempCxt
Definition: gist_private.h:78
MemoryContext scanCxt
Definition: gist_private.h:77
OffsetNumber * killedItems
Definition: gist_private.h:168
pairingheap * queue
Definition: gist_private.h:159
GISTSTATE * giststate
Definition: gist_private.h:156
MemoryContext queueCxt
Definition: gist_private.h:160
IndexOrderByDistance * distances
Definition: gist_private.h:165
BlockNumber curBlkno
Definition: gist_private.h:170
bool * xs_orderbynulls
Definition: relscan.h:179
int numberOfOrderBys
Definition: relscan.h:138
Relation indexRelation
Definition: relscan.h:135
Datum * xs_orderbyvals
Definition: relscan.h:178
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28

References createTempGistContext(), GISTScanOpaqueData::curBlkno, GISTScanOpaqueData::curPageLSN, GISTScanOpaqueData::distances, GISTScanOpaqueData::giststate, IndexScanDescData::indexRelation, initGISTstate(), InvalidBlockNumber, InvalidXLogRecPtr, GISTScanOpaqueData::killedItems, MemoryContextSwitchTo(), IndexScanDescData::numberOfOrderBys, GISTScanOpaqueData::numKilled, IndexScanDescData::opaque, palloc(), palloc0(), GISTScanOpaqueData::qual_ok, GISTScanOpaqueData::queue, GISTScanOpaqueData::queueCxt, RelationGetIndexScan(), GISTSTATE::scanCxt, GISTSTATE::tempCxt, IndexScanDescData::xs_orderbynulls, and IndexScanDescData::xs_orderbyvals.

Referenced by gisthandler().

◆ gistendscan()

void gistendscan ( IndexScanDesc  scan)

Definition at line 347 of file gistscan.c.

348{
350
351 /*
352 * freeGISTstate is enough to clean up everything made by gistbeginscan,
353 * as well as the queueCxt if there is a separate context for it.
354 */
356}
void freeGISTstate(GISTSTATE *giststate)
Definition: gist.c:1652

References freeGISTstate(), GISTScanOpaqueData::giststate, 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;
134 MemoryContext oldCxt;
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 */
158 "GiST queue context",
160 first_time = false;
161 }
162 else
163 {
164 /* third or later time through */
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 */
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,
201 attno - 1)->atttypid,
202 -1, 0);
203 }
205
206 /* Also create a memory context that will hold the returned tuples */
208 "GiST page data context",
210 }
211
212 /* create new, empty pairing heap for search queue */
213 oldCxt = MemoryContextSwitchTo(so->queueCxt);
215 MemoryContextSwitchTo(oldCxt);
216
217 so->firstCall = true;
218
219 /* Update scan key, if a new one is given */
220 if (key && scan->numberOfKeys > 0)
221 {
222 void **fn_extras = NULL;
223
224 /*
225 * If this isn't the first time through, preserve the fn_extra
226 * pointers, so that if the consistentFns are using them to cache
227 * data, that data is not leaked across a rescan.
228 */
229 if (!first_time)
230 {
231 fn_extras = (void **) palloc(scan->numberOfKeys * sizeof(void *));
232 for (i = 0; i < scan->numberOfKeys; i++)
233 fn_extras[i] = scan->keyData[i].sk_func.fn_extra;
234 }
235
236 memcpy(scan->keyData, key, scan->numberOfKeys * sizeof(ScanKeyData));
237
238 /*
239 * Modify the scan key so that the Consistent method is called for all
240 * comparisons. The original operator is passed to the Consistent
241 * function in the form of its strategy number, which is available
242 * from the sk_strategy field, and its subtype from the sk_subtype
243 * field.
244 *
245 * Next, if any of keys is a NULL and that key is not marked with
246 * SK_SEARCHNULL/SK_SEARCHNOTNULL then nothing can be found (ie, we
247 * assume all indexable operators are strict).
248 */
249 so->qual_ok = true;
250
251 for (i = 0; i < scan->numberOfKeys; i++)
252 {
253 ScanKey skey = scan->keyData + i;
254
255 /*
256 * Copy consistent support function to ScanKey structure instead
257 * of function implementing filtering operator.
258 */
259 fmgr_info_copy(&(skey->sk_func),
260 &(so->giststate->consistentFn[skey->sk_attno - 1]),
261 so->giststate->scanCxt);
262
263 /* Restore prior fn_extra pointers, if not first time */
264 if (!first_time)
265 skey->sk_func.fn_extra = fn_extras[i];
266
267 if (skey->sk_flags & SK_ISNULL)
268 {
269 if (!(skey->sk_flags & (SK_SEARCHNULL | SK_SEARCHNOTNULL)))
270 so->qual_ok = false;
271 }
272 }
273
274 if (!first_time)
275 pfree(fn_extras);
276 }
277
278 /* Update order-by key, if a new one is given */
279 if (orderbys && scan->numberOfOrderBys > 0)
280 {
281 void **fn_extras = NULL;
282
283 /* As above, preserve fn_extra if not first time through */
284 if (!first_time)
285 {
286 fn_extras = (void **) palloc(scan->numberOfOrderBys * sizeof(void *));
287 for (i = 0; i < scan->numberOfOrderBys; i++)
288 fn_extras[i] = scan->orderByData[i].sk_func.fn_extra;
289 }
290
291 memcpy(scan->orderByData, orderbys, scan->numberOfOrderBys * sizeof(ScanKeyData));
292
293 so->orderByTypes = (Oid *) palloc(scan->numberOfOrderBys * sizeof(Oid));
294
295 /*
296 * Modify the order-by key so that the Distance method is called for
297 * all comparisons. The original operator is passed to the Distance
298 * function in the form of its strategy number, which is available
299 * from the sk_strategy field, and its subtype from the sk_subtype
300 * field.
301 */
302 for (i = 0; i < scan->numberOfOrderBys; i++)
303 {
304 ScanKey skey = scan->orderByData + i;
305 FmgrInfo *finfo = &(so->giststate->distanceFn[skey->sk_attno - 1]);
306
307 /* Check we actually have a distance function ... */
308 if (!OidIsValid(finfo->fn_oid))
309 elog(ERROR, "missing support function %d for attribute %d of index \"%s\"",
312
313 /*
314 * Look up the datatype returned by the original ordering
315 * operator. GiST always uses a float8 for the distance function,
316 * but the ordering operator could be anything else.
317 *
318 * XXX: The distance function is only allowed to be lossy if the
319 * ordering operator's result type is float4 or float8. Otherwise
320 * we don't know how to return the distance to the executor. But
321 * we cannot check that here, as we won't know if the distance
322 * function is lossy until it returns *recheck = true for the
323 * first time.
324 */
326
327 /*
328 * Copy distance support function to ScanKey structure instead of
329 * function implementing ordering operator.
330 */
331 fmgr_info_copy(&(skey->sk_func), finfo, so->giststate->scanCxt);
332
333 /* Restore prior fn_extra pointers, if not first time */
334 if (!first_time)
335 skey->sk_func.fn_extra = fn_extras[i];
336 }
337
338 if (!first_time)
339 pfree(fn_extras);
340 }
341
342 /* any previous xs_hitup will have been pfree'd in context resets above */
343 scan->xs_hitup = NULL;
344}
#define Assert(condition)
Definition: c.h:815
#define OidIsValid(objectId)
Definition: c.h:732
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
Definition: fmgr.c:580
#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:72
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:76
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1655
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
void pfree(void *pointer)
Definition: mcxt.c:1521
#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
Definition: postgres_ext.h:32
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:511
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:524
#define SK_SEARCHNOTNULL
Definition: skey.h:122
#define SK_SEARCHNULL
Definition: skey.h:121
#define SK_ISNULL
Definition: skey.h:115
Definition: fmgr.h:57
void * fn_extra
Definition: fmgr.h:64
Oid fn_oid
Definition: fmgr.h:59
TupleDesc leafTupdesc
Definition: gist_private.h:80
TupleDesc fetchTupdesc
Definition: gist_private.h:83
FmgrInfo distanceFn[INDEX_MAX_KEYS]
Definition: gist_private.h:93
FmgrInfo consistentFn[INDEX_MAX_KEYS]
Definition: gist_private.h:86
MemoryContext pageDataCxt
Definition: gist_private.h:177
struct ScanKeyData * keyData
Definition: relscan.h:139
struct ScanKeyData * orderByData
Definition: relscan.h:140
HeapTuple xs_hitup
Definition: relscan.h:161
struct TupleDescData * xs_hitupdesc
Definition: relscan.h:162
Oid * rd_opcintype
Definition: rel.h:208
int sk_flags
Definition: skey.h:66
FmgrInfo sk_func
Definition: skey.h:71
AttrNumber sk_attno
Definition: skey.h:67
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:164
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:798
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:153

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, GISTSTATE::consistentFn, CreateTemplateTupleDesc(), GISTSTATE::distanceFn, elog, ERROR, GISTSTATE::fetchTupdesc, GISTScanOpaqueData::firstCall, fmgr_info_copy(), FmgrInfo::fn_extra, FmgrInfo::fn_oid, get_func_rettype(), GIST_DISTANCE_PROC, GISTScanOpaqueData::giststate, i, if(), IndexScanDescData::indexRelation, IndexRelationGetNumberOfKeyAttributes, sort-test::key, IndexScanDescData::keyData, GISTSTATE::leafTupdesc, MemoryContextReset(), MemoryContextSwitchTo(), IndexScanDescData::numberOfKeys, IndexScanDescData::numberOfOrderBys, OidIsValid, IndexScanDescData::opaque, IndexScanDescData::orderByData, GISTScanOpaqueData::orderByTypes, GISTScanOpaqueData::pageDataCxt, pairingheap_allocate(), pairingheap_GISTSearchItem_cmp(), palloc(), pfree(), GISTScanOpaqueData::qual_ok, GISTScanOpaqueData::queue, GISTScanOpaqueData::queueCxt, RelationData::rd_opcintype, RelationGetNumberOfAttributes, RelationGetRelationName, GISTSTATE::scanCxt, ScanKeyData::sk_attno, ScanKeyData::sk_flags, ScanKeyData::sk_func, SK_ISNULL, SK_SEARCHNOTNULL, SK_SEARCHNULL, TupleDescAttr(), 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}
int float8_cmp_internal(float8 a, float8 b)
Definition: float.c:910
struct IndexScanDescData * IndexScanDesc
Definition: genam.h:92
#define GISTSearchItemIsHeap(item)
Definition: gist_private.h:145
int b
Definition: isn.c:69
int a
Definition: isn.c:68
void * arg
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:743
IndexOrderByDistance distances[FLEXIBLE_ARRAY_MEMBER]
Definition: gist_private.h:142

References a, arg, b, cmp(), GISTSearchItem::distances, float8_cmp_internal(), GISTSearchItemIsHeap, i, IndexOrderByDistance::isnull, IndexScanDescData::numberOfOrderBys, and IndexOrderByDistance::value.

Referenced by gistrescan().