@@ -23,6 +23,7 @@ namespace sqlite {
2323using v8::Array;
2424using v8::ArrayBuffer;
2525using v8::BackingStoreInitializationMode;
26+ using v8::BackingStoreOnFailureMode;
2627using v8::BigInt;
2728using v8::Boolean;
2829using v8::ConstructorBehavior;
@@ -1719,6 +1720,133 @@ void DatabaseSync::Location(const FunctionCallbackInfo<Value>& args) {
17191720 }
17201721}
17211722
1723+ void DatabaseSync::Serialize (const FunctionCallbackInfo<Value>& args) {
1724+ DatabaseSync* db;
1725+ ASSIGN_OR_RETURN_UNWRAP (&db, args.This ());
1726+ Environment* env = Environment::GetCurrent (args);
1727+ THROW_AND_RETURN_ON_BAD_STATE (env, !db->IsOpen (), " database is not open" );
1728+
1729+ std::string db_name = " main" ;
1730+ if (!args[0 ]->IsUndefined ()) {
1731+ if (!args[0 ]->IsString ()) {
1732+ THROW_ERR_INVALID_ARG_TYPE (env->isolate (),
1733+ " The \" dbName\" argument must be a string." );
1734+ return ;
1735+ }
1736+ db_name = Utf8Value (env->isolate (), args[0 ].As <String>()).ToString ();
1737+ }
1738+
1739+ sqlite3_int64 size = 0 ;
1740+ unsigned char * data =
1741+ sqlite3_serialize (db->connection_ , db_name.c_str (), &size, 0 );
1742+
1743+ if (data == nullptr ) {
1744+ if (size == 0 ) {
1745+ Local<ArrayBuffer> ab = ArrayBuffer::New (env->isolate (), 0 );
1746+ args.GetReturnValue ().Set (Uint8Array::New (ab, 0 , 0 ));
1747+ return ;
1748+ }
1749+ THROW_ERR_SQLITE_ERROR (env->isolate (), db);
1750+ return ;
1751+ }
1752+
1753+ // V8 sandbox forbids external backing stores so allocate inside the
1754+ // sandbox and copy. Without sandbox wrap the output directly using
1755+ // sqlite3_free as the destructor to avoid the copy.
1756+ #ifdef V8_ENABLE_SANDBOX
1757+ auto free_data = OnScopeLeave ([&] { sqlite3_free (data); });
1758+ auto store = ArrayBuffer::NewBackingStore (
1759+ env->isolate (),
1760+ size,
1761+ BackingStoreInitializationMode::kUninitialized ,
1762+ BackingStoreOnFailureMode::kReturnNull );
1763+ if (!store) {
1764+ THROW_ERR_MEMORY_ALLOCATION_FAILED (env);
1765+ return ;
1766+ }
1767+ memcpy (store->Data (), data, size);
1768+ Local<ArrayBuffer> ab = ArrayBuffer::New (env->isolate (), std::move (store));
1769+ #else
1770+ auto store = ArrayBuffer::NewBackingStore (
1771+ data, size, [](void * ptr, size_t , void *) { sqlite3_free (ptr); }, nullptr );
1772+ Local<ArrayBuffer> ab = ArrayBuffer::New (env->isolate (), std::move (store));
1773+ #endif
1774+
1775+ args.GetReturnValue ().Set (Uint8Array::New (ab, 0 , size));
1776+ }
1777+
1778+ void DatabaseSync::Deserialize (const FunctionCallbackInfo<Value>& args) {
1779+ DatabaseSync* db;
1780+ ASSIGN_OR_RETURN_UNWRAP (&db, args.This ());
1781+ Environment* env = Environment::GetCurrent (args);
1782+ THROW_AND_RETURN_ON_BAD_STATE (env, !db->IsOpen (), " database is not open" );
1783+
1784+ if (!args[0 ]->IsUint8Array ()) {
1785+ THROW_ERR_INVALID_ARG_TYPE (env->isolate (),
1786+ " The \" buffer\" argument must be a Uint8Array." );
1787+ return ;
1788+ }
1789+
1790+ Local<Uint8Array> input = args[0 ].As <Uint8Array>();
1791+ size_t byte_length = input->ByteLength ();
1792+
1793+ if (byte_length == 0 ) {
1794+ THROW_ERR_INVALID_ARG_VALUE (env,
1795+ " The \" buffer\" argument must not be empty." );
1796+ return ;
1797+ }
1798+
1799+ std::string db_name = " main" ;
1800+ if (args.Length () > 1 && !args[1 ]->IsUndefined ()) {
1801+ if (!args[1 ]->IsObject ()) {
1802+ THROW_ERR_INVALID_ARG_TYPE (env->isolate (),
1803+ " The \" options\" argument must be an object." );
1804+ return ;
1805+ }
1806+
1807+ Local<Object> options = args[1 ].As <Object>();
1808+ Local<String> db_name_key = FIXED_ONE_BYTE_STRING (env->isolate (), " dbName" );
1809+ Local<Value> db_name_value;
1810+ if (!options->Get (env->context (), db_name_key).ToLocal (&db_name_value)) {
1811+ return ;
1812+ }
1813+
1814+ if (!db_name_value->IsUndefined ()) {
1815+ if (!db_name_value->IsString ()) {
1816+ THROW_ERR_INVALID_ARG_TYPE (
1817+ env->isolate (),
1818+ " The \" options.dbName\" argument must be a string." );
1819+ return ;
1820+ }
1821+ db_name =
1822+ Utf8Value (env->isolate (), db_name_value.As <String>()).ToString ();
1823+ }
1824+ }
1825+
1826+ unsigned char * buf =
1827+ static_cast <unsigned char *>(sqlite3_malloc64 (byte_length));
1828+ if (buf == nullptr ) {
1829+ THROW_ERR_MEMORY_ALLOCATION_FAILED (env);
1830+ return ;
1831+ }
1832+
1833+ input->CopyContents (buf, byte_length);
1834+
1835+ db->FinalizeStatements ();
1836+
1837+ int r = sqlite3_deserialize (
1838+ db->connection_ ,
1839+ db_name.c_str (),
1840+ buf,
1841+ byte_length,
1842+ byte_length,
1843+ SQLITE_DESERIALIZE_FREEONCLOSE | SQLITE_DESERIALIZE_RESIZEABLE);
1844+ if (r != SQLITE_OK) {
1845+ THROW_ERR_SQLITE_ERROR (env->isolate (), db);
1846+ return ;
1847+ }
1848+ }
1849+
17221850void DatabaseSync::AggregateFunction (const FunctionCallbackInfo<Value>& args) {
17231851 DatabaseSync* db;
17241852 ASSIGN_OR_RETURN_UNWRAP (&db, args.This ());
@@ -3766,6 +3894,8 @@ static void Initialize(Local<Object> target,
37663894 isolate, db_tmpl, " enableDefensive" , DatabaseSync::EnableDefensive);
37673895 SetProtoMethod (
37683896 isolate, db_tmpl, " loadExtension" , DatabaseSync::LoadExtension);
3897+ SetProtoMethod (isolate, db_tmpl, " serialize" , DatabaseSync::Serialize);
3898+ SetProtoMethod (isolate, db_tmpl, " deserialize" , DatabaseSync::Deserialize);
37693899 SetProtoMethod (
37703900 isolate, db_tmpl, " setAuthorizer" , DatabaseSync::SetAuthorizer);
37713901 SetSideEffectFreeGetter (isolate,
0 commit comments