mirror of
				https://github.com/isar/rusqlite.git
				synced 2025-10-31 13:58:55 +08:00 
			
		
		
		
	Oops
This commit is contained in:
		
							
								
								
									
										141
									
								
								src/context.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								src/context.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,141 @@ | ||||
| //! Code related to `sqlite3_context` common to `functions` and `vtab` modules. | ||||
|  | ||||
| use std::error::Error as StdError; | ||||
| use std::ffi::CStr; | ||||
| use std::os::raw::{c_char, c_int, c_void}; | ||||
|  | ||||
| use ffi; | ||||
| use ffi::sqlite3_context; | ||||
| use ffi::sqlite3_value; | ||||
|  | ||||
| use types::{ToSqlOutput, ValueRef}; | ||||
| use {str_to_cstring, Error}; | ||||
|  | ||||
| impl<'a> ValueRef<'a> { | ||||
|     pub unsafe fn from_value(value: *mut sqlite3_value) -> ValueRef<'a> { | ||||
|         use std::slice::from_raw_parts; | ||||
|  | ||||
|         match ffi::sqlite3_value_type(value) { | ||||
|             ffi::SQLITE_NULL => ValueRef::Null, | ||||
|             ffi::SQLITE_INTEGER => ValueRef::Integer(ffi::sqlite3_value_int64(value)), | ||||
|             ffi::SQLITE_FLOAT => ValueRef::Real(ffi::sqlite3_value_double(value)), | ||||
|             ffi::SQLITE_TEXT => { | ||||
|                 let text = ffi::sqlite3_value_text(value); | ||||
|                 assert!( | ||||
|                     !text.is_null(), | ||||
|                     "unexpected SQLITE_TEXT value type with NULL data" | ||||
|                 ); | ||||
|                 let s = CStr::from_ptr(text as *const c_char); | ||||
|  | ||||
|                 // sqlite3_value_text returns UTF8 data, so our unwrap here should be fine. | ||||
|                 let s = s.to_str() | ||||
|                     .expect("sqlite3_value_text returned invalid UTF-8"); | ||||
|                 ValueRef::Text(s) | ||||
|             } | ||||
|             ffi::SQLITE_BLOB => { | ||||
|                 let (blob, len) = ( | ||||
|                     ffi::sqlite3_value_blob(value), | ||||
|                     ffi::sqlite3_value_bytes(value), | ||||
|                 ); | ||||
|  | ||||
|                 assert!( | ||||
|                     len >= 0, | ||||
|                     "unexpected negative return from sqlite3_value_bytes" | ||||
|                 ); | ||||
|                 if len > 0 { | ||||
|                     assert!( | ||||
|                         !blob.is_null(), | ||||
|                         "unexpected SQLITE_BLOB value type with NULL data" | ||||
|                     ); | ||||
|                     ValueRef::Blob(from_raw_parts(blob as *const u8, len as usize)) | ||||
|                 } else { | ||||
|                     // The return value from sqlite3_value_blob() for a zero-length BLOB | ||||
|                     // is a NULL pointer. | ||||
|                     ValueRef::Blob(&[]) | ||||
|                 } | ||||
|             } | ||||
|             _ => unreachable!("sqlite3_value_type returned invalid value"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub unsafe fn set_result<'a>(ctx: *mut sqlite3_context, result: &ToSqlOutput<'a>) { | ||||
|     let value = match *result { | ||||
|         ToSqlOutput::Borrowed(v) => v, | ||||
|         ToSqlOutput::Owned(ref v) => ValueRef::from(v), | ||||
|  | ||||
|         #[cfg(feature = "blob")] | ||||
|         ToSqlOutput::ZeroBlob(len) => { | ||||
|             return ffi::sqlite3_result_zeroblob(ctx, len); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     match value { | ||||
|         ValueRef::Null => ffi::sqlite3_result_null(ctx), | ||||
|         ValueRef::Integer(i) => ffi::sqlite3_result_int64(ctx, i), | ||||
|         ValueRef::Real(r) => ffi::sqlite3_result_double(ctx, r), | ||||
|         ValueRef::Text(s) => { | ||||
|             let length = s.len(); | ||||
|             if length > ::std::i32::MAX as usize { | ||||
|                 ffi::sqlite3_result_error_toobig(ctx); | ||||
|             } else { | ||||
|                 let c_str = match str_to_cstring(s) { | ||||
|                     Ok(c_str) => c_str, | ||||
|                     // TODO sqlite3_result_error | ||||
|                     Err(_) => return ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_MISUSE), | ||||
|                 }; | ||||
|                 let destructor = if length > 0 { | ||||
|                     ffi::SQLITE_TRANSIENT() | ||||
|                 } else { | ||||
|                     ffi::SQLITE_STATIC() | ||||
|                 }; | ||||
|                 ffi::sqlite3_result_text(ctx, c_str.as_ptr(), length as c_int, destructor); | ||||
|             } | ||||
|         } | ||||
|         ValueRef::Blob(b) => { | ||||
|             let length = b.len(); | ||||
|             if length > ::std::i32::MAX as usize { | ||||
|                 ffi::sqlite3_result_error_toobig(ctx); | ||||
|             } else if length == 0 { | ||||
|                 ffi::sqlite3_result_zeroblob(ctx, 0) | ||||
|             } else { | ||||
|                 ffi::sqlite3_result_blob( | ||||
|                     ctx, | ||||
|                     b.as_ptr() as *const c_void, | ||||
|                     length as c_int, | ||||
|                     ffi::SQLITE_TRANSIENT(), | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub unsafe fn report_error(ctx: *mut sqlite3_context, err: &Error) { | ||||
|     // Extended constraint error codes were added in SQLite 3.7.16. We don't have an explicit | ||||
|     // feature check for that, and this doesn't really warrant one. We'll use the extended code | ||||
|     // if we're on the bundled version (since it's at least 3.17.0) and the normal constraint | ||||
|     // error code if not. | ||||
|     #[cfg(feature = "bundled")] | ||||
|     fn constraint_error_code() -> i32 { | ||||
|         ffi::SQLITE_CONSTRAINT_FUNCTION | ||||
|     } | ||||
|     #[cfg(not(feature = "bundled"))] | ||||
|     fn constraint_error_code() -> i32 { | ||||
|         ffi::SQLITE_CONSTRAINT | ||||
|     } | ||||
|  | ||||
|     match *err { | ||||
|         Error::SqliteFailure(ref err, ref s) => { | ||||
|             ffi::sqlite3_result_error_code(ctx, err.extended_code); | ||||
|             if let Some(Ok(cstr)) = s.as_ref().map(|s| str_to_cstring(s)) { | ||||
|                 ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1); | ||||
|             } | ||||
|         } | ||||
|         _ => { | ||||
|             ffi::sqlite3_result_error_code(ctx, constraint_error_code()); | ||||
|             if let Ok(cstr) = str_to_cstring(err.description()) { | ||||
|                 ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user