sqlx_core_oldapi/odbc/
row.rs1use crate::column::ColumnIndex;
2use crate::database::HasValueRef;
3use crate::error::Error;
4use crate::odbc::{Odbc, OdbcColumn, OdbcValueRef};
5use crate::row::Row;
6use std::sync::Arc;
7
8#[derive(Debug, Clone)]
9pub struct OdbcBatch {
10 pub(crate) columns: Arc<[OdbcColumn]>,
11 pub(crate) column_data: Vec<Arc<crate::odbc::ColumnData>>,
12}
13
14#[derive(Debug, Clone)]
15pub struct OdbcRow {
16 pub(crate) row_index: usize,
17 pub(crate) batch: Arc<OdbcBatch>,
18}
19
20impl Row for OdbcRow {
21 type Database = Odbc;
22
23 fn columns(&self) -> &[OdbcColumn] {
24 &self.batch.columns
25 }
26
27 fn try_get_raw<I>(
28 &self,
29 index: I,
30 ) -> Result<<Self::Database as HasValueRef<'_>>::ValueRef, Error>
31 where
32 I: ColumnIndex<Self>,
33 {
34 let column_index = index.index(self)?;
35 Ok(OdbcValueRef::new(&self.batch, self.row_index, column_index))
36 }
37}
38
39impl ColumnIndex<OdbcRow> for &str {
40 fn index(&self, row: &OdbcRow) -> Result<usize, Error> {
41 if let Some(pos) = row.batch.columns.iter().position(|col| col.name == *self) {
43 return Ok(pos);
44 }
45
46 row.batch
48 .columns
49 .iter()
50 .position(|col| col.name.eq_ignore_ascii_case(self))
51 .ok_or_else(|| Error::ColumnNotFound((*self).into()))
52 }
53}
54
55mod private {
56 use super::OdbcRow;
57 use crate::row::private_row::Sealed;
58 impl Sealed for OdbcRow {}
59}
60
61#[cfg(feature = "any")]
62impl From<OdbcRow> for crate::any::AnyRow {
63 fn from(row: OdbcRow) -> Self {
64 let columns = row
65 .batch
66 .columns
67 .iter()
68 .map(|col| crate::any::AnyColumn {
69 kind: crate::any::column::AnyColumnKind::Odbc(col.clone()),
70 type_info: crate::any::AnyTypeInfo::from(col.type_info.clone()),
71 })
72 .collect();
73
74 crate::any::AnyRow {
75 kind: crate::any::row::AnyRowKind::Odbc(row),
76 columns,
77 }
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use crate::odbc::{ColumnData, OdbcColumn, OdbcTypeInfo, OdbcValueVec};
85 use crate::type_info::TypeInfo;
86 use crate::value::ValueRef;
87 use odbc_api::DataType;
88 use std::sync::Arc;
89
90 fn create_test_row() -> OdbcRow {
91 let columns = Arc::new([
92 OdbcColumn {
93 name: "lowercase_col".to_string(),
94 type_info: OdbcTypeInfo::new(DataType::Integer),
95 ordinal: 0,
96 },
97 OdbcColumn {
98 name: "UPPERCASE_COL".to_string(),
99 type_info: OdbcTypeInfo::new(DataType::Varchar { length: None }),
100 ordinal: 1,
101 },
102 OdbcColumn {
103 name: "MixedCase_Col".to_string(),
104 type_info: OdbcTypeInfo::new(DataType::Double),
105 ordinal: 2,
106 },
107 ]);
108
109 let column_data = vec![
110 Arc::new(ColumnData {
111 values: OdbcValueVec::BigInt(vec![42]),
112 type_info: OdbcTypeInfo::new(DataType::Integer),
113 nulls: vec![false],
114 }),
115 Arc::new(ColumnData {
116 values: OdbcValueVec::Text(vec!["test".to_string()]),
117 type_info: OdbcTypeInfo::new(DataType::Varchar { length: None }),
118 nulls: vec![false],
119 }),
120 Arc::new(ColumnData {
121 values: OdbcValueVec::Double(vec![std::f64::consts::PI]),
122 type_info: OdbcTypeInfo::new(DataType::Double),
123 nulls: vec![false],
124 }),
125 ];
126
127 OdbcRow {
128 row_index: 0,
129 batch: Arc::new(OdbcBatch {
130 columns,
131 column_data,
132 }),
133 }
134 }
135
136 #[test]
137 fn test_exact_column_match() {
138 let row = create_test_row();
139
140 assert_eq!("lowercase_col".index(&row).unwrap(), 0);
142 assert_eq!("UPPERCASE_COL".index(&row).unwrap(), 1);
143 assert_eq!("MixedCase_Col".index(&row).unwrap(), 2);
144 }
145
146 #[test]
147 fn test_case_insensitive_column_match() {
148 let row = create_test_row();
149
150 assert_eq!("LOWERCASE_COL".index(&row).unwrap(), 0);
152 assert_eq!("lowercase_col".index(&row).unwrap(), 0);
153 assert_eq!("uppercase_col".index(&row).unwrap(), 1);
154 assert_eq!("UPPERCASE_COL".index(&row).unwrap(), 1);
155 assert_eq!("mixedcase_col".index(&row).unwrap(), 2);
156 assert_eq!("MIXEDCASE_COL".index(&row).unwrap(), 2);
157 assert_eq!("MixedCase_Col".index(&row).unwrap(), 2);
158 }
159
160 #[test]
161 fn test_column_not_found() {
162 let row = create_test_row();
163
164 let result = "nonexistent_column".index(&row);
165 assert!(result.is_err());
166 if let Err(Error::ColumnNotFound(name)) = result {
167 assert_eq!(name, "nonexistent_column");
168 } else {
169 panic!("Expected ColumnNotFound error");
170 }
171 }
172
173 #[test]
174 fn test_try_get_raw() {
175 let row = create_test_row();
176
177 let value = row.try_get_raw("lowercase_col").unwrap();
179 assert!(!value.is_null());
180 assert_eq!(value.type_info().name(), "INTEGER");
181
182 let value = row.try_get_raw("LOWERCASE_COL").unwrap();
184 assert!(!value.is_null());
185 assert_eq!(value.type_info().name(), "INTEGER");
186
187 let value = row.try_get_raw("uppercase_col").unwrap();
189 assert!(!value.is_null());
190 assert_eq!(value.type_info().name(), "VARCHAR");
191 }
192
193 #[test]
194 fn test_columns_method() {
195 let row = create_test_row();
196 let columns = row.columns();
197
198 assert_eq!(columns.len(), 3);
199 assert_eq!(columns[0].name, "lowercase_col");
200 assert_eq!(columns[1].name, "UPPERCASE_COL");
201 assert_eq!(columns[2].name, "MixedCase_Col");
202 }
203}