1use std::str;
2
3use crate::{Error, Result, Row, Rows, Statement};
4
5#[derive(Debug)]
7pub struct Column<'stmt> {
8 name: &'stmt str,
9 decl_type: Option<&'stmt str>,
10}
11
12impl Column<'_> {
13 #[inline]
15 pub fn name(&self) -> &str {
16 self.name
17 }
18
19 #[inline]
21 pub fn decl_type(&self) -> Option<&str> {
22 self.decl_type
23 }
24}
25
26impl Statement<'_> {
27 pub fn column_names(&self) -> Vec<&str> {
29 let n = self.column_count();
30 let mut cols = Vec::with_capacity(n as usize);
31 for i in 0..n {
32 let s = self.column_name_unwrap(i);
33 cols.push(s);
34 }
35 cols
36 }
37
38 #[inline]
41 pub fn column_count(&self) -> usize {
42 self.stmt.column_count()
43 }
44
45 #[inline]
46 pub(super) fn column_name_unwrap(&self, col: usize) -> &str {
47 self.column_name(col).expect("Column out of bounds")
50 }
51
52 #[inline]
62 pub fn column_name(&self, col: usize) -> Result<&str> {
63 self.stmt
64 .column_name(col)
65 .ok_or(Error::InvalidColumnIndex(col))
66 .map(|slice| {
67 str::from_utf8(slice.to_bytes()).expect("Invalid UTF-8 sequence in column name")
68 })
69 }
70
71 #[inline]
81 pub fn column_index(&self, name: &str) -> Result<usize> {
82 let bytes = name.as_bytes();
83 let n = self.column_count();
84 for i in 0..n {
85 if bytes.eq_ignore_ascii_case(self.stmt.column_name(i).unwrap().to_bytes()) {
88 return Ok(i);
89 }
90 }
91 Err(Error::InvalidColumnName(String::from(name)))
92 }
93
94 #[cfg(feature = "column_decltype")]
96 pub fn columns(&self) -> Vec<Column> {
97 let n = self.column_count();
98 let mut cols = Vec::with_capacity(n as usize);
99 for i in 0..n {
100 let name = self.column_name_unwrap(i);
101 let slice = self.stmt.column_decltype(i);
102 let decl_type = slice.map(|s| {
103 str::from_utf8(s.to_bytes()).expect("Invalid UTF-8 sequence in column declaration")
104 });
105 cols.push(Column { name, decl_type });
106 }
107 cols
108 }
109}
110
111impl<'stmt> Rows<'stmt> {
112 #[inline]
114 pub fn column_names(&self) -> Option<Vec<&str>> {
115 self.stmt.map(Statement::column_names)
116 }
117
118 #[inline]
120 pub fn column_count(&self) -> Option<usize> {
121 self.stmt.map(Statement::column_count)
122 }
123
124 #[inline]
126 pub fn column_name(&self, col: usize) -> Option<Result<&str>> {
127 self.stmt.map(|stmt| stmt.column_name(col))
128 }
129
130 #[inline]
132 pub fn column_index(&self, name: &str) -> Option<Result<usize>> {
133 self.stmt.map(|stmt| stmt.column_index(name))
134 }
135
136 #[inline]
138 #[cfg(feature = "column_decltype")]
139 pub fn columns(&self) -> Option<Vec<Column>> {
140 self.stmt.map(Statement::columns)
141 }
142}
143
144impl<'stmt> Row<'stmt> {
145 #[inline]
147 pub fn column_names(&self) -> Vec<&str> {
148 self.stmt.column_names()
149 }
150
151 #[inline]
153 pub fn column_count(&self) -> usize {
154 self.stmt.column_count()
155 }
156
157 #[inline]
159 pub fn column_name(&self, col: usize) -> Result<&str> {
160 self.stmt.column_name(col)
161 }
162
163 #[inline]
165 pub fn column_index(&self, name: &str) -> Result<usize> {
166 self.stmt.column_index(name)
167 }
168
169 #[inline]
171 #[cfg(feature = "column_decltype")]
172 pub fn columns(&self) -> Vec<Column> {
173 self.stmt.columns()
174 }
175}
176
177#[cfg(test)]
178mod test {
179 use crate::{Connection, Result};
180
181 #[test]
182 #[cfg(feature = "column_decltype")]
183 fn test_columns() -> Result<()> {
184 use super::Column;
185
186 let db = Connection::open_in_memory()?;
187 let query = db.prepare("SELECT * FROM sqlite_master")?;
188 let columns = query.columns();
189 let column_names: Vec<&str> = columns.iter().map(Column::name).collect();
190 assert_eq!(
191 column_names.as_slice(),
192 &["type", "name", "tbl_name", "rootpage", "sql"]
193 );
194 let column_types: Vec<Option<&str>> = columns.iter().map(Column::decl_type).collect();
195 assert_eq!(
196 &column_types[..3],
197 &[Some("text"), Some("text"), Some("text"),]
198 );
199 Ok(())
200 }
201
202 #[test]
203 fn test_column_name_in_error() -> Result<()> {
204 use crate::{types::Type, Error};
205 let db = Connection::open_in_memory()?;
206 db.execute_batch(
207 "BEGIN;
208 CREATE TABLE foo(x INTEGER, y TEXT);
209 INSERT INTO foo VALUES(4, NULL);
210 END;",
211 )?;
212 let mut stmt = db.prepare("SELECT x as renamed, y FROM foo")?;
213 let mut rows = stmt.query([])?;
214 let row = rows.next()?.unwrap();
215 match row.get::<_, String>(0).unwrap_err() {
216 Error::InvalidColumnType(idx, name, ty) => {
217 assert_eq!(idx, 0);
218 assert_eq!(name, "renamed");
219 assert_eq!(ty, Type::Integer);
220 }
221 e => {
222 panic!("Unexpected error type: {:?}", e);
223 }
224 }
225 match row.get::<_, String>("y").unwrap_err() {
226 Error::InvalidColumnType(idx, name, ty) => {
227 assert_eq!(idx, 1);
228 assert_eq!(name, "y");
229 assert_eq!(ty, Type::Null);
230 }
231 e => {
232 panic!("Unexpected error type: {:?}", e);
233 }
234 }
235 Ok(())
236 }
237}