mirror of
				https://github.com/isar/rusqlite.git
				synced 2025-11-01 06:18:54 +08:00 
			
		
		
		
	Partial CSV virtual table implementation.
This commit is contained in:
		
							
								
								
									
										114
									
								
								src/vtab/csvtab.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/vtab/csvtab.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,114 @@ | ||||
| //! CSV Virtual Table | ||||
| extern crate csv; | ||||
| use std::fs::File; | ||||
| use std::mem; | ||||
| use libc; | ||||
|  | ||||
| use {Connection, Error, Result}; | ||||
| use ffi; | ||||
| use vtab::declare_vtab; | ||||
|  | ||||
| use self::csv::Reader; | ||||
|  | ||||
| pub fn load_module(conn: &Connection) -> Result<()> { | ||||
|     let aux: Option<()> = None; | ||||
|     conn.create_module("csv", &CSV_MODULE, aux) | ||||
| } | ||||
|  | ||||
| init_module!(CSV_MODULE, CSVTab, CSVTabCursor, | ||||
|     csv_create, csv_best_index, csv_destroy, | ||||
|     csv_open, csv_close, | ||||
|     csv_filter, csv_next, csv_eof, | ||||
|     csv_column, csv_rowid); | ||||
|  | ||||
| #[repr(C)] | ||||
| struct CSVTab { | ||||
|     /// Base class | ||||
|     base: ffi::sqlite3_vtab, | ||||
|     reader: csv::Reader<File>, | ||||
|     offset_first_row: u64, | ||||
| } | ||||
|  | ||||
| impl CSVTab { | ||||
|     fn create(db: *mut ffi::sqlite3, | ||||
|               aux: *mut libc::c_void, | ||||
|               _argc: libc::c_int, | ||||
|               _argv: *const *const libc::c_char) | ||||
|               -> Result<CSVTab> { | ||||
|         let reader = try!(csv::Reader::from_file("FIXME")); | ||||
|         let vtab = CSVTab { | ||||
|             base: Default::default(), | ||||
|             reader: reader, | ||||
|             offset_first_row: 0, | ||||
|         }; | ||||
|         unimplemented!(); | ||||
|         try!(declare_vtab(db, "CREATE TABLE x FIXME")); | ||||
|         Ok(vtab) | ||||
|     } | ||||
|  | ||||
|     fn best_index(&self, _info: *mut ffi::sqlite3_index_info) {} | ||||
|  | ||||
|     fn open(&self) -> Result<CSVTabCursor> { | ||||
|         Ok(CSVTabCursor::new()) | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| #[repr(C)] | ||||
| struct CSVTabCursor { | ||||
|     /// Base class | ||||
|     base: ffi::sqlite3_vtab_cursor, | ||||
|     /// Current cursor position | ||||
|     row_number: usize, | ||||
| } | ||||
|  | ||||
| impl CSVTabCursor { | ||||
|     fn new() -> CSVTabCursor { | ||||
|         CSVTabCursor { | ||||
|             base: Default::default(), | ||||
|             row_number: 0, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn vtab(&self) -> &mut CSVTab { | ||||
|         unsafe { &mut *(self.base.pVtab as *mut CSVTab) } | ||||
|     } | ||||
|  | ||||
|     fn filter(&mut self) -> Result<()> { | ||||
|         { | ||||
|             let vtab = self.vtab(); | ||||
|             vtab.reader.seek(vtab.offset_first_row); // FIXME Result ignore | ||||
|         } | ||||
|         self.row_number = 0; | ||||
|         self.next() | ||||
|     } | ||||
|     fn next(&mut self) -> Result<()> { | ||||
|         let vtab = self.vtab(); | ||||
|         if vtab.reader.done() { | ||||
|             return Err(Error::SqliteFailure(ffi::Error::new(ffi::SQLITE_ERROR), None)); | ||||
|         } | ||||
|         unimplemented!(); | ||||
|         // self.row_number = self.row_number + 1; | ||||
|         Ok(()) | ||||
|     } | ||||
|     fn eof(&self) -> bool { | ||||
|         let vtab = self.vtab(); | ||||
|         unsafe { (*vtab).reader.done() } | ||||
|     } | ||||
|     fn column(&self, ctx: *mut ffi::sqlite3_context, _i: libc::c_int) -> Result<()> { | ||||
|         let vtab = self.vtab(); | ||||
|         unimplemented!(); | ||||
|         // TODO.set_result(ctx); | ||||
|         Ok(()) | ||||
|     } | ||||
|     fn rowid(&self) -> Result<i64> { | ||||
|         Ok(self.row_number as i64) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<csv::Error> for Error { | ||||
|     fn from(err: csv::Error) -> Error { | ||||
|         use std::error::Error as StdError; | ||||
|         Error::ModuleError(String::from(err.description())) | ||||
|     } | ||||
| } | ||||
| @@ -1,5 +1,4 @@ | ||||
| //! Int array virtual table. | ||||
| use std::error::Error as StdError; | ||||
| use std::cell::RefCell; | ||||
| use std::default::Default; | ||||
| use std::mem; | ||||
| @@ -8,12 +7,11 @@ use libc; | ||||
|  | ||||
| use {Connection, Error, Result}; | ||||
| use ffi; | ||||
| use functions::ToResult; | ||||
| use vtab::{declare_vtab, mprintf}; | ||||
| use vtab::declare_vtab; | ||||
|  | ||||
| pub fn create_int_array(conn: &Connection, name: &str) -> Result<Rc<RefCell<Vec<i64>>>> { | ||||
|     let array = Rc::new(RefCell::new(Vec::new())); | ||||
|     try!(conn.create_module(name, &INT_ARRAY_MODULE, array.clone())); | ||||
|     try!(conn.create_module(name, &INT_ARRAY_MODULE, Some(array.clone()))); | ||||
|     try!(conn.execute_batch(&format!("CREATE VIRTUAL TABLE temp.{0} USING {0}", | ||||
|                                      escape_quote(name.to_string())))); | ||||
|     Ok(array) | ||||
| @@ -60,11 +58,10 @@ impl IntArrayVTab { | ||||
|         Ok(vtab) | ||||
|     } | ||||
|  | ||||
|     fn best_index(&self, _info: *mut ffi::sqlite3_index_info) { | ||||
|     } | ||||
|     fn best_index(&self, _info: *mut ffi::sqlite3_index_info) {} | ||||
|  | ||||
|     fn open(&self) -> IntArrayVTabCursor { | ||||
|         IntArrayVTabCursor::new() | ||||
|     fn open(&self) -> Result<IntArrayVTabCursor> { | ||||
|         Ok(IntArrayVTabCursor::new()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -84,35 +81,36 @@ impl IntArrayVTabCursor { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn vtab(&self) -> *mut IntArrayVTab { | ||||
|         self.base.pVtab as *mut IntArrayVTab | ||||
|     fn vtab(&self) -> &mut IntArrayVTab { | ||||
|         unsafe { &mut *(self.base.pVtab as *mut IntArrayVTab) } | ||||
|     } | ||||
|  | ||||
|     fn filter(&mut self) -> libc::c_int { | ||||
|     fn filter(&mut self) -> Result<()> { | ||||
|         self.i = 0; | ||||
|         ffi::SQLITE_OK | ||||
|         Ok(()) | ||||
|     } | ||||
|     fn next(&mut self) -> libc::c_int { | ||||
|     fn next(&mut self) -> Result<()> { | ||||
|         self.i = self.i + 1; | ||||
|         ffi::SQLITE_OK | ||||
|         Ok(()) | ||||
|     } | ||||
|     fn eof(&self) -> bool { | ||||
|         let vtab = self.vtab(); | ||||
|         unsafe { | ||||
|             let array = (*(*vtab).array).borrow(); | ||||
|             let array = (*vtab.array).borrow(); | ||||
|             self.i >= array.len() | ||||
|         } | ||||
|     } | ||||
|     fn column(&self, ctx: *mut ffi::sqlite3_context, _i: libc::c_int) -> libc::c_int { | ||||
|     fn column(&self, ctx: *mut ffi::sqlite3_context, _i: libc::c_int) -> Result<()> { | ||||
|         use functions::ToResult; | ||||
|         let vtab = self.vtab(); | ||||
|         unsafe { | ||||
|             let array = (*(*vtab).array).borrow(); | ||||
|             let array = (*vtab.array).borrow(); | ||||
|             array[self.i].set_result(ctx); | ||||
|         } | ||||
|         ffi::SQLITE_OK | ||||
|         Ok(()) | ||||
|     } | ||||
|     fn rowid(&self) -> i64 { | ||||
|         self.i as i64 | ||||
|     fn rowid(&self) -> Result<i64> { | ||||
|         Ok(self.i as i64) | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										142
									
								
								src/vtab/mod.rs
									
									
									
									
									
								
							
							
						
						
									
										142
									
								
								src/vtab/mod.rs
									
									
									
									
									
								
							| @@ -1,8 +1,8 @@ | ||||
| //! Create virtual tables. | ||||
| //! (See http://sqlite.org/vtab.html) | ||||
| use std::error::Error as StdError; | ||||
| use std::ffi::CString; | ||||
| use std::mem; | ||||
| use std::ptr; | ||||
| use libc; | ||||
|  | ||||
| use {Connection, Error, Result, InnerConnection, str_to_cstring}; | ||||
| @@ -29,7 +29,7 @@ use ffi; | ||||
| // | ||||
| // let stmt = conn.prepare("SELECT ... FROM foo WHERE ..."); | ||||
| // \-> vtab.xbestindex | ||||
| // stmt.quey().next(); | ||||
| // stmt.query().next(); | ||||
| // \-> vtab.xopen | ||||
| //  |-> let cursor: Cursor = ...; // on the heap | ||||
| //  |-> cursor.xfilter or xnext | ||||
| @@ -42,7 +42,7 @@ impl Connection { | ||||
|     pub fn create_module<A>(&self, | ||||
|                             module_name: &str, | ||||
|                             module: *const ffi::sqlite3_module, | ||||
|                             aux: A) | ||||
|                             aux: Option<A>) | ||||
|                             -> Result<()> { | ||||
|         self.db | ||||
|             .borrow_mut() | ||||
| @@ -54,16 +54,27 @@ impl InnerConnection { | ||||
|     fn create_module<A>(&mut self, | ||||
|                         module_name: &str, | ||||
|                         module: *const ffi::sqlite3_module, | ||||
|                         aux: A) | ||||
|                         aux: Option<A>) | ||||
|                         -> Result<()> { | ||||
|         let boxed_aux: *mut A = Box::into_raw(Box::new(aux)); | ||||
|         let c_name = try!(str_to_cstring(module_name)); | ||||
|         let r = unsafe { | ||||
|             ffi::sqlite3_create_module_v2(self.db(), | ||||
|                                           c_name.as_ptr(), | ||||
|                                           module, | ||||
|                                           mem::transmute(boxed_aux), | ||||
|                                           Some(mem::transmute(free_boxed_value::<A>))) | ||||
|         let r = match aux { | ||||
|             Some(aux) => { | ||||
|                 let boxed_aux: *mut A = Box::into_raw(Box::new(aux)); | ||||
|                 unsafe { | ||||
|                     ffi::sqlite3_create_module_v2(self.db(), | ||||
|                                                   c_name.as_ptr(), | ||||
|                                                   module, | ||||
|                                                   mem::transmute(boxed_aux), | ||||
|                                                   Some(mem::transmute(free_boxed_value::<A>))) | ||||
|                 } | ||||
|             } | ||||
|             None => unsafe { | ||||
|                 ffi::sqlite3_create_module_v2(self.db(), | ||||
|                                               c_name.as_ptr(), | ||||
|                                               module, | ||||
|                                               ptr::null_mut(), | ||||
|                                               None) | ||||
|             }, | ||||
|         }; | ||||
|         self.decode_result(r) | ||||
|     } | ||||
| @@ -125,25 +136,23 @@ unsafe extern "C" fn $create(db: *mut ffi::sqlite3, | ||||
|                               pp_vtab: *mut *mut ffi::sqlite3_vtab, | ||||
|                               err_msg: *mut *mut libc::c_char) | ||||
|                               -> libc::c_int { | ||||
|     use std::error::Error as StdError; | ||||
|     use vtab::mprintf; | ||||
|     match $vtab::create(db, aux, argc, argv) { | ||||
|         Ok(vtab) => { | ||||
|             let boxed_vtab: *mut $vtab = Box::into_raw(Box::new(vtab)); | ||||
|             *pp_vtab = boxed_vtab as *mut ffi::sqlite3_vtab; | ||||
|             ffi::SQLITE_OK | ||||
|         } | ||||
|         Err(err) => { | ||||
|             match err { | ||||
|                 Error::SqliteFailure(err, s) => { | ||||
|                     if let Some(s) = s { | ||||
|                         *err_msg = mprintf(&s); | ||||
|                     } | ||||
|                     err.extended_code | ||||
|                 } | ||||
|                 _ => { | ||||
|                     *err_msg = mprintf(err.description()); | ||||
|                     ffi::SQLITE_ERROR | ||||
|                 } | ||||
|         Err(Error::SqliteFailure(err, s)) => { | ||||
|             if let Some(s) = s { | ||||
|                 *err_msg = mprintf(&s); | ||||
|             } | ||||
|             err.extended_code | ||||
|         }, | ||||
|         Err(err) => { | ||||
|             *err_msg = mprintf(err.description()); | ||||
|             ffi::SQLITE_ERROR | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -163,15 +172,28 @@ unsafe extern "C" fn $destroy(vtab: *mut ffi::sqlite3_vtab) -> libc::c_int { | ||||
| unsafe extern "C" fn $open(vtab: *mut ffi::sqlite3_vtab, | ||||
|                             pp_cursor: *mut *mut ffi::sqlite3_vtab_cursor) | ||||
|                             -> libc::c_int { | ||||
|     let vtab = vtab as *mut $vtab; | ||||
|     let cursor = (*vtab).open(); | ||||
|     let boxed_cursor: *mut $cursor = Box::into_raw(Box::new(cursor)); | ||||
|     *pp_cursor = boxed_cursor as *mut ffi::sqlite3_vtab_cursor; | ||||
|     ffi::SQLITE_OK | ||||
|     use vtab::set_err_msg; | ||||
|     let vt = vtab as *mut $vtab; | ||||
|     match (*vt).open() { | ||||
|         Ok(cursor) => { | ||||
|             let boxed_cursor: *mut $cursor = Box::into_raw(Box::new(cursor)); | ||||
|             *pp_cursor = boxed_cursor as *mut ffi::sqlite3_vtab_cursor; | ||||
|             ffi::SQLITE_OK | ||||
|         }, | ||||
|         Err(Error::SqliteFailure(err, s)) => { | ||||
|             if let Some(err_msg) = s { | ||||
|                 set_err_msg(vtab, &err_msg); | ||||
|             } | ||||
|             err.extended_code | ||||
|         } | ||||
|         Err(_) => { | ||||
|             ffi::SQLITE_ERROR | ||||
|         } | ||||
|     } | ||||
| } | ||||
| unsafe extern "C" fn $close(cursor: *mut ffi::sqlite3_vtab_cursor) -> libc::c_int { | ||||
|     let cursor = cursor as *mut $cursor; | ||||
|     let _: Box<$cursor> = Box::from_raw(mem::transmute(cursor)); | ||||
|     let cr = cursor as *mut $cursor; | ||||
|     let _: Box<$cursor> = Box::from_raw(mem::transmute(cr)); | ||||
|     ffi::SQLITE_OK | ||||
| } | ||||
|  | ||||
| @@ -181,35 +203,70 @@ unsafe extern "C" fn $filter(cursor: *mut ffi::sqlite3_vtab_cursor, | ||||
|                               _argc: libc::c_int, | ||||
|                               _argv: *mut *mut ffi::sqlite3_value) | ||||
|                               -> libc::c_int { | ||||
|     let cursor = cursor as *mut $cursor; | ||||
|     (*cursor).filter() | ||||
|     use vtab::cursor_error; | ||||
|     let cr = cursor as *mut $cursor; | ||||
|     cursor_error(cursor, (*cr).filter()) | ||||
| } | ||||
| unsafe extern "C" fn $next(cursor: *mut ffi::sqlite3_vtab_cursor) -> libc::c_int { | ||||
|     let cursor = cursor as *mut $cursor; | ||||
|     (*cursor).next() | ||||
|     use vtab::cursor_error; | ||||
|     let cr = cursor as *mut $cursor; | ||||
|     cursor_error(cursor, (*cr).next()) | ||||
| } | ||||
| unsafe extern "C" fn $eof(cursor: *mut ffi::sqlite3_vtab_cursor) -> libc::c_int { | ||||
|     let cursor = cursor as *mut $cursor; | ||||
|     (*cursor).eof() as libc::c_int | ||||
|     let cr = cursor as *mut $cursor; | ||||
|     (*cr).eof() as libc::c_int | ||||
| } | ||||
| unsafe extern "C" fn $column(cursor: *mut ffi::sqlite3_vtab_cursor, | ||||
|                               ctx: *mut ffi::sqlite3_context, | ||||
|                               i: libc::c_int) | ||||
|                               -> libc::c_int { | ||||
|     let cursor = cursor as *mut $cursor; | ||||
|     (*cursor).column(ctx, i) | ||||
|     use vtab::cursor_error; | ||||
|     let cr = cursor as *mut $cursor; | ||||
|     cursor_error(cursor, (*cr).column(ctx, i)) | ||||
| } | ||||
| unsafe extern "C" fn $rowid(cursor: *mut ffi::sqlite3_vtab_cursor, | ||||
|                              p_rowid: *mut ffi::sqlite3_int64) | ||||
|                              -> libc::c_int { | ||||
|     let cursor = cursor as *mut $cursor; | ||||
|     *p_rowid = (*cursor).rowid(); | ||||
|     ffi::SQLITE_OK | ||||
|     use vtab::cursor_error; | ||||
|     let cr = cursor as *mut $cursor; | ||||
|     match (*cr).rowid() { | ||||
|         Ok(rowid) => { | ||||
|             *p_rowid = rowid; | ||||
|             ffi::SQLITE_OK | ||||
|         }, | ||||
|         err => cursor_error(cursor, err) | ||||
|     } | ||||
| } | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub unsafe fn cursor_error<T>(cursor: *mut ffi::sqlite3_vtab_cursor, | ||||
|                               result: Result<T>) | ||||
|                               -> libc::c_int { | ||||
|     match result { | ||||
|         Ok(_) => ffi::SQLITE_OK, | ||||
|         Err(Error::SqliteFailure(err, s)) => { | ||||
|             if let Some(err_msg) = s { | ||||
|                 set_err_msg((*cursor).pVtab, &err_msg); | ||||
|             } | ||||
|             err.extended_code | ||||
|         } | ||||
|         Err(_) => { | ||||
|             // TODO errMsg | ||||
|             ffi::SQLITE_ERROR | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| unsafe fn set_err_msg(vtab: *mut ffi::sqlite3_vtab, err_msg: &str) { | ||||
|     if !(*vtab).zErrMsg.is_null() { | ||||
|         ffi::sqlite3_free((*vtab).zErrMsg as *mut libc::c_void); | ||||
|     } | ||||
|     (*vtab).zErrMsg = mprintf(err_msg); | ||||
| } | ||||
|  | ||||
| unsafe fn result_error(ctx: *mut ffi::sqlite3_context, err: Error) -> libc::c_int { | ||||
|     use std::error::Error as StdError; | ||||
|     match err { | ||||
|         Error::SqliteFailure(err, s) => { | ||||
|             ffi::sqlite3_result_error_code(ctx, err.extended_code); | ||||
| @@ -235,4 +292,5 @@ pub fn mprintf(err_msg: &str) -> *mut ::libc::c_char { | ||||
|     unsafe { ffi::sqlite3_mprintf(c_format.as_ptr(), c_err.as_ptr()) } | ||||
| } | ||||
|  | ||||
| pub mod int_array; | ||||
| pub mod int_array; | ||||
| #[cfg(feature = "csvtab")]pub mod csvtab; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user