connectorx/sources/sqlite/
mod.rs1mod errors;
4mod typesystem;
5
6pub use self::errors::SQLiteSourceError;
7use crate::{
8 data_order::DataOrder,
9 errors::ConnectorXError,
10 sources::{PartitionParser, Produce, Source, SourcePartition},
11 sql::{count_query, limit1_query, CXQuery},
12 utils::DummyBox,
13};
14use anyhow::anyhow;
15use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
16use fallible_streaming_iterator::FallibleStreamingIterator;
17use fehler::{throw, throws};
18use log::debug;
19use owning_ref::OwningHandle;
20use r2d2::{Pool, PooledConnection};
21use r2d2_sqlite::SqliteConnectionManager;
22use rusqlite::{Row, Rows, Statement};
23use sqlparser::dialect::SQLiteDialect;
24use std::convert::TryFrom;
25pub use typesystem::SQLiteTypeSystem;
26use urlencoding::decode;
27
28pub struct SQLiteSource {
29 pool: Pool<SqliteConnectionManager>,
30 origin_query: Option<String>,
31 queries: Vec<CXQuery<String>>,
32 names: Vec<String>,
33 schema: Vec<SQLiteTypeSystem>,
34}
35
36impl SQLiteSource {
37 #[throws(SQLiteSourceError)]
38 pub fn new(conn: &str, nconn: usize) -> Self {
39 let decoded_conn = decode(conn)?.into_owned();
40 debug!("decoded conn: {}", decoded_conn);
41 let manager = SqliteConnectionManager::file(decoded_conn);
42 let pool = r2d2::Pool::builder()
43 .max_size(nconn as u32)
44 .build(manager)?;
45
46 Self {
47 pool,
48 origin_query: None,
49 queries: vec![],
50 names: vec![],
51 schema: vec![],
52 }
53 }
54}
55
56impl Source for SQLiteSource
57where
58 SQLiteSourcePartition: SourcePartition<TypeSystem = SQLiteTypeSystem>,
59{
60 const DATA_ORDERS: &'static [DataOrder] = &[DataOrder::RowMajor];
61 type Partition = SQLiteSourcePartition;
62 type TypeSystem = SQLiteTypeSystem;
63 type Error = SQLiteSourceError;
64
65 #[throws(SQLiteSourceError)]
66 fn set_data_order(&mut self, data_order: DataOrder) {
67 if !matches!(data_order, DataOrder::RowMajor) {
68 throw!(ConnectorXError::UnsupportedDataOrder(data_order));
69 }
70 }
71
72 fn set_queries<Q: ToString>(&mut self, queries: &[CXQuery<Q>]) {
73 self.queries = queries.iter().map(|q| q.map(Q::to_string)).collect();
74 }
75
76 fn set_origin_query(&mut self, query: Option<String>) {
77 self.origin_query = query;
78 }
79
80 #[throws(SQLiteSourceError)]
81 fn fetch_metadata(&mut self) {
82 assert!(!self.queries.is_empty());
83 let conn = self.pool.get()?;
84
85 let stmt = conn.prepare(self.queries[0].as_str())?;
89 let columns = stmt.columns();
90
91 let mut names: Vec<String> = Vec::with_capacity(columns.len());
92 let mut types: Vec<Option<SQLiteTypeSystem>> = Vec::with_capacity(columns.len());
93
94 for col in &columns {
95 names.push(col.name().to_string());
96 let decl_type = col.decl_type();
97 match SQLiteTypeSystem::try_from((decl_type, rusqlite::types::Type::Null)) {
98 Ok(t) => types.push(Some(t)),
99 Err(_) => types.push(None),
100 }
101 }
102
103 if !types.contains(&None) {
105 self.names = names;
106 self.schema = types.into_iter().map(|t| t.unwrap()).collect();
107 return;
108 }
109
110 drop(columns);
113 drop(stmt);
114
115 let mut num_empty = 0;
116 for (i, query) in self.queries.iter().enumerate() {
117 let l1query = limit1_query(query, &SQLiteDialect {})?;
118
119 let is_success = conn.query_row(l1query.as_str(), [], |row| {
120 for (j, col) in row.as_ref().columns().iter().enumerate() {
121 if types[j].is_none() {
122 let vr = row.get_ref(j)?;
123 if let Ok(t) = SQLiteTypeSystem::try_from((col.decl_type(), vr.data_type()))
124 {
125 types[j] = Some(t);
126 }
127 }
128 }
129 Ok(())
130 });
131
132 match is_success {
133 Ok(()) => {
134 if !types.contains(&None) {
135 self.names = names;
136 self.schema = types.into_iter().map(|t| t.unwrap()).collect();
137 return;
138 } else if i == self.queries.len() - 1 {
139 debug!(
140 "cannot get metadata for '{}' due to null value: {:?}",
141 query, types
142 );
143 throw!(SQLiteSourceError::InferTypeFromNull);
144 }
145 }
146 Err(e) => {
147 if let rusqlite::Error::QueryReturnedNoRows = e {
148 num_empty += 1;
149 }
150 if i == self.queries.len() - 1 && num_empty < self.queries.len() {
151 debug!("cannot get metadata for '{}': {}", query, e);
152 throw!(e)
153 }
154 }
155 }
156 }
157
158 self.names = names;
161 self.schema = types
162 .into_iter()
163 .map(|t| t.unwrap_or(SQLiteTypeSystem::Text(false)))
164 .collect();
165 }
166
167 #[throws(SQLiteSourceError)]
168 fn result_rows(&mut self) -> Option<usize> {
169 match &self.origin_query {
170 Some(q) => {
171 let cxq = CXQuery::Naked(q.clone());
172 let conn = self.pool.get()?;
173 let nrows =
174 conn.query_row(count_query(&cxq, &SQLiteDialect {})?.as_str(), [], |row| {
175 Ok(row.get::<_, i64>(0)? as usize)
176 })?;
177 Some(nrows)
178 }
179 None => None,
180 }
181 }
182
183 fn names(&self) -> Vec<String> {
184 self.names.clone()
185 }
186
187 fn schema(&self) -> Vec<Self::TypeSystem> {
188 self.schema.clone()
189 }
190
191 #[throws(SQLiteSourceError)]
192 fn partition(self) -> Vec<Self::Partition> {
193 let mut ret = vec![];
194 for query in self.queries {
195 let conn = self.pool.get()?;
196
197 ret.push(SQLiteSourcePartition::new(conn, &query, &self.schema));
198 }
199 ret
200 }
201}
202
203pub struct SQLiteSourcePartition {
204 conn: PooledConnection<SqliteConnectionManager>,
205 query: CXQuery<String>,
206 schema: Vec<SQLiteTypeSystem>,
207 nrows: usize,
208 ncols: usize,
209}
210
211impl SQLiteSourcePartition {
212 pub fn new(
213 conn: PooledConnection<SqliteConnectionManager>,
214 query: &CXQuery<String>,
215 schema: &[SQLiteTypeSystem],
216 ) -> Self {
217 Self {
218 conn,
219 query: query.clone(),
220 schema: schema.to_vec(),
221 nrows: 0,
222 ncols: schema.len(),
223 }
224 }
225}
226
227impl SourcePartition for SQLiteSourcePartition {
228 type TypeSystem = SQLiteTypeSystem;
229 type Parser<'a> = SQLiteSourcePartitionParser<'a>;
230 type Error = SQLiteSourceError;
231
232 #[throws(SQLiteSourceError)]
233 fn result_rows(&mut self) {
234 self.nrows = self.conn.query_row(
235 count_query(&self.query, &SQLiteDialect {})?.as_str(),
236 [],
237 |row| Ok(row.get::<_, i64>(0)? as usize),
238 )?;
239 }
240
241 #[throws(SQLiteSourceError)]
242 fn parser(&mut self) -> Self::Parser<'_> {
243 SQLiteSourcePartitionParser::new(&self.conn, self.query.as_str(), &self.schema)?
244 }
245
246 fn nrows(&self) -> usize {
247 self.nrows
248 }
249
250 fn ncols(&self) -> usize {
251 self.ncols
252 }
253}
254
255unsafe impl<'a> Send for SQLiteSourcePartitionParser<'a> {}
256
257pub struct SQLiteSourcePartitionParser<'a> {
258 rows: OwningHandle<Box<Statement<'a>>, DummyBox<Rows<'a>>>,
259 ncols: usize,
260 current_col: usize,
261 current_consumed: bool,
262 is_finished: bool,
263}
264
265impl<'a> SQLiteSourcePartitionParser<'a> {
266 #[throws(SQLiteSourceError)]
267 pub fn new(
268 conn: &'a PooledConnection<SqliteConnectionManager>,
269 query: &str,
270 schema: &[SQLiteTypeSystem],
271 ) -> Self {
272 let stmt: Statement<'a> = conn.prepare(query)?;
273
274 let rows: OwningHandle<Box<Statement<'a>>, DummyBox<Rows<'a>>> =
278 OwningHandle::new_with_fn(Box::new(stmt), |stmt: *const Statement<'a>| unsafe {
279 DummyBox((*(stmt as *mut Statement<'_>)).query([]).unwrap())
280 });
281 Self {
282 rows,
283 ncols: schema.len(),
284 current_col: 0,
285 current_consumed: true,
286 is_finished: false,
287 }
288 }
289
290 #[throws(SQLiteSourceError)]
291 fn next_loc(&mut self) -> (&Row<'_>, usize) {
292 self.current_consumed = true;
293 let row: &Row = (*self.rows)
294 .get()
295 .ok_or_else(|| anyhow!("Sqlite empty current row"))?;
296 let col = self.current_col;
297 self.current_col = (self.current_col + 1) % self.ncols;
298 (row, col)
299 }
300}
301
302impl<'a> PartitionParser<'a> for SQLiteSourcePartitionParser<'a> {
303 type TypeSystem = SQLiteTypeSystem;
304 type Error = SQLiteSourceError;
305
306 #[throws(SQLiteSourceError)]
307 fn fetch_next(&mut self) -> (usize, bool) {
308 assert!(self.current_col == 0);
309
310 if !self.current_consumed {
311 return (1, false);
312 } else if self.is_finished {
313 return (0, true);
314 }
315
316 match (*self.rows).next()? {
317 Some(_) => {
318 self.current_consumed = false;
319 (1, false)
320 }
321 None => {
322 self.is_finished = true;
323 (0, true)
324 }
325 }
326 }
327}
328
329macro_rules! impl_produce {
330 ($($t: ty,)+) => {
331 $(
332 impl<'r, 'a> Produce<'r, $t> for SQLiteSourcePartitionParser<'a> {
333 type Error = SQLiteSourceError;
334
335 #[throws(SQLiteSourceError)]
336 fn produce(&'r mut self) -> $t {
337 let (row, col) = self.next_loc()?;
338 let val = row.get(col)?;
339 val
340 }
341 }
342
343 impl<'r, 'a> Produce<'r, Option<$t>> for SQLiteSourcePartitionParser<'a> {
344 type Error = SQLiteSourceError;
345
346 #[throws(SQLiteSourceError)]
347 fn produce(&'r mut self) -> Option<$t> {
348 let (row, col) = self.next_loc()?;
349 let val = row.get(col)?;
350 val
351 }
352 }
353 )+
354 };
355}
356
357impl_produce!(
358 bool,
359 i64,
360 i32,
361 i16,
362 f64,
363 Box<str>,
364 NaiveDate,
365 NaiveTime,
366 NaiveDateTime,
367 Vec<u8>,
368);