From 781976b1991759bc9daf1afe09cea1415bce04be Mon Sep 17 00:00:00 2001 From: Paul Kulchenko Date: Tue, 15 Nov 2022 22:08:37 -0800 Subject: [PATCH] Add iterating over changeset to SQLite Lua API --- tool/net/lsqlite3.c | 69 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/tool/net/lsqlite3.c b/tool/net/lsqlite3.c index ff7485c6b..7b7e89a9e 100644 --- a/tool/net/lsqlite3.c +++ b/tool/net/lsqlite3.c @@ -1827,13 +1827,15 @@ static int db_deserialize(lua_State *L) { typedef struct { sqlite3_changeset_iter *itr; + bool collectable; } liter; -static liter *lsqlite_makeiter(lua_State *L, sqlite3_changeset_iter *piter) { +static liter *lsqlite_makeiter(lua_State *L, sqlite3_changeset_iter *piter, bool collectable) { liter *litr = (liter*)lua_newuserdata(L, sizeof(liter)); lua_rawgeti(L, LUA_REGISTRYINDEX, sqlite_itr_meta_ref); lua_setmetatable(L, -2); litr->itr = piter; + litr->collectable = collectable; return litr; } @@ -1847,6 +1849,26 @@ static liter *lsqlite_checkiter(lua_State *L, int index) { return litr; } +static int liter_finalize(lua_State *L) { + liter *litr = lsqlite_getiter(L, 1); + int rc; + if (litr->itr) { + if (!litr->collectable) { + return pusherr(L, SQLITE_CORRUPT); + } + if ((rc = sqlite3changeset_finalize(litr->itr)) != SQLITE_OK) { + return pusherr(L, rc); + } + litr->itr = NULL; + } + lua_pushboolean(L, 1); + return 1; +} + +static int liter_gc(lua_State *L) { + return liter_finalize(L); +} + static int liter_tostring(lua_State *L) { char buff[32]; liter *litr = lsqlite_getiter(L, 1); @@ -1896,6 +1918,20 @@ static int liter_conflict(lua_State *L) { return liter_table(L, sqlite3changeset_conflict); } +static int liter_op(lua_State *L) { + const char *zTab; + int rc, nCol, Op, bIndirect; + liter *litr = lsqlite_checkiter(L, 1); + + if ((rc = sqlite3changeset_op(litr->itr, &zTab, &nCol, &Op, &bIndirect)) != LUA_OK) { + return pusherr(L, rc); + } + lua_pushstring(L, zTab); + lua_pushinteger(L, Op); + lua_pushboolean(L, bIndirect); + return 3; +} + static int liter_fk_conflicts(lua_State *L) { int rc, nOut; liter *litr = lsqlite_checkiter(L, 1); @@ -1906,6 +1942,15 @@ static int liter_fk_conflicts(lua_State *L) { return 1; } +static int liter_next(lua_State *L) { + liter *litr = lsqlite_checkiter(L, 1); + if (!litr->collectable) { + return pusherr(L, SQLITE_CORRUPT); + } + lua_pushinteger(L, sqlite3changeset_next(litr->itr)); + return 1; +} + static int liter_pk(lua_State *L) { const char *zTab; int n, rc, nCol; @@ -2031,7 +2076,7 @@ static int db_changeset_conflict_callback( lua_rawgeti(L, LUA_REGISTRYINDEX, changeset_conflict_cb); /* get callback */ lua_rawgeti(L, LUA_REGISTRYINDEX, changeset_cb_udata); /* get callback user data */ lua_pushinteger(L, eConflict); - (void)lsqlite_makeiter(L, p); + (void)lsqlite_makeiter(L, p, 0); lua_pushstring(L, zTab); lua_pushinteger(L, Op); lua_pushboolean(L, bIndirect); @@ -2241,6 +2286,21 @@ static int db_create_session(lua_State *L) { return 1; } +static int db_iterate_changeset(lua_State *L) { + sqlite3_changeset_iter *p; + sdb *db = lsqlite_checkdb(L, 1); + const char *cset = luaL_checkstring(L, 2); + int nset = lua_rawlen(L, 2); + int flags = luaL_optinteger(L, 3, 0); + int rc; + + if ((rc = sqlite3changeset_start_v2(&p, nset, cset, flags)) != SQLITE_OK) { + return pusherr(L, rc); + } + (void)lsqlite_makeiter(L, p, 1); + return 1; +} + static int db_invert_changeset(lua_State *L) { sdb *db = lsqlite_checkdb(L, 1); const char *cset = luaL_checkstring(L, 2); @@ -2551,6 +2611,7 @@ static const luaL_Reg dblib[] = { {"apply_changeset", db_apply_changeset }, {"invert_changeset", db_invert_changeset }, {"concat_changeset", db_concat_changeset }, + {"iterate_changeset", db_iterate_changeset }, #endif {"__tostring", db_tostring }, @@ -2652,13 +2713,17 @@ static const luaL_Reg reblib[] = { }; static const luaL_Reg itrlib[] = { + {"op", liter_op }, {"pk", liter_pk }, {"new", liter_new }, {"old", liter_old }, + {"next", liter_next }, {"conflict", liter_conflict }, + {"finalize", liter_finalize }, {"fk_conflicts", liter_fk_conflicts }, {"__tostring", liter_tostring }, + {"__gc", liter_gc }, {NULL, NULL} };