From e3b21341cbdf95b5f108e64061ea1d8b86bde533 Mon Sep 17 00:00:00 2001 From: Simone Mosciatti Date: Sat, 23 Dec 2017 11:58:57 +0100 Subject: [PATCH] fix bug when different returns types are product for the same column, which is possible using the JSON1 module --- src/community_statement.rs | 17 +---------------- src/sqlite.rs | 29 ++++++++++++++++++++++++----- test/correctness/test.py | 14 +++++++++++++- 3 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/community_statement.rs b/src/community_statement.rs index 639d245..a58cca8 100644 --- a/src/community_statement.rs +++ b/src/community_statement.rs @@ -6,8 +6,7 @@ use std::ffi::{CString, CStr}; use sqlite::ffi; use sqlite::StatementTrait; -use sqlite::{SQLite3Error, Cursor, EntityType, RawConnection, - SQLiteOK}; +use sqlite::{SQLite3Error, Cursor, RawConnection, SQLiteOK}; use sqlite::generate_sqlite3_error; #[cfg(feature = "pro")] @@ -163,23 +162,9 @@ impl<'a> StatementTrait<'a> for Statement<'a> { unsafe { ffi::sqlite3_column_count(self.stmt) } as i32; - let mut types: Vec = Vec::new(); - for i in 0..n_columns { - types.push(match unsafe { - ffi::sqlite3_column_type(self.stmt, i) - } { - ffi::SQLITE_INTEGER => EntityType::Integer, - ffi::SQLITE_FLOAT => EntityType::Float, - ffi::SQLITE_TEXT => EntityType::Text, - ffi::SQLITE_BLOB => EntityType::Blob, - ffi::SQLITE_NULL => EntityType::Null, - _ => EntityType::Null, - }) - } Ok(Cursor::RowsCursor { stmt: self, num_columns: n_columns, - types: types, previous_status: ffi::SQLITE_ROW, to_replicate: self.to_replicate(), modified_rows: 0, diff --git a/src/sqlite.rs b/src/sqlite.rs index d0bae7b..a66dbc7 100644 --- a/src/sqlite.rs +++ b/src/sqlite.rs @@ -180,7 +180,6 @@ pub enum Cursor<'a> { }, RowsCursor { num_columns: i32, - types: Vec, previous_status: i32, stmt: &'a Statement<'a>, modified_rows: i32, @@ -221,6 +220,20 @@ impl<'a> FromIterator> for Cursor<'a> { } } +fn get_entity_type(stmt: *mut ffi::sqlite3_stmt, + i: i32) + -> EntityType { + let entity_type = unsafe { ffi::sqlite3_column_type(stmt, i) }; + match entity_type { + ffi::SQLITE_INTEGER => EntityType::Integer, + ffi::SQLITE_FLOAT => EntityType::Float, + ffi::SQLITE_TEXT => EntityType::Text, + ffi::SQLITE_BLOB => EntityType::Blob, + ffi::SQLITE_NULL => EntityType::Null, + _ => EntityType::Null, + + } +} impl<'a> Iterator for Cursor<'a> { type Item = Row; @@ -243,7 +256,6 @@ impl<'a> Iterator for Cursor<'a> { Cursor::RowsCursor { ref stmt, num_columns, - ref types, ref mut previous_status, .. } => { @@ -251,34 +263,41 @@ impl<'a> Iterator for Cursor<'a> { ffi::SQLITE_ROW => { let mut result = vec![]; for i in 0..num_columns { - let entity_value = match types[i as - usize] { + let entity_value = match get_entity_type(stmt.get_raw_stmt(), i) { EntityType::Integer => { let value = unsafe { ffi::sqlite3_column_int(stmt.get_raw_stmt(), i) }; + debug!("Got integer: {:?}", + value); Entity::Integer { int: value } } EntityType::Float => { let value = unsafe { ffi::sqlite3_column_double(stmt.get_raw_stmt(), i) }; + debug!("Got float: {:?}", value); Entity::Float { float: value } } EntityType::Text => { let value = unsafe { CStr::from_ptr(ffi::sqlite3_column_text(stmt.get_raw_stmt(), i) as *const i8).to_string_lossy().into_owned() }; + debug!("Got text: {:?}", value); Entity::Text { text: value } } EntityType::Blob => { let value = unsafe { CStr::from_ptr(ffi::sqlite3_column_blob(stmt.get_raw_stmt(), i) as *const i8).to_string_lossy().into_owned() }; + debug!("Got blob: {:?}", value); Entity::Blob { blob: value } } - EntityType::Null => Entity::Null {}, + EntityType::Null => { + debug!("Got null"); + Entity::Null {} + } }; result.push(entity_value); } diff --git a/test/correctness/test.py b/test/correctness/test.py index 442d629..e421fc3 100644 --- a/test/correctness/test.py +++ b/test/correctness/test.py @@ -216,7 +216,19 @@ def test_multi_insert_same_statement(self): COMMIT;""") self.assertEquals(done, ["DONE", 6L]) - +class TestJSON(TestRediSQLWithExec): + def test_multiple_insert_on_different_types(self): + with DB(self.client, "H"): + with Table(self.client, "j1", "(A text, B int)", key = "H"): + done = self.exec_naked("REDISQL.EXEC", "H", """BEGIN; + INSERT INTO j1 VALUES ('{\"foo\" : \"bar\"}', 1); + INSERT INTO j1 VALUES ('{\"foo\" : 3}', 2); + INSERT INTO j1 VALUES ('{\"foo\" : [1, 2, 3]}', 3); + INSERT INTO j1 VALUES ('{\"foo\" : {\"baz\" : [1, 2, 3]}}', 4); + COMMIT;""") + self.assertEquals(done, ["DONE", 4L]) + result = self.exec_naked("REDISQL.EXEC", "H", "SELECT json_extract(A, '$.foo') FROM j1 ORDER BY B;") + self.assertEquals(result, [["bar"], [3], ["[1,2,3]"], ['{"baz":[1,2,3]}']]) class TestStatements(TestRediSQLWithExec):