Add rebaser processing to SQLite Lua API

This commit is contained in:
Paul Kulchenko 2022-10-09 10:31:38 -07:00
parent cdc50f24cd
commit 6244e76177

View file

@ -1732,6 +1732,90 @@ static int db_deserialize(lua_State *L) {
return 0;
}
/*
** =======================================================
** Rebaser functions (for session support)
** =======================================================
*/
typedef struct {
sqlite3_rebaser *reb;
} lrebaser;
static lrebaser *lsqlite_makerebaser(lua_State *L, sqlite3_rebaser *reb) {
lrebaser *lreb = (lrebaser*)lua_newuserdata(L, sizeof(lrebaser));
lua_rawgeti(L, LUA_REGISTRYINDEX, sqlite_reb_meta_ref);
lua_setmetatable(L, -2);
lreb->reb = reb;
return lreb;
}
static lrebaser *lsqlite_getrebaser(lua_State *L, int index) {
return (lrebaser *)luaL_checkudata(L, index, sqlite_reb_meta);
}
static lrebaser *lsqlite_checkrebaser(lua_State *L, int index) {
lrebaser *lreb = lsqlite_getrebaser(L, index);
if (lreb->reb == NULL) luaL_argerror(L, index, "invalid sqlite rebaser");
return lreb;
}
static int lrebaser_delete(lua_State *L) {
lrebaser *lreb = lsqlite_getrebaser(L, 1);
if (lreb->reb != NULL) {
sqlite3rebaser_delete(lreb->reb);
lreb->reb = NULL;
}
return 0;
}
static int lrebaser_gc(lua_State *L) {
return lrebaser_delete(L);
}
static int lrebaser_tostring(lua_State *L) {
char buff[30];
lrebaser *lreb = lsqlite_getrebaser(L, 1);
if (lreb->reb == NULL)
strcpy(buff, "closed");
else
sprintf(buff, "%p", lreb->reb);
lua_pushfstring(L, "sqlite rebaser (%s)", buff);
return 1;
}
static int lrebaser_rebase(lua_State *L) {
lrebaser *lreb = lsqlite_checkrebaser(L, 1);
const char *cset = luaL_checkstring(L, 2);
int nset = lua_rawlen(L, 2);
int rc;
int size;
void *buf;
if ((rc = sqlite3rebaser_rebase(lreb->reb, nset, cset, &size, &buf)) != SQLITE_OK) {
lua_pushnil(L);
lua_pushinteger(L, rc);
return 2;
}
lua_pushlstring(L, buf, size);
sqlite3_free(buf);
return 1;
}
static int db_create_rebaser(lua_State *L) {
sqlite3_rebaser *reb;
int rc;
if ((rc = sqlite3rebaser_create(&reb)) != SQLITE_OK) {
lua_pushnil(L);
lua_pushinteger(L, rc);
return 2;
}
(void)lsqlite_makerebaser(L, reb);
return 1;
}
/*
** =======================================================
** Session functions
@ -1763,12 +1847,14 @@ static lsession *lsqlite_checksession(lua_State *L, int index) {
static int lsession_attach(lua_State *L) {
lsession *lses = lsqlite_checksession(L, 1);
const char *zTab = luaL_optstring(L, 2, NULL);
int rc;
if (sqlite3session_attach(lses->ses, zTab) != SQLITE_OK) {
if ((rc = sqlite3session_attach(lses->ses, zTab)) != SQLITE_OK) {
lua_pushnil(L);
} else {
lua_pushboolean(L, 1);
lua_pushinteger(L, rc);
return 2;
}
lua_pushboolean(L, 1);
return 1;
}
@ -1780,14 +1866,17 @@ static int lsession_isempty(lua_State *L) {
static int lsession_changeset(lua_State *L) {
lsession *lses = lsqlite_checksession(L, 1);
int rc;
int size;
void *buf;
if (sqlite3session_changeset(lses->ses, &size, &buf) != SQLITE_OK) {
if ((rc = sqlite3session_changeset(lses->ses, &size, &buf)) != SQLITE_OK) {
lua_pushnil(L);
} else {
lua_pushinteger(L, rc);
return 2;
}
lua_pushlstring(L, buf, size);
sqlite3_free(buf);
}
return 1;
}
@ -1899,6 +1988,9 @@ static int db_apply_changeset(lua_State *L) {
int top = lua_gettop(L);
int rc;
int flags = 0;
void *pRebase;
int nRebase;
lrebaser *lreb = NULL;
// parameters: db, changeset[[, filter cb], conflict cb[, udata[, rebaser[, flags]]]]
@ -1923,9 +2015,8 @@ static int db_apply_changeset(lua_State *L) {
top = lua_gettop(L);
}
}
if (top >= 6) lreb = lsqlite_checkrebaser(L, 6);
if (top >= 7) flags = luaL_checkinteger(L, 7);
if (top >= 4) { // two callback are guaranteed to be on the stack in this case
// shorten stack or extend to set udata to `nil` if not provided
lua_settop(L, 5);
@ -1937,7 +2028,10 @@ static int db_apply_changeset(lua_State *L) {
rc = sqlite3changeset_apply_v2(db->db, nset, cset,
db_changeset_filter_callback,
db_changeset_conflict_callback,
db, 0, 0, flags);
db, // context
lreb ? &pRebase : 0,
lreb ? &nRebase : 0,
flags);
if (rc != SQLITE_OK) {
lua_pushnil(L);
@ -1945,72 +2039,17 @@ static int db_apply_changeset(lua_State *L) {
return 2;
}
lua_pushboolean(L, 1);
return 1;
}
/*
** =======================================================
** Rebaser functions (for session support)
** =======================================================
*/
typedef struct {
sqlite3_rebaser *reb;
} lrebaser;
static lrebaser *lsqlite_makerebaser(lua_State *L, sqlite3_rebaser *reb) {
lrebaser *lreb = (lrebaser*)lua_newuserdata(L, sizeof(lrebaser));
lua_rawgeti(L, LUA_REGISTRYINDEX, sqlite_reb_meta_ref);
lua_setmetatable(L, -2);
lreb->reb = reb;
return lreb;
}
static lrebaser *lsqlite_getrebaser(lua_State *L, int index) {
return (lrebaser *)luaL_checkudata(L, index, sqlite_reb_meta);
}
static lrebaser *lsqlite_checkrebaser(lua_State *L, int index) {
lrebaser *lreb = lsqlite_getrebaser(L, index);
if (lreb->reb == NULL) luaL_argerror(L, index, "invalid sqlite rebaser");
return lreb;
}
static int lrebaser_delete(lua_State *L) {
lrebaser *lreb = lsqlite_getrebaser(L, 1);
if (lreb->reb != NULL) {
sqlite3rebaser_delete(lreb->reb);
lreb->reb = NULL;
}
return 0;
}
static int lrebaser_gc(lua_State *L) {
return lrebaser_delete(L);
}
static int lrebaser_tostring(lua_State *L) {
char buff[30];
lrebaser *lreb = lsqlite_getrebaser(L, 1);
if (lreb->reb == NULL)
strcpy(buff, "closed");
else
sprintf(buff, "%p", lreb->reb);
lua_pushfstring(L, "sqlite rebaser (%s)", buff);
return 1;
}
static int db_create_rebaser(lua_State *L) {
sqlite3_rebaser *reb;
if (sqlite3rebaser_create(&reb) != SQLITE_OK) {
if (lreb) { // if rebaser is present
rc = sqlite3rebaser_configure(lreb->reb, nRebase, pRebase);
if (rc == SQLITE_OK) lua_pushstring(L, pRebase);
sqlite3_free(pRebase);
if (rc == SQLITE_OK) return 1;
lua_pushnil(L);
lua_pushinteger(L, SQLITE_NOMEM);
lua_pushinteger(L, rc);
return 2;
}
(void)lsqlite_makerebaser(L, reb);
lua_pushboolean(L, 1);
return 1;
}
@ -2288,6 +2327,7 @@ static const luaL_Reg seslib[] = {
};
static const luaL_Reg reblib[] = {
{"rebase", lrebaser_rebase },
{"delete", lrebaser_delete },
{"__tostring", lrebaser_tostring },