mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-23 00:39:20 +08:00
don't truncate text columns that contain nul bytes
This commit is contained in:
parent
76cab84a00
commit
004c8f23d4
@ -1,6 +1,5 @@
|
|||||||
use std::ffi::CStr;
|
|
||||||
use std::iter::IntoIterator;
|
use std::iter::IntoIterator;
|
||||||
use std::os::raw::{c_char, c_int, c_void};
|
use std::os::raw::{c_int, c_void};
|
||||||
#[cfg(feature = "array")]
|
#[cfg(feature = "array")]
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::slice::from_raw_parts;
|
use std::slice::from_raw_parts;
|
||||||
@ -649,7 +648,8 @@ impl Statement<'_> {
|
|||||||
pub(crate) fn value_ref(&self, col: usize) -> ValueRef<'_> {
|
pub(crate) fn value_ref(&self, col: usize) -> ValueRef<'_> {
|
||||||
let raw = unsafe { self.stmt.ptr() };
|
let raw = unsafe { self.stmt.ptr() };
|
||||||
|
|
||||||
match self.stmt.column_type(col) {
|
let kind = self.stmt.column_type(col);
|
||||||
|
match kind {
|
||||||
ffi::SQLITE_NULL => ValueRef::Null,
|
ffi::SQLITE_NULL => ValueRef::Null,
|
||||||
ffi::SQLITE_INTEGER => {
|
ffi::SQLITE_INTEGER => {
|
||||||
ValueRef::Integer(unsafe { ffi::sqlite3_column_int64(raw, col as c_int) })
|
ValueRef::Integer(unsafe { ffi::sqlite3_column_int64(raw, col as c_int) })
|
||||||
@ -657,20 +657,7 @@ impl Statement<'_> {
|
|||||||
ffi::SQLITE_FLOAT => {
|
ffi::SQLITE_FLOAT => {
|
||||||
ValueRef::Real(unsafe { ffi::sqlite3_column_double(raw, col as c_int) })
|
ValueRef::Real(unsafe { ffi::sqlite3_column_double(raw, col as c_int) })
|
||||||
}
|
}
|
||||||
ffi::SQLITE_TEXT => {
|
ffi::SQLITE_TEXT | ffi::SQLITE_BLOB => {
|
||||||
let s = unsafe {
|
|
||||||
let text = ffi::sqlite3_column_text(raw, col as c_int);
|
|
||||||
assert!(
|
|
||||||
!text.is_null(),
|
|
||||||
"unexpected SQLITE_TEXT column type with NULL data"
|
|
||||||
);
|
|
||||||
CStr::from_ptr(text as *const c_char)
|
|
||||||
};
|
|
||||||
|
|
||||||
let s = s.to_bytes();
|
|
||||||
ValueRef::Text(s)
|
|
||||||
}
|
|
||||||
ffi::SQLITE_BLOB => {
|
|
||||||
let (blob, len) = unsafe {
|
let (blob, len) = unsafe {
|
||||||
(
|
(
|
||||||
ffi::sqlite3_column_blob(raw, col as c_int),
|
ffi::sqlite3_column_blob(raw, col as c_int),
|
||||||
@ -682,16 +669,23 @@ impl Statement<'_> {
|
|||||||
len >= 0,
|
len >= 0,
|
||||||
"unexpected negative return from sqlite3_column_bytes"
|
"unexpected negative return from sqlite3_column_bytes"
|
||||||
);
|
);
|
||||||
if len > 0 {
|
|
||||||
|
let bytes = if len > 0 {
|
||||||
assert!(
|
assert!(
|
||||||
!blob.is_null(),
|
!blob.is_null(),
|
||||||
"unexpected SQLITE_BLOB column type with NULL data"
|
"unexpected SQLITE_BLOB/TEXT column type with NULL data"
|
||||||
);
|
);
|
||||||
ValueRef::Blob(unsafe { from_raw_parts(blob as *const u8, len as usize) })
|
unsafe { from_raw_parts(blob as *const u8, len as usize) }
|
||||||
} else {
|
} else {
|
||||||
// The return value from sqlite3_column_blob() for a zero-length BLOB
|
// The return value from sqlite3_column_blob() for a zero-length BLOB
|
||||||
// is a NULL pointer.
|
// is a NULL pointer.
|
||||||
ValueRef::Blob(&[])
|
&[]
|
||||||
|
};
|
||||||
|
|
||||||
|
if kind == ffi::SQLITE_TEXT {
|
||||||
|
ValueRef::Text(bytes)
|
||||||
|
} else {
|
||||||
|
ValueRef::Blob(bytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!("sqlite3_column_type returned invalid value"),
|
_ => unreachable!("sqlite3_column_type returned invalid value"),
|
||||||
@ -740,7 +734,7 @@ pub enum StatementStatus {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::types::ToSql;
|
use crate::types::ToSql;
|
||||||
use crate::{Connection, Error, Result, NO_PARAMS};
|
use crate::{params, Connection, Error, Result, NO_PARAMS};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_execute_named() {
|
fn test_execute_named() {
|
||||||
@ -1089,4 +1083,21 @@ mod test {
|
|||||||
let stmt = conn.prepare(";").unwrap();
|
let stmt = conn.prepare(";").unwrap();
|
||||||
assert_eq!(0, stmt.column_count());
|
assert_eq!(0, stmt.column_count());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_nul_in_text_column() {
|
||||||
|
let db = Connection::open_in_memory().unwrap();
|
||||||
|
db.execute_batch("create table tbl(val text);").unwrap();
|
||||||
|
|
||||||
|
let expected = "a\x00b".to_string();
|
||||||
|
db.execute(
|
||||||
|
"insert into tbl values (cast(? as text))",
|
||||||
|
params![expected.as_bytes()],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let text: String = db
|
||||||
|
.query_row("select val from tbl", NO_PARAMS, |row| row.get(0))
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(text, expected);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user