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(super) 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. 89 #[cfg(feature = "column_decltype")] columns(&self) -> Vec<Column>90 pub fn columns(&self) -> Vec<Column> { 91 let n = self.column_count(); 92 let mut cols = Vec::with_capacity(n as usize); 93 for i in 0..n { 94 let name = self.column_name_unwrap(i); 95 let slice = self.stmt.column_decltype(i); 96 let decl_type = slice.map(|s| { 97 str::from_utf8(s.to_bytes()).expect("Invalid UTF-8 sequence in column declaration") 98 }); 99 cols.push(Column { name, decl_type }); 100 } 101 cols 102 } 103 } 104 105 impl<'stmt> Rows<'stmt> { 106 /// Get all the column names. column_names(&self) -> Option<Vec<&str>>107 pub fn column_names(&self) -> Option<Vec<&str>> { 108 self.stmt.map(Statement::column_names) 109 } 110 111 /// Return the number of columns. column_count(&self) -> Option<usize>112 pub fn column_count(&self) -> Option<usize> { 113 self.stmt.map(Statement::column_count) 114 } 115 116 /// Return the name of the column. column_name(&self, col: usize) -> Option<Result<&str>>117 pub fn column_name(&self, col: usize) -> Option<Result<&str>> { 118 self.stmt.map(|stmt| stmt.column_name(col)) 119 } 120 121 /// Return the index of the column. column_index(&self, name: &str) -> Option<Result<usize>>122 pub fn column_index(&self, name: &str) -> Option<Result<usize>> { 123 self.stmt.map(|stmt| stmt.column_index(name)) 124 } 125 126 /// Returns a slice describing the columns of the Rows. 127 #[cfg(feature = "column_decltype")] columns(&self) -> Option<Vec<Column>>128 pub fn columns(&self) -> Option<Vec<Column>> { 129 self.stmt.map(Statement::columns) 130 } 131 } 132 133 impl<'stmt> Row<'stmt> { 134 /// Get all the column names of the Row. column_names(&self) -> Vec<&str>135 pub fn column_names(&self) -> Vec<&str> { 136 self.stmt.column_names() 137 } 138 139 /// Return the number of columns in the current row. column_count(&self) -> usize140 pub fn column_count(&self) -> usize { 141 self.stmt.column_count() 142 } 143 144 /// Return the name of the column. column_name(&self, col: usize) -> Result<&str>145 pub fn column_name(&self, col: usize) -> Result<&str> { 146 self.stmt.column_name(col) 147 } 148 149 /// Return the index of the column. column_index(&self, name: &str) -> Result<usize>150 pub fn column_index(&self, name: &str) -> Result<usize> { 151 self.stmt.column_index(name) 152 } 153 154 /// Returns a slice describing the columns of the Row. 155 #[cfg(feature = "column_decltype")] columns(&self) -> Vec<Column>156 pub fn columns(&self) -> Vec<Column> { 157 self.stmt.columns() 158 } 159 } 160 161 #[cfg(test)] 162 mod test { 163 use crate::Connection; 164 165 #[test] 166 #[cfg(feature = "column_decltype")] test_columns()167 fn test_columns() { 168 use super::Column; 169 170 let db = Connection::open_in_memory().unwrap(); 171 let query = db.prepare("SELECT * FROM sqlite_master").unwrap(); 172 let columns = query.columns(); 173 let column_names: Vec<&str> = columns.iter().map(Column::name).collect(); 174 assert_eq!( 175 column_names.as_slice(), 176 &["type", "name", "tbl_name", "rootpage", "sql"] 177 ); 178 let column_types: Vec<Option<&str>> = columns.iter().map(Column::decl_type).collect(); 179 assert_eq!( 180 &column_types[..3], 181 &[Some("text"), Some("text"), Some("text"),] 182 ); 183 } 184 185 #[test] test_column_name_in_error()186 fn test_column_name_in_error() { 187 use crate::{types::Type, Error}; 188 let db = Connection::open_in_memory().unwrap(); 189 db.execute_batch( 190 "BEGIN; 191 CREATE TABLE foo(x INTEGER, y TEXT); 192 INSERT INTO foo VALUES(4, NULL); 193 END;", 194 ) 195 .unwrap(); 196 let mut stmt = db.prepare("SELECT x as renamed, y FROM foo").unwrap(); 197 let mut rows = stmt.query(crate::NO_PARAMS).unwrap(); 198 let row = rows.next().unwrap().unwrap(); 199 match row.get::<_, String>(0).unwrap_err() { 200 Error::InvalidColumnType(idx, name, ty) => { 201 assert_eq!(idx, 0); 202 assert_eq!(name, "renamed"); 203 assert_eq!(ty, Type::Integer); 204 } 205 e => { 206 panic!("Unexpected error type: {:?}", e); 207 } 208 } 209 match row.get::<_, String>("y").unwrap_err() { 210 Error::InvalidColumnType(idx, name, ty) => { 211 assert_eq!(idx, 1); 212 assert_eq!(name, "y"); 213 assert_eq!(ty, Type::Null); 214 } 215 e => { 216 panic!("Unexpected error type: {:?}", e); 217 } 218 } 219 } 220 } 221