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