mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-05 16:36:26 +00:00
Update lsqlite3 to add update hook support for redbean (#383)
This commit is contained in:
parent
668dc42bac
commit
183b3ed6a2
1 changed files with 200 additions and 0 deletions
|
@ -89,6 +89,15 @@ struct sdb {
|
|||
/* references */
|
||||
int busy_cb; /* busy callback */
|
||||
int busy_udata;
|
||||
|
||||
int update_hook_cb; /* update_hook callback */
|
||||
int update_hook_udata;
|
||||
|
||||
int commit_hook_cb; /* commit_hook callback */
|
||||
int commit_hook_udata;
|
||||
|
||||
int rollback_hook_cb; /* rollback_hook callback */
|
||||
int rollback_hook_udata;
|
||||
};
|
||||
|
||||
static const char *const sqlite_meta = ":sqlite3";
|
||||
|
@ -570,6 +579,12 @@ static sdb *newdb (lua_State *L) {
|
|||
|
||||
db->busy_cb =
|
||||
db->busy_udata =
|
||||
db->update_hook_cb =
|
||||
db->update_hook_udata =
|
||||
db->commit_hook_cb =
|
||||
db->commit_hook_udata =
|
||||
db->rollback_hook_cb =
|
||||
db->rollback_hook_udata =
|
||||
LUA_NOREF;
|
||||
|
||||
luaL_getmetatable(L, sqlite_meta);
|
||||
|
@ -614,6 +629,12 @@ static int cleanupdb(lua_State *L, sdb *db) {
|
|||
/* 'free' all references */
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, db->busy_cb);
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, db->busy_udata);
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_cb);
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_udata);
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_cb);
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_udata);
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_cb);
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_udata);
|
||||
|
||||
/* close database */
|
||||
result = sqlite3_close(db->db);
|
||||
|
@ -1130,6 +1151,182 @@ static int db_create_collation(lua_State *L) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** update_hook callback:
|
||||
** Params: database, callback function, userdata
|
||||
**
|
||||
** callback function:
|
||||
** Params: userdata, {one of SQLITE_INSERT, SQLITE_DELETE, or SQLITE_UPDATE},
|
||||
** database name, table name (containing the affected row), rowid of the row
|
||||
*/
|
||||
static void db_update_hook_callback(void *user, int op, char const *dbname, char const *tblname, sqlite3_int64 rowid) {
|
||||
sdb *db = (sdb*)user;
|
||||
lua_State *L = db->L;
|
||||
int top = lua_gettop(L);
|
||||
lua_Number n;
|
||||
|
||||
/* setup lua callback call */
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, db->update_hook_cb); /* get callback */
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, db->update_hook_udata); /* get callback user data */
|
||||
lua_pushinteger(L, op);
|
||||
lua_pushstring(L, dbname); /* update_hook database name */
|
||||
lua_pushstring(L, tblname); /* update_hook database name */
|
||||
|
||||
PUSH_INT64(L, rowid, lua_pushfstring(L, "%ll", rowid));
|
||||
|
||||
/* call lua function */
|
||||
lua_pcall(L, 5, 0, 0);
|
||||
/* ignore any error generated by this function */
|
||||
|
||||
lua_settop(L, top);
|
||||
}
|
||||
|
||||
static int db_update_hook(lua_State *L) {
|
||||
sdb *db = lsqlite_checkdb(L, 1);
|
||||
|
||||
if (lua_gettop(L) < 2 || lua_isnil(L, 2)) {
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_cb);
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_udata);
|
||||
|
||||
db->update_hook_cb =
|
||||
db->update_hook_udata = LUA_NOREF;
|
||||
|
||||
/* clear update_hook handler */
|
||||
sqlite3_update_hook(db->db, NULL, NULL);
|
||||
}
|
||||
else {
|
||||
luaL_checktype(L, 2, LUA_TFUNCTION);
|
||||
|
||||
/* make sure we have an userdata field (even if nil) */
|
||||
lua_settop(L, 3);
|
||||
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_cb);
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_udata);
|
||||
|
||||
db->update_hook_udata = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
db->update_hook_cb = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
|
||||
/* set update_hook handler */
|
||||
sqlite3_update_hook(db->db, db_update_hook_callback, db);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** commit_hook callback:
|
||||
** Params: database, callback function, userdata
|
||||
**
|
||||
** callback function:
|
||||
** Params: userdata
|
||||
** Returned value: Return false or nil to continue the COMMIT operation normally.
|
||||
** return true (non false, non nil), then the COMMIT is converted into a ROLLBACK.
|
||||
*/
|
||||
static int db_commit_hook_callback(void *user) {
|
||||
sdb *db = (sdb*)user;
|
||||
lua_State *L = db->L;
|
||||
int top = lua_gettop(L);
|
||||
int rollback = 0;
|
||||
|
||||
/* setup lua callback call */
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, db->commit_hook_cb); /* get callback */
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, db->commit_hook_udata); /* get callback user data */
|
||||
|
||||
/* call lua function */
|
||||
if (!lua_pcall(L, 1, 1, 0))
|
||||
rollback = lua_toboolean(L, -1); /* use result if there was no error */
|
||||
|
||||
lua_settop(L, top);
|
||||
return rollback;
|
||||
}
|
||||
|
||||
static int db_commit_hook(lua_State *L) {
|
||||
sdb *db = lsqlite_checkdb(L, 1);
|
||||
|
||||
if (lua_gettop(L) < 2 || lua_isnil(L, 2)) {
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_cb);
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_udata);
|
||||
|
||||
db->commit_hook_cb =
|
||||
db->commit_hook_udata = LUA_NOREF;
|
||||
|
||||
/* clear commit_hook handler */
|
||||
sqlite3_commit_hook(db->db, NULL, NULL);
|
||||
}
|
||||
else {
|
||||
luaL_checktype(L, 2, LUA_TFUNCTION);
|
||||
|
||||
/* make sure we have an userdata field (even if nil) */
|
||||
lua_settop(L, 3);
|
||||
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_cb);
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_udata);
|
||||
|
||||
db->commit_hook_udata = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
db->commit_hook_cb = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
|
||||
/* set commit_hook handler */
|
||||
sqlite3_commit_hook(db->db, db_commit_hook_callback, db);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** rollback hook callback:
|
||||
** Params: database, callback function, userdata
|
||||
**
|
||||
** callback function:
|
||||
** Params: userdata
|
||||
*/
|
||||
static void db_rollback_hook_callback(void *user) {
|
||||
sdb *db = (sdb*)user;
|
||||
lua_State *L = db->L;
|
||||
int top = lua_gettop(L);
|
||||
|
||||
/* setup lua callback call */
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, db->rollback_hook_cb); /* get callback */
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, db->rollback_hook_udata); /* get callback user data */
|
||||
|
||||
/* call lua function */
|
||||
lua_pcall(L, 1, 0, 0);
|
||||
/* ignore any error generated by this function */
|
||||
|
||||
lua_settop(L, top);
|
||||
}
|
||||
|
||||
static int db_rollback_hook(lua_State *L) {
|
||||
sdb *db = lsqlite_checkdb(L, 1);
|
||||
|
||||
if (lua_gettop(L) < 2 || lua_isnil(L, 2)) {
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_cb);
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_udata);
|
||||
|
||||
db->rollback_hook_cb =
|
||||
db->rollback_hook_udata = LUA_NOREF;
|
||||
|
||||
/* clear rollback_hook handler */
|
||||
sqlite3_rollback_hook(db->db, NULL, NULL);
|
||||
}
|
||||
else {
|
||||
luaL_checktype(L, 2, LUA_TFUNCTION);
|
||||
|
||||
/* make sure we have an userdata field (even if nil) */
|
||||
lua_settop(L, 3);
|
||||
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_cb);
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_udata);
|
||||
|
||||
db->rollback_hook_udata = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
db->rollback_hook_cb = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
|
||||
/* set rollback_hook handler */
|
||||
sqlite3_rollback_hook(db->db, db_rollback_hook_callback, db);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** busy handler:
|
||||
** Params: database, callback function, userdata
|
||||
|
@ -1640,6 +1837,9 @@ static const luaL_Reg dblib[] = {
|
|||
|
||||
{"busy_timeout", db_busy_timeout },
|
||||
{"busy_handler", db_busy_handler },
|
||||
{"update_hook", db_update_hook },
|
||||
{"commit_hook", db_commit_hook },
|
||||
{"rollback_hook", db_rollback_hook },
|
||||
|
||||
{"prepare", db_prepare },
|
||||
{"rows", db_rows },
|
||||
|
|
Loading…
Add table
Reference in a new issue