From 710c979bfa5ce0fc141748c3fd813fbec6e8220c Mon Sep 17 00:00:00 2001 From: oltdaniel <53529846+oltdaniel@users.noreply.github.com> Date: Mon, 20 Jun 2022 21:52:02 +0200 Subject: [PATCH] Proof of concept of sqlite serialization This is a minimal proof of concept in order to show that it is easily possible to store the sqlite database within the zip file itself not requiring creating an external file first. Changes include compiling the sqlite library with the serialization flag, adding serialize/deserialize to the lua sqlite library and demonstrating the work via the redbean demo. --- third_party/sqlite3/sqlite3.mk | 1 + tool/net/demo/.init.lua | 44 ++++++++++++++++++++++++++-------- tool/net/lsqlite3.c | 36 ++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 10 deletions(-) diff --git a/third_party/sqlite3/sqlite3.mk b/third_party/sqlite3/sqlite3.mk index e2d6b4925..621393972 100644 --- a/third_party/sqlite3/sqlite3.mk +++ b/third_party/sqlite3/sqlite3.mk @@ -129,6 +129,7 @@ THIRD_PARTY_SQLITE3_FLAGS = \ -DSQLITE_HAVE_C99_MATH_FUNCS \ -DSQLITE_ENABLE_MATH_FUNCTIONS \ -DSQLITE_ENABLE_JSON1 \ + -DSQLITE_ENABLE_DESERIALIZE \ $(THIRD_PARTY_SQLITE3_A_OBJS): \ OVERRIDE_CFLAGS += \ diff --git a/tool/net/demo/.init.lua b/tool/net/demo/.init.lua index 304d0f89a..19bf04366 100644 --- a/tool/net/demo/.init.lua +++ b/tool/net/demo/.init.lua @@ -9,16 +9,35 @@ HidePath('/usr/share/ssl/') -- LaunchBrowser('/tool/net/demo/index.html') -- sql database (see sql.lua) -db = sqlite3.open_memory() -db:exec[[ - CREATE TABLE test ( - id INTEGER PRIMARY KEY, - content TEXT - ); - INSERT INTO test (content) VALUES ('Hello World'); - INSERT INTO test (content) VALUES ('Hello Lua'); - INSERT INTO test (content) VALUES ('Hello Sqlite3'); -]] +function StoreSqlite(database, path) + local buffer = database:serialize() + return StoreAsset(path, buffer) +end + +function LoadSqlite(path) + local database = sqlite3.open_memory() + local buffer = LoadAsset(path) + database:deserialize(buffer) + return database +end + +database = "database.sqlite3" +-- Check if there is already a database +if GetAssetSize(database) ~= nil then + db = LoadSqlite(database) + db:exec[[ + INSERT INTO test (content) VALUES ('World'); + ]] +else + db = sqlite3.open_memory() + db:exec[[ + CREATE TABLE test ( + id INTEGER PRIMARY KEY, + content TEXT + ); + INSERT INTO test (content) VALUES ('Hello'); + ]] +end -- this intercepts all requests if it's defined function OnHttpRequest() @@ -35,6 +54,11 @@ function OnHttpRequest() SetHeader('Server', 'redbean!') end +function OnServerStop() + -- make sure we store the database on exit + StoreSqlite(db, database) +end + function Adder(x, y) return x + y end diff --git a/tool/net/lsqlite3.c b/tool/net/lsqlite3.c index 0510e736f..610b34293 100644 --- a/tool/net/lsqlite3.c +++ b/tool/net/lsqlite3.c @@ -1683,6 +1683,39 @@ static int db_gc(lua_State *L) { return 0; } +static int db_serialize(lua_State *L) { + sdb *db = lsqlite_getdb(L, 1); + sqlite_int64 size = 0; + + if (db->db == NULL) /* ignore closed databases */ + return 0; + + char *buffer = (char *)sqlite3_serialize(db->db, "main", &size, 0); + if (buffer == NULL) /* ignore failed database serialization */ + return 0; + + lua_pushlstring(L, buffer, size); + free(buffer); + return 1; +} + +static int db_deserialize(lua_State *L) { + sdb *db = lsqlite_getdb(L, 1); + size_t size = 0; + + if (db->db == NULL) /* ignore closed databases */ + return 0; + + + const char *buffer = luaL_checklstring(L, 2, &size); + if (buffer == NULL || size == 0) /* ignore empty database content */ + return 0; + + sqlite3_deserialize(db->db, "main", buffer, size, 5, 0); + free(buffer); + return 0; +} + /* ** ======================================================= ** General library functions @@ -1857,6 +1890,9 @@ static const luaL_Reg dblib[] = { {"close", db_close }, {"close_vm", db_close_vm }, + {"serialize", db_serialize }, + {"deserialize", db_deserialize }, + {"__tostring", db_tostring }, {"__gc", db_gc },