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