5
5
#include "utils/builtins.h"
6
6
#include "utils/elog.h"
7
7
#include "utils/lsyscache.h"
8
+ #include "utils/rel.h"
9
+ #include "utils/fmgroids.h"
8
10
9
11
#include "nodes/print.h"
10
12
13
+ #include "catalog/pg_am.h"
11
14
#include "catalog/pg_proc.h"
12
15
#include "catalog/pg_operator.h"
13
16
#include "commands/explain.h"
@@ -30,7 +33,12 @@ typedef struct
30
33
JoinType jointype ;
31
34
32
35
Path * outer_path ;
36
+ Oid outer_idx ;
37
+ Oid outer_rel ;
38
+
33
39
Path * inner_path ;
40
+ Oid inner_idx ;
41
+ Oid inner_rel ;
34
42
35
43
List * joinrestrictinfo ;
36
44
} CrossmatchJoinPath ;
@@ -41,11 +49,13 @@ typedef struct
41
49
42
50
List * scan_tlist ;
43
51
44
- Relation outer_rel ;
52
+ Oid outer_idx ;
53
+ Oid outer_rel ;
45
54
ItemPointer outer_ptr ;
46
55
HeapTuple outer_tup ;
47
56
48
- Relation inner_rel ;
57
+ Oid inner_idx ;
58
+ Oid inner_rel ;
49
59
ItemPointer inner_ptr ;
50
60
HeapTuple inner_tup ;
51
61
} CrossmatchScanState ;
@@ -55,6 +65,71 @@ static CustomScanMethods crossmatch_plan_methods;
55
65
static CustomExecMethods crossmatch_exec_methods ;
56
66
57
67
68
+ /*
69
+ * TODO: check for the predicates & decide
70
+ * whether some partial indices may suffice
71
+ */
72
+ static Oid
73
+ pick_suitable_index (Oid relation , AttrNumber column )
74
+ {
75
+ Oid found_index = InvalidOid ;
76
+ int64 found_index_size = 0 ;
77
+ HeapTuple htup ;
78
+ SysScanDesc scan ;
79
+ Relation pg_index ;
80
+ ScanKeyData key [3 ];
81
+
82
+ ScanKeyInit (& key [0 ],
83
+ Anum_pg_index_indrelid ,
84
+ BTEqualStrategyNumber ,
85
+ F_OIDEQ ,
86
+ ObjectIdGetDatum (relation ));
87
+
88
+ pg_index = heap_open (IndexRelationId , AccessShareLock );
89
+ scan = systable_beginscan (pg_index , InvalidOid , false, NULL , 1 , key );
90
+
91
+ while (HeapTupleIsValid (htup = systable_getnext (scan )))
92
+ {
93
+ Form_pg_index pg_ind = (Form_pg_index ) GETSTRUCT (htup );
94
+ Relation index ;
95
+ Oid index_am ;
96
+
97
+ index = index_open (pg_ind -> indexrelid , AccessShareLock );
98
+ index_am = index -> rd_rel -> relam ;
99
+ index_close (index , AccessShareLock );
100
+
101
+ /* check if this is a valid GIST index with no predicates */
102
+ if (index_am == GIST_AM_OID && pg_ind -> indisvalid &&
103
+ heap_attisnull (htup , Anum_pg_index_indpred ))
104
+ {
105
+ int i ;
106
+
107
+ for (i = 0 ; i < pg_ind -> indkey .dim1 ; i ++ )
108
+ {
109
+ int64 cur_index_size = 0 ;
110
+
111
+ if (pg_ind -> indkey .values [i ] == column )
112
+ {
113
+ cur_index_size = DatumGetInt64 (
114
+ DirectFunctionCall2 (pg_relation_size ,
115
+ ObjectIdGetDatum (relation ),
116
+ PointerGetDatum (cstring_to_text ("main" ))));
117
+
118
+ if (found_index == InvalidOid || cur_index_size < found_index_size )
119
+ found_index = pg_ind -> indexrelid ;
120
+
121
+ break ; /* no need to go further */
122
+ }
123
+ }
124
+ }
125
+ }
126
+
127
+ systable_endscan (scan );
128
+ heap_close (pg_index , AccessShareLock );
129
+
130
+ return found_index ;
131
+ }
132
+
58
133
static Path *
59
134
crossmatch_find_cheapest_path (PlannerInfo * root ,
60
135
RelOptInfo * joinrel ,
@@ -95,6 +170,18 @@ create_crossmatch_path(PlannerInfo *root,
95
170
{
96
171
CrossmatchJoinPath * result ;
97
172
173
+ Oid outer_rel = root -> simple_rte_array [outer_path -> parent -> relid ]-> relid ;
174
+ Oid inner_rel = root -> simple_rte_array [inner_path -> parent -> relid ]-> relid ;
175
+ Oid outer_idx ;
176
+ Oid inner_idx ;
177
+
178
+ /* TODO: use actual column numbers */
179
+ if ((outer_idx = pick_suitable_index (outer_rel , 1 )) == InvalidOid ||
180
+ (inner_idx = pick_suitable_index (inner_rel , 1 )) == InvalidOid )
181
+ {
182
+ return ;
183
+ }
184
+
98
185
result = palloc0 (sizeof (CrossmatchJoinPath ));
99
186
NodeSetTag (result , T_CustomPath );
100
187
@@ -107,11 +194,15 @@ create_crossmatch_path(PlannerInfo *root,
107
194
result -> cpath .flags = 0 ;
108
195
result -> cpath .methods = & crossmatch_path_methods ;
109
196
result -> outer_path = outer_path ;
197
+ result -> outer_idx = outer_idx ;
198
+ result -> outer_rel = outer_rel ;
110
199
result -> inner_path = inner_path ;
200
+ result -> inner_idx = inner_idx ;
201
+ result -> inner_rel = inner_rel ;
111
202
result -> joinrestrictinfo = restrict_clauses ;
112
203
113
204
/* TODO: real costs */
114
- result -> cpath .path .startup_cost = 1 ;
205
+ result -> cpath .path .startup_cost = 0 ;
115
206
result -> cpath .path .total_cost = 1 ;
116
207
117
208
add_path (joinrel , & result -> cpath .path );
@@ -237,12 +328,6 @@ create_crossmatch_plan(PlannerInfo *root,
237
328
List * otherclauses ;
238
329
CustomScan * cscan ;
239
330
240
- Index lrel = gpath -> outer_path -> parent -> relid ;
241
- Index rrel = gpath -> inner_path -> parent -> relid ;
242
-
243
- /* relids should not be 0 */
244
- Assert (lrel != 0 && rrel != 0 );
245
-
246
331
if (IS_OUTER_JOIN (gpath -> jointype ))
247
332
{
248
333
extract_actual_join_clauses (joinrestrictclauses ,
@@ -264,8 +349,10 @@ create_crossmatch_plan(PlannerInfo *root,
264
349
cscan -> flags = best_path -> flags ;
265
350
cscan -> methods = & crossmatch_plan_methods ;
266
351
267
- cscan -> custom_private = list_make2_oid (root -> simple_rte_array [lrel ]-> relid ,
268
- root -> simple_rte_array [rrel ]-> relid );
352
+ cscan -> custom_private = list_make4_oid (gpath -> outer_idx ,
353
+ gpath -> outer_rel ,
354
+ gpath -> inner_idx ,
355
+ gpath -> inner_rel );
269
356
270
357
return & cscan -> scan .plan ;
271
358
}
@@ -279,13 +366,15 @@ crossmatch_create_scan_state(CustomScan *node)
279
366
scan_state -> css .flags = node -> flags ;
280
367
scan_state -> css .methods = & crossmatch_exec_methods ;
281
368
369
+ /* TODO: check if this assignment is redundant */
282
370
scan_state -> css .ss .ps .ps_TupFromTlist = false;
283
371
284
372
scan_state -> scan_tlist = node -> custom_scan_tlist ;
285
- scan_state -> outer_rel = heap_open (linitial_oid (node -> custom_private ),
286
- AccessShareLock );
287
- scan_state -> inner_rel = heap_open (lsecond_oid (node -> custom_private ),
288
- AccessShareLock );
373
+
374
+ scan_state -> outer_idx = linitial_oid (node -> custom_private );
375
+ scan_state -> outer_rel = lsecond_oid (node -> custom_private );
376
+ scan_state -> inner_idx = lthird_oid (node -> custom_private );
377
+ scan_state -> outer_rel = lfourth_oid (node -> custom_private );
289
378
290
379
return (Node * ) scan_state ;
291
380
}
@@ -306,7 +395,7 @@ crossmatch_exec(CustomScanState *node)
306
395
307
396
/* TODO: fill with real data from joined tables */
308
397
Datum values [2 ] = { DirectFunctionCall1 (spherepoint_in , CStringGetDatum ("(0d, 0d)" )),
309
- DirectFunctionCall1 (spherepoint_in , CStringGetDatum ("(0d, 0d )" )) };
398
+ DirectFunctionCall1 (spherepoint_in , CStringGetDatum ("(1d, 1d )" )) };
310
399
bool nulls [2 ] = {0 ,0 };
311
400
312
401
elog (LOG , "slot.natts: %d" , tupdesc -> natts );
@@ -319,6 +408,7 @@ crossmatch_exec(CustomScanState *node)
319
408
{
320
409
ExprDoneCond isDone ;
321
410
411
+ /* TODO: find a better way to fill 'ecxt_scantuple' */
322
412
node -> ss .ps .ps_ProjInfo -> pi_exprContext -> ecxt_scantuple = ExecStoreTuple (htup , slot , InvalidBuffer , false);
323
413
324
414
result = ExecProject (node -> ss .ps .ps_ProjInfo , & isDone );
@@ -342,10 +432,7 @@ crossmatch_exec(CustomScanState *node)
342
432
static void
343
433
crossmatch_end (CustomScanState * node )
344
434
{
345
- CrossmatchScanState * scan_state = (CrossmatchScanState * ) node ;
346
435
347
- heap_close (scan_state -> outer_rel , AccessShareLock );
348
- heap_close (scan_state -> inner_rel , AccessShareLock );
349
436
}
350
437
351
438
static void
0 commit comments