1 use std::str; 2 3 use crate::{Error, Result, Row, Rows, Statement}; 4 5 /// Information about a column of a SQLite query. 6 #[derive(Debug)] 7 pub struct Column<'stmt> { 8 name: &'stmt str, 9 decl_type: Option<&'stmt str>, 10 } 11 12 impl Column<'_> { 13 /// Returns the name of the column. name(&self) -> &str14 pub fn name(&self) -> &str { 15 self.name 16 } 17 18 /// Returns the type of the column (`None` for expression). decl_type(&self) -> Option<&str>19 pub fn decl_type(&self) -> Option<&str> { 20 self.decl_type 21 } 22 } 23 24 impl Statement<'_> { 25 /// Get all the column names in the result set of the prepared statement. column_names(&self) -> Vec<&str>26 pub fn column_names(&self) -> Vec<&str> { 27 let n = self.column_count(); 28 let mut cols = Vec::with_capacity(n as usize); 29 for i in 0..n { 30 let s = self.column_name_unwrap(i); 31 cols.push(s); 32 } 33 cols 34 } 35 36 /// Return the number of columns in the result set returned by the prepared 37 /// statement. column_count(&self) -> usize38 pub fn column_count(&self) -> usize { 39 self.stmt.column_count() 40 } 41 column_name_unwrap(&self, col: usize) -> &str42 pub(crate) fn column_name_unwrap(&self, col: usize) -> &str { 43 // Just panic if the bounds are wrong for now, we never call this 44 // without checking first. 45 self.column_name(col).expect("Column out of bounds") 46 } 47 48 /// Returns the name assigned to a particular column in the result set 49 /// returned by the prepared statement. 50 /// 51 /// ## Failure 52 /// 53 /// Returns an `Error::InvalidColumnIndex` if `idx` is outside the valid 54 /// column range for this row. 55 /// 56 /// Panics when column name is not valid UTF-8. column_name(&self, col: usize) -> Result<&str>57 pub fn column_name(&self, col: usize) -> Result<&str> { 58 self.stmt 59 .column_name(col) 60 .ok_or(Error::InvalidColumnIndex(col)) 61 .map(|slice| { 62 str::from_utf8(slice.to_bytes()).expect("Invalid UTF-8 sequence in column name") 63 }) 64 } 65 66 /// Returns the column index in the result set for a given column name. 67 /// 68 /// If there is no AS clause then the name of the column is unspecified and 69 /// may change from one release of SQLite to the next. 70 /// 71 /// # Failure 72 /// 73 /// Will return an `Error::InvalidColumnName` when there is no column with 74 /// the specified `name`. column_index(&self, name: &str) -> Result<usize>75 pub fn column_index(&self, name: &str) -> Result<usize> { 76 let bytes = name.as_bytes(); 77 let n = self.column_count(); 78 for i in 0..n { 79 // Note: `column_name` is only fallible if `i` is out of bounds, 80 // which we've already checked. 81 if bytes.eq_ignore_ascii_case(self.stmt.column_name(i).unwrap().to_bytes()) { 82 return Ok(i); 83 } 84 } 85 Err(Error::InvalidColumnName(String::from(name))) 86 } 87 88 /// Returns a slice describing the columns of the result of the query. columns(&self) -> Vec<Column>89 pub fn columns(&self) -> Vec<Column> { 90 let n = self.column_count(); 91 let mut cols = Vec::with_capacity(n as usize); 92 for i in 0..n { 93 let name = self.column_name_unwrap(i); 94 let slice = self.stmt.column_decltype(i); 95 let decl_type = slice.map(|s| { 96 str::from_utf8(s.to_bytes()).expect("Invalid UTF-8 sequence in column declaration") 97 }); 98 cols.push(Column { name, decl_type }); 99 } 100 cols 101 } 102 } 103 104 impl<'stmt> Rows<'stmt> { 105 /// Get all the column names. column_names(&self) -> Option<Vec<&str>>106 pub fn column_names(&self) -> Option<Vec<&str>> { 107 self.stmt.map(Statement::column_names) 108 } 109 110 /// Return the number of columns. column_count(&self) -> Option<usize>111 pub fn column_count(&self) -> Option<usize> { 112 self.stmt.map(Statement::column_count) 113 } 114 115 /// Return the name of the column. column_name(&self, col: usize) -> Option<Result<&str>>116 pub fn column_name(&self, col: usize) -> Option<Result<&str>> { 117 self.stmt.map(|stmt| stmt.column_name(col)) 118 } 119 120 /// Return the index of the column. column_index(&self, name: &str) -> Option<Result<usize>>121 pub fn column_index(&self, name: &str) -> Option<Result<usize>> { 122 self.stmt.map(|stmt| stmt.column_index(name)) 123 } 124 125 /// Returns a slice describing the columns of the Rows. columns(&self) -> Option<Vec<Column>>126 pub fn columns(&self) -> Option<Vec<Column>> { 127 self.stmt.map(Statement::columns) 128 } 129 } 130 131 impl<'stmt> Row<'stmt> { 132 /// Get all the column names of the Row. column_names(&self) -> Vec<&str>133 pub fn column_names(&self) -> Vec<&str> { 134 self.stmt.column_names() 135 } 136 137 /// Return the number of columns in the current row. column_count(&self) -> usize138 pub fn column_count(&self) -> usize { 139 self.stmt.column_count() 140 } 141 142 /// Return the name of the column. column_name(&self, col: usize) -> Result<&str>143 pub fn column_name(&self, col: usize) -> Result<&str> { 144 self.stmt.column_name(col) 145 } 146 147 /// Return the index of the column. column_index(&self, name: &str) -> Result<usize>148 pub fn column_index(&self, name: &str) -> Result<usize> { 149 self.stmt.column_index(name) 150 } 151 152 /// Returns a slice describing the columns of the Row. columns(&self) -> Vec<Column>153 pub fn columns(&self) -> Vec<Column> { 154 self.stmt.columns() 155 } 156 } 157 158 #[cfg(test)] 159 mod test { 160 use super::Column; 161 use crate::Connection; 162 163 #[test] test_columns()164 fn test_columns() { 165 let db = Connection::open_in_memory().unwrap(); 166 let query = db.prepare("SELECT * FROM sqlite_master").unwrap(); 167 let columns = query.columns(); 168 let column_names: Vec<&str> = columns.iter().map(Column::name).collect(); 169 assert_eq!( 170 column_names.as_slice(), 171 &["type", "name", "tbl_name", "rootpage", "sql"] 172 ); 173 let column_types: Vec<Option<&str>> = columns.iter().map(Column::decl_type).collect(); 174 assert_eq!( 175 &column_types[..3], 176 &[Some("text"), Some("text"), Some("text"),] 177 ); 178 } 179 180 #[test] test_column_name_in_error()181 fn test_column_name_in_error() { 182 use crate::{types::Type, Error}; 183 let db = Connection::open_in_memory().unwrap(); 184 db.execute_batch( 185 "BEGIN; 186 CREATE TABLE foo(x INTEGER, y TEXT); 187 INSERT INTO foo VALUES(4, NULL); 188 END;", 189 ) 190 .unwrap(); 191 let mut stmt = db.prepare("SELECT x as renamed, y FROM foo").unwrap(); 192 let mut rows = stmt.query(crate::NO_PARAMS).unwrap(); 193 let row = rows.next().unwrap().unwrap(); 194 match row.get::<_, String>(0).unwrap_err() { 195 Error::InvalidColumnType(idx, name, ty) => { 196 assert_eq!(idx, 0); 197 assert_eq!(name, "renamed"); 198 assert_eq!(ty, Type::Integer); 199 } 200 e => { 201 panic!("Unexpected error type: {:?}", e); 202 } 203 } 204 match row.get::<_, String>("y").unwrap_err() { 205 Error::InvalidColumnType(idx, name, ty) => { 206 assert_eq!(idx, 1); 207 assert_eq!(name, "y"); 208 assert_eq!(ty, Type::Null); 209 } 210 e => { 211 panic!("Unexpected error type: {:?}", e); 212 } 213 } 214 } 215 } 216