1 use super::{Type, Value}; 2 use crate::types::{FromSqlError, FromSqlResult}; 3 4 /// A non-owning [dynamic type value](http://sqlite.org/datatype3.html). Typically, the 5 /// memory backing this value is owned by SQLite. 6 /// 7 /// See [`Value`](Value) for an owning dynamic type value. 8 #[derive(Copy, Clone, Debug, PartialEq)] 9 pub enum ValueRef<'a> { 10 /// The value is a `NULL` value. 11 Null, 12 /// The value is a signed integer. 13 Integer(i64), 14 /// The value is a floating point number. 15 Real(f64), 16 /// The value is a text string. 17 Text(&'a [u8]), 18 /// The value is a blob of data 19 Blob(&'a [u8]), 20 } 21 22 impl ValueRef<'_> { 23 /// Returns SQLite fundamental datatype. 24 #[inline] 25 #[must_use] data_type(&self) -> Type26 pub fn data_type(&self) -> Type { 27 match *self { 28 ValueRef::Null => Type::Null, 29 ValueRef::Integer(_) => Type::Integer, 30 ValueRef::Real(_) => Type::Real, 31 ValueRef::Text(_) => Type::Text, 32 ValueRef::Blob(_) => Type::Blob, 33 } 34 } 35 } 36 37 impl<'a> ValueRef<'a> { 38 /// If `self` is case `Integer`, returns the integral value. Otherwise, 39 /// returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType). 40 #[inline] as_i64(&self) -> FromSqlResult<i64>41 pub fn as_i64(&self) -> FromSqlResult<i64> { 42 match *self { 43 ValueRef::Integer(i) => Ok(i), 44 _ => Err(FromSqlError::InvalidType), 45 } 46 } 47 48 /// If `self` is case `Null` returns None. 49 /// If `self` is case `Integer`, returns the integral value. 50 /// Otherwise, returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType). 51 #[inline] as_i64_or_null(&self) -> FromSqlResult<Option<i64>>52 pub fn as_i64_or_null(&self) -> FromSqlResult<Option<i64>> { 53 match *self { 54 ValueRef::Null => Ok(None), 55 ValueRef::Integer(i) => Ok(Some(i)), 56 _ => Err(FromSqlError::InvalidType), 57 } 58 } 59 60 /// If `self` is case `Real`, returns the floating point value. Otherwise, 61 /// returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType). 62 #[inline] as_f64(&self) -> FromSqlResult<f64>63 pub fn as_f64(&self) -> FromSqlResult<f64> { 64 match *self { 65 ValueRef::Real(f) => Ok(f), 66 _ => Err(FromSqlError::InvalidType), 67 } 68 } 69 70 /// If `self` is case `Null` returns None. 71 /// If `self` is case `Real`, returns the floating point value. 72 /// Otherwise, returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType). 73 #[inline] as_f64_or_null(&self) -> FromSqlResult<Option<f64>>74 pub fn as_f64_or_null(&self) -> FromSqlResult<Option<f64>> { 75 match *self { 76 ValueRef::Null => Ok(None), 77 ValueRef::Real(f) => Ok(Some(f)), 78 _ => Err(FromSqlError::InvalidType), 79 } 80 } 81 82 /// If `self` is case `Text`, returns the string value. Otherwise, returns 83 /// [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType). 84 #[inline] as_str(&self) -> FromSqlResult<&'a str>85 pub fn as_str(&self) -> FromSqlResult<&'a str> { 86 match *self { 87 ValueRef::Text(t) => { 88 std::str::from_utf8(t).map_err(|e| FromSqlError::Other(Box::new(e))) 89 } 90 _ => Err(FromSqlError::InvalidType), 91 } 92 } 93 94 /// If `self` is case `Null` returns None. 95 /// If `self` is case `Text`, returns the string value. 96 /// Otherwise, returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType). 97 #[inline] as_str_or_null(&self) -> FromSqlResult<Option<&'a str>>98 pub fn as_str_or_null(&self) -> FromSqlResult<Option<&'a str>> { 99 match *self { 100 ValueRef::Null => Ok(None), 101 ValueRef::Text(t) => std::str::from_utf8(t) 102 .map_err(|e| FromSqlError::Other(Box::new(e))) 103 .map(Some), 104 _ => Err(FromSqlError::InvalidType), 105 } 106 } 107 108 /// If `self` is case `Blob`, returns the byte slice. Otherwise, returns 109 /// [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType). 110 #[inline] as_blob(&self) -> FromSqlResult<&'a [u8]>111 pub fn as_blob(&self) -> FromSqlResult<&'a [u8]> { 112 match *self { 113 ValueRef::Blob(b) => Ok(b), 114 _ => Err(FromSqlError::InvalidType), 115 } 116 } 117 118 /// If `self` is case `Null` returns None. 119 /// If `self` is case `Blob`, returns the byte slice. 120 /// Otherwise, returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType). 121 #[inline] as_blob_or_null(&self) -> FromSqlResult<Option<&'a [u8]>>122 pub fn as_blob_or_null(&self) -> FromSqlResult<Option<&'a [u8]>> { 123 match *self { 124 ValueRef::Null => Ok(None), 125 ValueRef::Blob(b) => Ok(Some(b)), 126 _ => Err(FromSqlError::InvalidType), 127 } 128 } 129 130 /// Returns the byte slice that makes up this `ValueRef` if it's either 131 /// [`ValueRef::Blob`] or [`ValueRef::Text`]. 132 #[inline] as_bytes(&self) -> FromSqlResult<&'a [u8]>133 pub fn as_bytes(&self) -> FromSqlResult<&'a [u8]> { 134 match self { 135 ValueRef::Text(s) | ValueRef::Blob(s) => Ok(s), 136 _ => Err(FromSqlError::InvalidType), 137 } 138 } 139 140 /// If `self` is case `Null` returns None. 141 /// If `self` is [`ValueRef::Blob`] or [`ValueRef::Text`] returns the byte 142 /// slice that makes up this value 143 #[inline] as_bytes_or_null(&self) -> FromSqlResult<Option<&'a [u8]>>144 pub fn as_bytes_or_null(&self) -> FromSqlResult<Option<&'a [u8]>> { 145 match *self { 146 ValueRef::Null => Ok(None), 147 ValueRef::Text(s) | ValueRef::Blob(s) => Ok(Some(s)), 148 _ => Err(FromSqlError::InvalidType), 149 } 150 } 151 } 152 153 impl From<ValueRef<'_>> for Value { 154 #[inline] 155 #[track_caller] from(borrowed: ValueRef<'_>) -> Value156 fn from(borrowed: ValueRef<'_>) -> Value { 157 match borrowed { 158 ValueRef::Null => Value::Null, 159 ValueRef::Integer(i) => Value::Integer(i), 160 ValueRef::Real(r) => Value::Real(r), 161 ValueRef::Text(s) => { 162 let s = std::str::from_utf8(s).expect("invalid UTF-8"); 163 Value::Text(s.to_string()) 164 } 165 ValueRef::Blob(b) => Value::Blob(b.to_vec()), 166 } 167 } 168 } 169 170 impl<'a> From<&'a str> for ValueRef<'a> { 171 #[inline] from(s: &str) -> ValueRef<'_>172 fn from(s: &str) -> ValueRef<'_> { 173 ValueRef::Text(s.as_bytes()) 174 } 175 } 176 177 impl<'a> From<&'a [u8]> for ValueRef<'a> { 178 #[inline] from(s: &[u8]) -> ValueRef<'_>179 fn from(s: &[u8]) -> ValueRef<'_> { 180 ValueRef::Blob(s) 181 } 182 } 183 184 impl<'a> From<&'a Value> for ValueRef<'a> { 185 #[inline] from(value: &'a Value) -> ValueRef<'a>186 fn from(value: &'a Value) -> ValueRef<'a> { 187 match *value { 188 Value::Null => ValueRef::Null, 189 Value::Integer(i) => ValueRef::Integer(i), 190 Value::Real(r) => ValueRef::Real(r), 191 Value::Text(ref s) => ValueRef::Text(s.as_bytes()), 192 Value::Blob(ref b) => ValueRef::Blob(b), 193 } 194 } 195 } 196 197 impl<'a, T> From<Option<T>> for ValueRef<'a> 198 where 199 T: Into<ValueRef<'a>>, 200 { 201 #[inline] from(s: Option<T>) -> ValueRef<'a>202 fn from(s: Option<T>) -> ValueRef<'a> { 203 match s { 204 Some(x) => x.into(), 205 None => ValueRef::Null, 206 } 207 } 208 } 209 210 #[cfg(any( 211 feature = "functions", 212 feature = "session", 213 feature = "vtab", 214 feature = "preupdate_hook" 215 ))] 216 impl<'a> ValueRef<'a> { from_value(value: *mut crate::ffi::sqlite3_value) -> ValueRef<'a>217 pub(crate) unsafe fn from_value(value: *mut crate::ffi::sqlite3_value) -> ValueRef<'a> { 218 use crate::ffi; 219 use std::slice::from_raw_parts; 220 221 match ffi::sqlite3_value_type(value) { 222 ffi::SQLITE_NULL => ValueRef::Null, 223 ffi::SQLITE_INTEGER => ValueRef::Integer(ffi::sqlite3_value_int64(value)), 224 ffi::SQLITE_FLOAT => ValueRef::Real(ffi::sqlite3_value_double(value)), 225 ffi::SQLITE_TEXT => { 226 let text = ffi::sqlite3_value_text(value); 227 let len = ffi::sqlite3_value_bytes(value); 228 assert!( 229 !text.is_null(), 230 "unexpected SQLITE_TEXT value type with NULL data" 231 ); 232 let s = from_raw_parts(text.cast::<u8>(), len as usize); 233 ValueRef::Text(s) 234 } 235 ffi::SQLITE_BLOB => { 236 let (blob, len) = ( 237 ffi::sqlite3_value_blob(value), 238 ffi::sqlite3_value_bytes(value), 239 ); 240 241 assert!( 242 len >= 0, 243 "unexpected negative return from sqlite3_value_bytes" 244 ); 245 if len > 0 { 246 assert!( 247 !blob.is_null(), 248 "unexpected SQLITE_BLOB value type with NULL data" 249 ); 250 ValueRef::Blob(from_raw_parts(blob.cast::<u8>(), len as usize)) 251 } else { 252 // The return value from sqlite3_value_blob() for a zero-length BLOB 253 // is a NULL pointer. 254 ValueRef::Blob(&[]) 255 } 256 } 257 _ => unreachable!("sqlite3_value_type returned invalid value"), 258 } 259 } 260 261 // TODO sqlite3_value_nochange // 3.22.0 & VTab xUpdate 262 // TODO sqlite3_value_frombind // 3.28.0 263 } 264 265 #[cfg(test)] 266 mod test { 267 use super::ValueRef; 268 use crate::types::FromSqlResult; 269 270 #[test] as_i64() -> FromSqlResult<()>271 fn as_i64() -> FromSqlResult<()> { 272 assert!(ValueRef::Real(1.0).as_i64().is_err()); 273 assert_eq!(ValueRef::Integer(1).as_i64(), Ok(1)); 274 Ok(()) 275 } 276 #[test] as_i64_or_null() -> FromSqlResult<()>277 fn as_i64_or_null() -> FromSqlResult<()> { 278 assert_eq!(ValueRef::Null.as_i64_or_null(), Ok(None)); 279 assert!(ValueRef::Real(1.0).as_i64_or_null().is_err()); 280 assert_eq!(ValueRef::Integer(1).as_i64_or_null(), Ok(Some(1))); 281 Ok(()) 282 } 283 #[test] as_f64() -> FromSqlResult<()>284 fn as_f64() -> FromSqlResult<()> { 285 assert!(ValueRef::Integer(1).as_f64().is_err()); 286 assert_eq!(ValueRef::Real(1.0).as_f64(), Ok(1.0)); 287 Ok(()) 288 } 289 #[test] as_f64_or_null() -> FromSqlResult<()>290 fn as_f64_or_null() -> FromSqlResult<()> { 291 assert_eq!(ValueRef::Null.as_f64_or_null(), Ok(None)); 292 assert!(ValueRef::Integer(1).as_f64_or_null().is_err()); 293 assert_eq!(ValueRef::Real(1.0).as_f64_or_null(), Ok(Some(1.0))); 294 Ok(()) 295 } 296 #[test] as_str() -> FromSqlResult<()>297 fn as_str() -> FromSqlResult<()> { 298 assert!(ValueRef::Null.as_str().is_err()); 299 assert_eq!(ValueRef::Text(b"").as_str(), Ok("")); 300 Ok(()) 301 } 302 #[test] as_str_or_null() -> FromSqlResult<()>303 fn as_str_or_null() -> FromSqlResult<()> { 304 assert_eq!(ValueRef::Null.as_str_or_null(), Ok(None)); 305 assert!(ValueRef::Integer(1).as_str_or_null().is_err()); 306 assert_eq!(ValueRef::Text(b"").as_str_or_null(), Ok(Some(""))); 307 Ok(()) 308 } 309 #[test] as_blob() -> FromSqlResult<()>310 fn as_blob() -> FromSqlResult<()> { 311 assert!(ValueRef::Null.as_blob().is_err()); 312 assert_eq!(ValueRef::Blob(b"").as_blob(), Ok(&b""[..])); 313 Ok(()) 314 } 315 #[test] as_blob_or_null() -> FromSqlResult<()>316 fn as_blob_or_null() -> FromSqlResult<()> { 317 assert_eq!(ValueRef::Null.as_blob_or_null(), Ok(None)); 318 assert!(ValueRef::Integer(1).as_blob_or_null().is_err()); 319 assert_eq!(ValueRef::Blob(b"").as_blob_or_null(), Ok(Some(&b""[..]))); 320 Ok(()) 321 } 322 #[test] as_bytes() -> FromSqlResult<()>323 fn as_bytes() -> FromSqlResult<()> { 324 assert!(ValueRef::Null.as_bytes().is_err()); 325 assert_eq!(ValueRef::Blob(b"").as_bytes(), Ok(&b""[..])); 326 Ok(()) 327 } 328 #[test] as_bytes_or_null() -> FromSqlResult<()>329 fn as_bytes_or_null() -> FromSqlResult<()> { 330 assert_eq!(ValueRef::Null.as_bytes_or_null(), Ok(None)); 331 assert!(ValueRef::Integer(1).as_bytes_or_null().is_err()); 332 assert_eq!(ValueRef::Blob(b"").as_bytes_or_null(), Ok(Some(&b""[..]))); 333 Ok(()) 334 } 335 } 336