aboutsummaryrefslogtreecommitdiff
path: root/src/vtab/csvtab.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/vtab/csvtab.rs')
-rw-r--r--src/vtab/csvtab.rs97
1 files changed, 45 insertions, 52 deletions
diff --git a/src/vtab/csvtab.rs b/src/vtab/csvtab.rs
index 79ec5da..df3529a 100644
--- a/src/vtab/csvtab.rs
+++ b/src/vtab/csvtab.rs
@@ -1,7 +1,7 @@
-//! `feature = "csvtab"` CSV Virtual Table.
+//! CSV Virtual Table.
//!
//! Port of [csv](http://www.sqlite.org/cgi/src/finfo?name=ext/misc/csv.c) C
-//! extension: https://www.sqlite.org/csv.html
+//! extension: `https://www.sqlite.org/csv.html`
//!
//! # Example
//!
@@ -35,7 +35,7 @@ use crate::vtab::{
};
use crate::{Connection, Error, Result};
-/// `feature = "csvtab"` Register the "csv" module.
+/// Register the "csv" module.
/// ```sql
/// CREATE VIRTUAL TABLE vtab USING csv(
/// filename=FILENAME -- Name of file containing CSV content
@@ -48,12 +48,12 @@ use crate::{Connection, Error, Result};
/// ```
pub fn load_module(conn: &Connection) -> Result<()> {
let aux: Option<()> = None;
- conn.create_module("csv", read_only_module::<CSVTab>(), aux)
+ conn.create_module("csv", read_only_module::<CsvTab>(), aux)
}
/// An instance of the CSV virtual table
#[repr(C)]
-struct CSVTab {
+struct CsvTab {
/// Base class. Must be first
base: ffi::sqlite3_vtab,
/// Name of the CSV file
@@ -65,7 +65,7 @@ struct CSVTab {
offset_first_row: csv::Position,
}
-impl CSVTab {
+impl CsvTab {
fn reader(&self) -> Result<csv::Reader<File>, csv::Error> {
csv::ReaderBuilder::new()
.has_headers(self.has_headers)
@@ -96,20 +96,20 @@ impl CSVTab {
}
}
-unsafe impl<'vtab> VTab<'vtab> for CSVTab {
+unsafe impl<'vtab> VTab<'vtab> for CsvTab {
type Aux = ();
- type Cursor = CSVTabCursor<'vtab>;
+ type Cursor = CsvTabCursor<'vtab>;
fn connect(
_: &mut VTabConnection,
_aux: Option<&()>,
args: &[&[u8]],
- ) -> Result<(String, CSVTab)> {
+ ) -> Result<(String, CsvTab)> {
if args.len() < 4 {
return Err(Error::ModuleError("no CSV file specified".to_owned()));
}
- let mut vtab = CSVTab {
+ let mut vtab = CsvTab {
base: ffi::sqlite3_vtab::default(),
filename: "".to_owned(),
has_headers: false,
@@ -122,7 +122,7 @@ unsafe impl<'vtab> VTab<'vtab> for CSVTab {
let args = &args[3..];
for c_slice in args {
- let (param, value) = CSVTab::parameter(c_slice)?;
+ let (param, value) = CsvTab::parameter(c_slice)?;
match param {
"filename" => {
if !Path::new(value).exists() {
@@ -166,7 +166,7 @@ unsafe impl<'vtab> VTab<'vtab> for CSVTab {
}
}
"delimiter" => {
- if let Some(b) = CSVTab::parse_byte(value) {
+ if let Some(b) = CsvTab::parse_byte(value) {
vtab.delimiter = b;
} else {
return Err(Error::ModuleError(format!(
@@ -176,7 +176,7 @@ unsafe impl<'vtab> VTab<'vtab> for CSVTab {
}
}
"quote" => {
- if let Some(b) = CSVTab::parse_byte(value) {
+ if let Some(b) = CsvTab::parse_byte(value) {
if b == b'0' {
vtab.quote = 0;
} else {
@@ -212,7 +212,7 @@ unsafe impl<'vtab> VTab<'vtab> for CSVTab {
if n_col.is_none() && schema.is_none() {
cols = headers
.into_iter()
- .map(|header| escape_double_quote(&header).into_owned())
+ .map(|header| escape_double_quote(header).into_owned())
.collect();
}
}
@@ -259,16 +259,16 @@ unsafe impl<'vtab> VTab<'vtab> for CSVTab {
Ok(())
}
- fn open(&self) -> Result<CSVTabCursor<'_>> {
- Ok(CSVTabCursor::new(self.reader()?))
+ fn open(&self) -> Result<CsvTabCursor<'_>> {
+ Ok(CsvTabCursor::new(self.reader()?))
}
}
-impl CreateVTab<'_> for CSVTab {}
+impl CreateVTab<'_> for CsvTab {}
/// A cursor for the CSV virtual table
#[repr(C)]
-struct CSVTabCursor<'vtab> {
+struct CsvTabCursor<'vtab> {
/// Base class. Must be first
base: ffi::sqlite3_vtab_cursor,
/// The CSV reader object
@@ -278,12 +278,12 @@ struct CSVTabCursor<'vtab> {
/// Values of the current row
cols: csv::StringRecord,
eof: bool,
- phantom: PhantomData<&'vtab CSVTab>,
+ phantom: PhantomData<&'vtab CsvTab>,
}
-impl CSVTabCursor<'_> {
- fn new<'vtab>(reader: csv::Reader<File>) -> CSVTabCursor<'vtab> {
- CSVTabCursor {
+impl CsvTabCursor<'_> {
+ fn new<'vtab>(reader: csv::Reader<File>) -> CsvTabCursor<'vtab> {
+ CsvTabCursor {
base: ffi::sqlite3_vtab_cursor::default(),
reader,
row_number: 0,
@@ -294,12 +294,12 @@ impl CSVTabCursor<'_> {
}
/// Accessor to the associated virtual table.
- fn vtab(&self) -> &CSVTab {
- unsafe { &*(self.base.pVtab as *const CSVTab) }
+ fn vtab(&self) -> &CsvTab {
+ unsafe { &*(self.base.pVtab as *const CsvTab) }
}
}
-unsafe impl VTabCursor for CSVTabCursor<'_> {
+unsafe impl VTabCursor for CsvTabCursor<'_> {
// Only a full table scan is supported. So `filter` simply rewinds to
// the beginning.
fn filter(
@@ -354,6 +354,7 @@ unsafe impl VTabCursor for CSVTabCursor<'_> {
}
impl From<csv::Error> for Error {
+ #[cold]
fn from(err: csv::Error) -> Error {
Error::ModuleError(err.to_string())
}
@@ -362,53 +363,45 @@ impl From<csv::Error> for Error {
#[cfg(test)]
mod test {
use crate::vtab::csvtab;
- use crate::{Connection, Result, NO_PARAMS};
+ use crate::{Connection, Result};
use fallible_iterator::FallibleIterator;
#[test]
- fn test_csv_module() {
- let db = Connection::open_in_memory().unwrap();
- csvtab::load_module(&db).unwrap();
- db.execute_batch("CREATE VIRTUAL TABLE vtab USING csv(filename='test.csv', header=yes)")
- .unwrap();
+ fn test_csv_module() -> Result<()> {
+ let db = Connection::open_in_memory()?;
+ csvtab::load_module(&db)?;
+ db.execute_batch("CREATE VIRTUAL TABLE vtab USING csv(filename='test.csv', header=yes)")?;
{
- let mut s = db.prepare("SELECT rowid, * FROM vtab").unwrap();
+ let mut s = db.prepare("SELECT rowid, * FROM vtab")?;
{
let headers = s.column_names();
assert_eq!(vec!["rowid", "colA", "colB", "colC"], headers);
}
- let ids: Result<Vec<i32>> = s
- .query(NO_PARAMS)
- .unwrap()
- .map(|row| row.get::<_, i32>(0))
- .collect();
- let sum = ids.unwrap().iter().sum::<i32>();
+ let ids: Result<Vec<i32>> = s.query([])?.map(|row| row.get::<_, i32>(0)).collect();
+ let sum = ids?.iter().sum::<i32>();
assert_eq!(sum, 15);
}
- db.execute_batch("DROP TABLE vtab").unwrap();
+ db.execute_batch("DROP TABLE vtab")
}
#[test]
- fn test_csv_cursor() {
- let db = Connection::open_in_memory().unwrap();
- csvtab::load_module(&db).unwrap();
- db.execute_batch("CREATE VIRTUAL TABLE vtab USING csv(filename='test.csv', header=yes)")
- .unwrap();
+ fn test_csv_cursor() -> Result<()> {
+ let db = Connection::open_in_memory()?;
+ csvtab::load_module(&db)?;
+ db.execute_batch("CREATE VIRTUAL TABLE vtab USING csv(filename='test.csv', header=yes)")?;
{
- let mut s = db
- .prepare(
- "SELECT v1.rowid, v1.* FROM vtab v1 NATURAL JOIN vtab v2 WHERE \
+ let mut s = db.prepare(
+ "SELECT v1.rowid, v1.* FROM vtab v1 NATURAL JOIN vtab v2 WHERE \
v1.rowid < v2.rowid",
- )
- .unwrap();
+ )?;
- let mut rows = s.query(NO_PARAMS).unwrap();
- let row = rows.next().unwrap().unwrap();
+ let mut rows = s.query([])?;
+ let row = rows.next()?.unwrap();
assert_eq!(row.get_unwrap::<_, i32>(0), 2);
}
- db.execute_batch("DROP TABLE vtab").unwrap();
+ db.execute_batch("DROP TABLE vtab")
}
}