From afc07b9339936a61f32294de9d504814bc73661e Mon Sep 17 00:00:00 2001
From: Daniel Oltmanns <53529846+oltdaniel@users.noreply.github.com>
Date: Wed, 5 Oct 2022 16:09:53 +0200
Subject: [PATCH] Proof of concept of sqlite serialization (#436)
* 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.
* Change demo for sqlite serialization
As explained in https://github.com/jart/cosmopolitan/pull/436#issuecomment-1164706893 the original use case is not possible with sqlite serialization, as an in-memory database cannot be shared across multiple processes. Thereby, this use case simply creates a backup of the in-memory database created in '.init.lua' and loads it to do a query.
* Fix sqlite3_deserialize parameters
The call to the sqlite3 library for the deserilization wasn't fully correct. This should fix the size parameters.
---
third_party/sqlite3/sqlite3.mk | 1 +
tool/net/demo/sql-backup.lua | 13 +++++++++++
tool/net/demo/sql-backupstore.lua | 4 ++++
tool/net/lsqlite3.c | 36 +++++++++++++++++++++++++++++++
tool/net/net.mk | 4 ++++
5 files changed, 58 insertions(+)
create mode 100644 tool/net/demo/sql-backup.lua
create mode 100644 tool/net/demo/sql-backupstore.lua
diff --git a/third_party/sqlite3/sqlite3.mk b/third_party/sqlite3/sqlite3.mk
index a30e3ac65..f9a8a6681 100644
--- a/third_party/sqlite3/sqlite3.mk
+++ b/third_party/sqlite3/sqlite3.mk
@@ -125,6 +125,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): private \
OVERRIDE_CFLAGS += \
diff --git a/tool/net/demo/sql-backup.lua b/tool/net/demo/sql-backup.lua
new file mode 100644
index 000000000..e8dea9f54
--- /dev/null
+++ b/tool/net/demo/sql-backup.lua
@@ -0,0 +1,13 @@
+if GetAssetSize("backup.sqlite3") == nil then
+ Write("no backup exists. call sql-backupstore.lua first.")
+ return
+end
+
+backup = sqlite3.open_memory()
+buffer = LoadAsset("backup.sqlite3")
+backup:deserialize(buffer)
+
+-- See .init.lua for CREATE TABLE setup.
+for row in backup:nrows("SELECT * FROM test") do
+ Write(row.id.." "..row.content.."
")
+end
\ No newline at end of file
diff --git a/tool/net/demo/sql-backupstore.lua b/tool/net/demo/sql-backupstore.lua
new file mode 100644
index 000000000..e99bd0010
--- /dev/null
+++ b/tool/net/demo/sql-backupstore.lua
@@ -0,0 +1,4 @@
+buffer = db:serialize()
+StoreAsset("backup.sqlite3", buffer)
+
+Write("backup created. size: "..GetAssetSize("backup.sqlite3"))
\ No newline at end of file
diff --git a/tool/net/lsqlite3.c b/tool/net/lsqlite3.c
index 2a8ee3be0..0e5798a6a 100644
--- a/tool/net/lsqlite3.c
+++ b/tool/net/lsqlite3.c
@@ -1695,6 +1695,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, size, 0);
+ free(buffer);
+ return 0;
+}
+
/*
** =======================================================
** General library functions
@@ -1864,6 +1897,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 },
diff --git a/tool/net/net.mk b/tool/net/net.mk
index d4462a4ae..36b79a141 100644
--- a/tool/net/net.mk
+++ b/tool/net/net.mk
@@ -138,6 +138,8 @@ o/$(MODE)/tool/net/.init.lua.zip.o \
o/$(MODE)/tool/net/demo/.init.lua.zip.o \
o/$(MODE)/tool/net/demo/.reload.lua.zip.o \
o/$(MODE)/tool/net/demo/sql.lua.zip.o \
+o/$(MODE)/tool/net/demo/sql-backup.lua.zip.o \
+o/$(MODE)/tool/net/demo/sql-backupstore.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-unix.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-rawsocket.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-subprocess.lua.zip.o \
@@ -187,6 +189,8 @@ o/$(MODE)/tool/net/redbean-demo.com.dbg: \
$(TOOL_NET_REDBEAN_LUA_MODULES) \
o/$(MODE)/tool/net/net.pkg \
o/$(MODE)/tool/net/demo/sql.lua.zip.o \
+ o/$(MODE)/tool/net/demo/sql-backup.lua.zip.o \
+ o/$(MODE)/tool/net/demo/sql-backupstore.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-unix.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-rawsocket.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-subprocess.lua.zip.o \