55#include "utils/builtins.h"
66#include "utils/elog.h"
77#include "utils/lsyscache.h"
8+ #include "utils/rel.h"
9+ #include "utils/fmgroids.h"
810
911#include "nodes/print.h"
1012
13+ #include "catalog/pg_am.h"
1114#include "catalog/pg_proc.h"
1215#include "catalog/pg_operator.h"
1316#include "commands/explain.h"
@@ -30,7 +33,12 @@ typedef struct
3033JoinType jointype ;
3134
3235Path * outer_path ;
36+ Oid outer_idx ;
37+ Oid outer_rel ;
38+
3339Path * inner_path ;
40+ Oid inner_idx ;
41+ Oid inner_rel ;
3442
3543List * joinrestrictinfo ;
3644}CrossmatchJoinPath ;
@@ -41,11 +49,13 @@ typedef struct
4149
4250List * scan_tlist ;
4351
44- Relation outer_rel ;
52+ Oid outer_idx ;
53+ Oid outer_rel ;
4554ItemPointer outer_ptr ;
4655HeapTuple outer_tup ;
4756
48- Relation inner_rel ;
57+ Oid inner_idx ;
58+ Oid inner_rel ;
4959ItemPointer inner_ptr ;
5060HeapTuple inner_tup ;
5161}CrossmatchScanState ;
@@ -55,6 +65,71 @@ static CustomScanMethodscrossmatch_plan_methods;
5565static CustomExecMethods crossmatch_exec_methods ;
5666
5767
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+
58133static Path *
59134crossmatch_find_cheapest_path (PlannerInfo * root ,
60135RelOptInfo * joinrel ,
@@ -95,6 +170,18 @@ create_crossmatch_path(PlannerInfo *root,
95170{
96171CrossmatchJoinPath * result ;
97172
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+
98185result = palloc0 (sizeof (CrossmatchJoinPath ));
99186NodeSetTag (result ,T_CustomPath );
100187
@@ -107,11 +194,15 @@ create_crossmatch_path(PlannerInfo *root,
107194result -> cpath .flags = 0 ;
108195result -> cpath .methods = & crossmatch_path_methods ;
109196result -> outer_path = outer_path ;
197+ result -> outer_idx = outer_idx ;
198+ result -> outer_rel = outer_rel ;
110199result -> inner_path = inner_path ;
200+ result -> inner_idx = inner_idx ;
201+ result -> inner_rel = inner_rel ;
111202result -> joinrestrictinfo = restrict_clauses ;
112203
113204/* TODO: real costs */
114- result -> cpath .path .startup_cost = 1 ;
205+ result -> cpath .path .startup_cost = 0 ;
115206result -> cpath .path .total_cost = 1 ;
116207
117208add_path (joinrel ,& result -> cpath .path );
@@ -237,12 +328,6 @@ create_crossmatch_plan(PlannerInfo *root,
237328List * otherclauses ;
238329CustomScan * cscan ;
239330
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-
246331if (IS_OUTER_JOIN (gpath -> jointype ))
247332{
248333extract_actual_join_clauses (joinrestrictclauses ,
@@ -264,8 +349,10 @@ create_crossmatch_plan(PlannerInfo *root,
264349cscan -> flags = best_path -> flags ;
265350cscan -> methods = & crossmatch_plan_methods ;
266351
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 );
269356
270357return & cscan -> scan .plan ;
271358}
@@ -279,13 +366,15 @@ crossmatch_create_scan_state(CustomScan *node)
279366scan_state -> css .flags = node -> flags ;
280367scan_state -> css .methods = & crossmatch_exec_methods ;
281368
369+ /* TODO: check if this assignment is redundant */
282370scan_state -> css .ss .ps .ps_TupFromTlist = false;
283371
284372scan_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 );
289378
290379return (Node * )scan_state ;
291380}
@@ -306,7 +395,7 @@ crossmatch_exec(CustomScanState *node)
306395
307396/* TODO: fill with real data from joined tables */
308397Datum values [2 ]= {DirectFunctionCall1 (spherepoint_in ,CStringGetDatum ("(0d, 0d)" )),
309- DirectFunctionCall1 (spherepoint_in ,CStringGetDatum ("(0d, 0d )" )) };
398+ DirectFunctionCall1 (spherepoint_in ,CStringGetDatum ("(1d, 1d )" )) };
310399bool nulls [2 ]= {0 ,0 };
311400
312401elog (LOG ,"slot.natts: %d" ,tupdesc -> natts );
@@ -319,6 +408,7 @@ crossmatch_exec(CustomScanState *node)
319408{
320409ExprDoneCond isDone ;
321410
411+ /* TODO: find a better way to fill 'ecxt_scantuple' */
322412node -> ss .ps .ps_ProjInfo -> pi_exprContext -> ecxt_scantuple = ExecStoreTuple (htup ,slot ,InvalidBuffer , false);
323413
324414result = ExecProject (node -> ss .ps .ps_ProjInfo ,& isDone );
@@ -342,10 +432,7 @@ crossmatch_exec(CustomScanState *node)
342432static void
343433crossmatch_end (CustomScanState * node )
344434{
345- CrossmatchScanState * scan_state = (CrossmatchScanState * )node ;
346435
347- heap_close (scan_state -> outer_rel ,AccessShareLock );
348- heap_close (scan_state -> inner_rel ,AccessShareLock );
349436}
350437
351438static void