mirror of
				https://github.com/isar/rusqlite.git
				synced 2025-10-31 22:08:55 +08:00 
			
		
		
		
	Draft of serialize API
This commit is contained in:
		| @@ -77,6 +77,8 @@ column_decltype = [] | ||||
| wasm32-wasi-vfs = ["libsqlite3-sys/wasm32-wasi-vfs"] | ||||
| # Note: doesn't support 32-bit. | ||||
| winsqlite3 = ["libsqlite3-sys/winsqlite3"] | ||||
| # 3.23.0 | ||||
| serialize = ["modern_sqlite"] | ||||
|  | ||||
| # Helper feature for enabling most non-build-related optional features | ||||
| # or dependencies (except `session`). This is useful for running tests / clippy | ||||
| @@ -109,6 +111,7 @@ modern-full = [ | ||||
| ] | ||||
|  | ||||
| bundled-full = ["modern-full", "bundled"] | ||||
| default = ["serialize"] | ||||
|  | ||||
| [dependencies] | ||||
| time = { version = "0.3.0", features = ["formatting", "macros", "parsing"], optional = true } | ||||
|   | ||||
| @@ -393,7 +393,6 @@ impl Error { | ||||
|  | ||||
| #[cold] | ||||
| pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error { | ||||
|     // TODO sqlite3_error_offset // 3.38.0, #1130 | ||||
|     Error::SqliteFailure(ffi::Error::new(code), message) | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -119,6 +119,9 @@ mod params; | ||||
| mod pragma; | ||||
| mod raw_statement; | ||||
| mod row; | ||||
| #[cfg(feature = "serialize")] | ||||
| #[cfg_attr(docsrs, doc(cfg(feature = "serialize")))] | ||||
| pub mod serialize; | ||||
| #[cfg(feature = "session")] | ||||
| #[cfg_attr(docsrs, doc(cfg(feature = "session")))] | ||||
| pub mod session; | ||||
|   | ||||
							
								
								
									
										131
									
								
								src/serialize.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								src/serialize.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,131 @@ | ||||
| //! Serialize a database. | ||||
| use std::convert::TryInto; | ||||
| use std::marker::PhantomData; | ||||
| use std::ops::Deref; | ||||
| use std::ptr::NonNull; | ||||
|  | ||||
| use crate::error::error_from_handle; | ||||
| use crate::ffi; | ||||
| use crate::{Connection, DatabaseName, Result}; | ||||
|  | ||||
| /// Shared serialized database | ||||
| pub struct SharedData<'conn> { | ||||
|     phantom: PhantomData<&'conn Connection>, | ||||
|     ptr: NonNull<u8>, | ||||
|     sz: usize, | ||||
| } | ||||
|  | ||||
| /// Owned serialized database | ||||
| pub struct OwnedData { | ||||
|     ptr: NonNull<u8>, | ||||
|     sz: usize, | ||||
| } | ||||
|  | ||||
| /// Serialized database | ||||
| pub enum Data<'conn> { | ||||
|     /// Shared serialized database | ||||
|     Shared(SharedData<'conn>), | ||||
|     /// Owned serialized database | ||||
|     Owned(OwnedData), | ||||
| } | ||||
|  | ||||
| impl<'conn> Deref for Data<'conn> { | ||||
|     type Target = [u8]; | ||||
|  | ||||
|     fn deref(&self) -> &[u8] { | ||||
|         let (ptr, sz) = match self { | ||||
|             Data::Owned(OwnedData { ptr, sz }) => (ptr.as_ptr(), *sz), | ||||
|             Data::Shared(SharedData { ptr, sz, .. }) => (ptr.as_ptr(), *sz), | ||||
|         }; | ||||
|         unsafe { std::slice::from_raw_parts(ptr, sz) } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Drop for OwnedData { | ||||
|     fn drop(&mut self) { | ||||
|         unsafe { | ||||
|             ffi::sqlite3_free(self.ptr.as_ptr().cast()); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Connection { | ||||
|     /// Serialize a database. | ||||
|     pub fn serialize<'conn>(&'conn self, schema: DatabaseName<'_>) -> Result<Data<'conn>> { | ||||
|         let schema = schema.as_cstring()?; | ||||
|         let mut sz = 0; | ||||
|         let mut ptr: *mut u8 = unsafe { | ||||
|             ffi::sqlite3_serialize( | ||||
|                 self.handle(), | ||||
|                 schema.as_ptr(), | ||||
|                 &mut sz, | ||||
|                 ffi::SQLITE_SERIALIZE_NOCOPY, | ||||
|             ) | ||||
|         }; | ||||
|         Ok(if ptr.is_null() { | ||||
|             ptr = unsafe { ffi::sqlite3_serialize(self.handle(), schema.as_ptr(), &mut sz, 0) }; | ||||
|             if ptr.is_null() { | ||||
|                 return Err(unsafe { error_from_handle(self.handle(), ffi::SQLITE_NOMEM) }); | ||||
|             } | ||||
|             Data::Owned(OwnedData { | ||||
|                 ptr: NonNull::new(ptr).unwrap(), | ||||
|                 sz: sz.try_into().unwrap(), | ||||
|             }) | ||||
|         } else { | ||||
|             // shared buffer | ||||
|             Data::Shared(SharedData { | ||||
|                 ptr: NonNull::new(ptr).unwrap(), | ||||
|                 sz: sz.try_into().unwrap(), | ||||
|                 phantom: PhantomData, | ||||
|             }) | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     /// Deserialize a database. | ||||
|     pub fn deserialize( | ||||
|         &mut self, | ||||
|         schema: DatabaseName<'_>, | ||||
|         data: Data<'_>, | ||||
|         read_only: bool, | ||||
|     ) -> Result<()> { | ||||
|         let schema = schema.as_cstring()?; | ||||
|         let (data, sz, flags) = match data { | ||||
|             Data::Owned(OwnedData { ptr, sz }) => ( | ||||
|                 ptr.as_ptr(), // FIXME double-free => mem forget | ||||
|                 sz.try_into().unwrap(), | ||||
|                 if read_only { | ||||
|                     ffi::SQLITE_DESERIALIZE_FREEONCLOSE | ffi::SQLITE_DESERIALIZE_READONLY | ||||
|                 } else { | ||||
|                     ffi::SQLITE_DESERIALIZE_FREEONCLOSE | ffi::SQLITE_DESERIALIZE_RESIZEABLE | ||||
|                 }, | ||||
|             ), | ||||
|             Data::Shared(SharedData { ptr, sz, .. }) => ( | ||||
|                 ptr.as_ptr(), // FIXME lifetime of ptr must be > lifetime self | ||||
|                 sz.try_into().unwrap(), | ||||
|                 if read_only { | ||||
|                     ffi::SQLITE_DESERIALIZE_READONLY | ||||
|                 } else { | ||||
|                     0 | ||||
|                 }, | ||||
|             ), | ||||
|         }; | ||||
|         let rc = unsafe { | ||||
|             ffi::sqlite3_deserialize(self.handle(), schema.as_ptr(), data, sz, sz, flags) | ||||
|         }; | ||||
|         if rc != ffi::SQLITE_OK { | ||||
|             return Err(unsafe { error_from_handle(self.handle(), rc) }); | ||||
|         } | ||||
|         /* TODO | ||||
|         if let Some(mxSize) = mxSize { | ||||
|             unsafe { | ||||
|                 ffi::sqlite3_file_control( | ||||
|                     self.handle(), | ||||
|                     schema.as_ptr(), | ||||
|                     ffi::SQLITE_FCNTL_SIZE_LIMIT, | ||||
|                     &mut mxSize, | ||||
|                 ) | ||||
|             }; | ||||
|         }*/ | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user