@@ -75,8 +75,136 @@ static int xConnect(sqlite3* db, void *pAux,
7575	return  xCreate (db , pAux , argc , argv , ppVTab , pzErr );
7676}
7777
78+ static  VALUE  constraint_op_as_symbol (unsigned char   op )
79+ {
80+ 	ID  op_id ;
81+ 	switch (op ) {
82+ 		case  SQLITE_INDEX_CONSTRAINT_EQ :
83+ 			op_id  =  rb_intern ("==" );
84+ 			break ;
85+ 		case  SQLITE_INDEX_CONSTRAINT_GT :
86+ 			op_id  =  rb_intern (">" );
87+ 			break ;
88+ 		case  SQLITE_INDEX_CONSTRAINT_LE :
89+ 			op_id  =  rb_intern ("<=" );
90+ 			break ;
91+ 		case  SQLITE_INDEX_CONSTRAINT_LT :
92+ 			op_id  =  rb_intern ("<" );
93+ 			break ;
94+ 		case  SQLITE_INDEX_CONSTRAINT_GE :
95+ 			op_id  =  rb_intern (">=" );
96+ 			break ;
97+ 		case  SQLITE_INDEX_CONSTRAINT_MATCH :
98+ 			op_id  =  rb_intern ("match" );
99+ 			break ;
100+ #if  SQLITE_VERSION_NUMBER >=3010000 
101+ 		case  SQLITE_INDEX_CONSTRAINT_LIKE :
102+ 			op_id  =  rb_intern ("like" );
103+ 			break ;
104+ 		case  SQLITE_INDEX_CONSTRAINT_GLOB :
105+ 			op_id  =  rb_intern ("glob" );
106+ 			break ;
107+ 		case  SQLITE_INDEX_CONSTRAINT_REGEXP :
108+ 			op_id  =  rb_intern ("regexp" );
109+ 			break ;
110+ #endif 
111+ #if  SQLITE_VERSION_NUMBER >=3009000 
112+ 		case  SQLITE_INDEX_SCAN_UNIQUE :
113+ 			op_id  =  rb_intern ("unique" );
114+ 			break ;
115+ #endif 
116+ 		default :
117+ 			op_id  =  rb_intern ("unsupported" );
118+ 	}
119+ 	return  ID2SYM (op_id );
120+ }
121+ 
122+ static  VALUE  constraint_to_ruby (const  struct  sqlite3_index_constraint *  c )
123+ {
124+ 	VALUE  cons  =  rb_ary_new2 (2 );
125+ 	rb_ary_store (cons , 0 , LONG2FIX (c -> iColumn ));
126+ 	rb_ary_store (cons , 1 , constraint_op_as_symbol (c -> op ));
127+ 	return  cons ;
128+ }
129+ 
130+ static  VALUE  order_by_to_ruby (const  struct  sqlite3_index_orderby *  c )
131+ {
132+ 	VALUE  order_by  =  rb_ary_new2 (2 );
133+ 	rb_ary_store (order_by , 0 , LONG2FIX (c -> iColumn ));
134+ 	rb_ary_store (order_by , 1 , LONG2FIX (1 - 2 * c -> desc ));
135+ 	return  order_by ;
136+ }
137+ 
78138static  int  xBestIndex (ruby_sqlite3_vtab  * pVTab , sqlite3_index_info *  info )
79139{
140+ 	int  i ;
141+ 	VALUE  constraint  =  rb_ary_new ();
142+         VALUE  order_by  =  rb_ary_new2 (info -> nOrderBy );
143+ 	VALUE  ret , idx_num , estimated_cost , order_by_consumed , omit_all ;
144+ #if  SQLITE_VERSION_NUMBER  >= 3008002 
145+ 	VALUE  estimated_rows ;
146+ #endif 
147+ #if  SQLITE_VERSION_NUMBER  >= 3009000 
148+ 	VALUE  idx_flags ;
149+ #endif 
150+ #if  SQLITE_VERSION_NUMBER  >= 3010000 
151+ 	VALUE  col_used ;
152+ #endif 
153+ 
154+ 	// convert constraints to ruby 
155+ 	for  (i  =  0 ; i  <  info -> nConstraint ; ++ i ) {
156+ 		if  (info -> aConstraint [i ].usable ) {
157+ 			rb_ary_push (constraint , constraint_to_ruby (info -> aConstraint  +  i ));
158+ 		} else  {
159+ 			printf ("ignoring %d %d\n" , info -> aConstraint [i ].iColumn , info -> aConstraint [i ].op );
160+ 		}
161+ 	}
162+ 
163+ 	// convert order_by to ruby 
164+ 	for  (i  =  0 ; i  <  info -> nOrderBy ; ++ i ) {
165+ 		rb_ary_store (order_by , i , order_by_to_ruby (info -> aOrderBy  +  i ));
166+ 	}
167+ 
168+ 	
169+ 	ret  =  rb_funcall ( pVTab -> vtable , rb_intern ("best_index" ), 2 , constraint , order_by  );
170+ 	if  (ret  !=  Qnil  ) {
171+ 		if  (!RB_TYPE_P (ret , T_HASH )) {
172+ 			rb_raise (rb_eTypeError , "best_index: expect returned value to be a Hash" );
173+ 		}
174+ 		idx_num  =  rb_hash_aref (ret , ID2SYM (rb_intern ("idxNum" )));
175+ 		if  (idx_num  ==  Qnil  ) { 
176+ 			rb_raise (rb_eKeyError , "best_index: mandatory key 'idxNum' not found" );
177+ 		}
178+ 		info -> idxNum  =  FIX2INT (idx_num );
179+ 		estimated_cost  =  rb_hash_aref (ret , ID2SYM (rb_intern ("estimatedCost" )));
180+ 		if  (estimated_cost  !=  Qnil ) { info -> estimatedCost  =  NUM2DBL (estimated_cost ); }
181+ 		order_by_consumed  =  rb_hash_aref (ret , ID2SYM (rb_intern ("orderByConsumed" )));
182+ 		info -> orderByConsumed  =  RTEST (order_by_consumed );
183+ #if  SQLITE_VERSION_NUMBER  >= 3008002 
184+ 		estimated_rows  =  rb_hash_aref (ret , ID2SYM (rb_intern ("estimatedRows" )));
185+ 		if  (estimated_rows  !=  Qnil ) { bignum_to_int64 (estimated_rows , & info -> estimatedRows ); }
186+ #endif 
187+ #if  SQLITE_VERSION_NUMBER  >= 3009000 
188+ 		idx_flags  =  rb_hash_aref (ret , ID2SYM (rb_intern ("idxFlags" )));
189+ 		if  (idx_flags  !=  Qnil ) { info -> idxFlags  =  FIX2INT (idx_flags ); }
190+ #endif 
191+ #if  SQLITE_VERSION_NUMBER  >= 3010000 
192+ 		col_used  =  rb_hash_aref (ret , ID2SYM (rb_intern ("colUsed" )));
193+ 		if  (col_used  !=  Qnil ) { bignum_to_int64 (col_used , & info -> colUsed ); }
194+ #endif 
195+ 
196+ 		// make sure that expression are given to filter 
197+ 		omit_all  =  rb_hash_aref (ret , ID2SYM (rb_intern ("omitAllConstraint" )));
198+ 		for  (i  =  0 ; i  <  info -> nConstraint ; ++ i ) {
199+ 			if  (RTEST (omit_all )) {
200+ 				info -> aConstraintUsage [i ].omit  =  1 ;
201+ 			}
202+ 			if  (info -> aConstraint [i ].usable ) {
203+ 				info -> aConstraintUsage [i ].argvIndex  =  (i + 1 );
204+ 			}
205+ 		}
206+ 	}
207+ 
80208	return  SQLITE_OK ;
81209}
82210
@@ -117,6 +245,12 @@ static int xNext(ruby_sqlite3_vtab_cursor* cursor)
117245static  int  xFilter (ruby_sqlite3_vtab_cursor *  cursor , int  idxNum , const  char  * idxStr ,
118246		int  argc , sqlite3_value  * * argv )
119247{
248+ 	int  i ;
249+ 	VALUE  argv_ruby  =  rb_ary_new2 (argc );
250+ 	for  (i  =  0 ; i  <  argc ; ++ i ) {
251+ 		rb_ary_store (argv_ruby , i , sqlite3val2rb (argv [i ]));
252+ 	}
253+ 	rb_funcall ( cursor -> pVTab -> vtable , rb_intern ("filter" ), 2 ,  LONG2FIX (idxNum ), argv_ruby  );
120254	cursor -> rowid  =  0 ;
121255	return  xNext (cursor );
122256}
0 commit comments