diff -r 4ff31a4ea1fb -r 408291a6eb3e dbd/sqlite3/statement.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dbd/sqlite3/statement.c Sun Nov 23 01:29:09 2008 +0000 @@ -0,0 +1,222 @@ +#include "dbd_sqlite3.h" + +static lua_push_type_t sqlite_to_lua_push(unsigned int sqlite_type) { + lua_push_type_t lua_type; + + switch(sqlite_type) { + case SQLITE_NULL: + lua_type = LUA_PUSH_NIL; + break; + + case SQLITE_INTEGER: + lua_type = LUA_PUSH_INTEGER; + break; + + case SQLITE_FLOAT: + lua_type = LUA_PUSH_NUMBER; + break; + + default: + lua_type = LUA_PUSH_STRING; + } + + return lua_type; +} + +static int step(statement_t *statement) { + int res = sqlite3_step(statement->stmt); + + if (res == SQLITE_DONE) { + statement->more_data = 0; + return 1; + } else if (res == SQLITE_ROW) { + statement->more_data = 1; + return 1; + } + + return 0; +} + +static int statement_close(lua_State *L) { + statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_SQLITE_STATEMENT); + int ok = 0; + + if (statement->stmt) { + if (sqlite3_finalize(statement->stmt) == SQLITE_OK) { + ok = 1; + } + } + + lua_pushboolean(L, ok); + + return 1; +} + +static int statement_execute(lua_State *L) { + int n = lua_gettop(L); + statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_SQLITE_STATEMENT); + int p; + + if (sqlite3_reset(statement->stmt) != SQLITE_OK) { + lua_pushboolean(L, 0); + return 1; + } + + for (p = 2; p <= n; p++) { + int i = p - 1; + + if (lua_isnil(L, p)) { + if (sqlite3_bind_null(statement->stmt, i) != SQLITE_OK) { + luaL_error(L, "Failed to execute statement: %s", sqlite3_errmsg(statement->sqlite)); + } + } else if (lua_isnumber(L, p)) { + if (sqlite3_bind_double(statement->stmt, i, luaL_checknumber(L, p)) != SQLITE_OK) { + luaL_error(L, "Failed to execute statement: %s", sqlite3_errmsg(statement->sqlite)); + } + } else if (lua_isstring(L, p)) { + if (sqlite3_bind_text(statement->stmt, i, luaL_checkstring(L, p), -1, SQLITE_STATIC) != SQLITE_OK) { + luaL_error(L, "Failed to execute statement: %s", sqlite3_errmsg(statement->sqlite)); + } + } + } + + lua_pushboolean(L, step(statement)); + return 1; +} + +static int statement_fetch_impl(lua_State *L, int named_columns) { + statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_SQLITE_STATEMENT); + int num_columns; + + if (!statement->more_data) { + lua_pushnil(L); + return 1; + } + + num_columns = sqlite3_column_count(statement->stmt); + + if (num_columns) { + int i; + int d = 1; + + lua_newtable(L); + + for (i = 0; i < num_columns; i++) { + lua_push_type_t lua_push = sqlite_to_lua_push(sqlite3_column_type(statement->stmt, i)); + const char *name = sqlite3_column_name(statement->stmt, i); + + if (lua_push == LUA_PUSH_NIL) { + if (named_columns) { + LUA_PUSH_ATTRIB_NIL(name); + } else { + LUA_PUSH_ARRAY_NIL(d); + } + } else if (lua_push == LUA_PUSH_INTEGER) { + int val = sqlite3_column_int(statement->stmt, i); + + if (named_columns) { + LUA_PUSH_ATTRIB_INT(name, val); + } else { + LUA_PUSH_ARRAY_INT(d, val); + } + } else if (lua_push == LUA_PUSH_NUMBER) { + double val = sqlite3_column_double(statement->stmt, i); + + if (named_columns) { + LUA_PUSH_ATTRIB_FLOAT(name, val); + } else { + LUA_PUSH_ARRAY_FLOAT(d, val); + } + } else if (lua_push == LUA_PUSH_STRING) { + const char *val = (const char *)sqlite3_column_text(statement->stmt, i); + + if (named_columns) { + LUA_PUSH_ATTRIB_STRING(name, val); + } else { + LUA_PUSH_ARRAY_STRING(d, val); + } + } else if (lua_push == LUA_PUSH_BOOLEAN) { + int val = sqlite3_column_int(statement->stmt, i); + + if (named_columns) { + LUA_PUSH_ATTRIB_BOOL(name, val); + } else { + LUA_PUSH_ARRAY_BOOL(d, val); + } + } else { + luaL_error(L, "Unknown push type in result set"); + } + } + } + + if (step(statement) == 0) { + if (sqlite3_reset(statement->stmt) != SQLITE_OK) { + luaL_error(L, "Failed to fetch statement: %s", sqlite3_errmsg(statement->sqlite)); + } + } + + return 1; +} + + +static int statement_fetch(lua_State *L) { + return statement_fetch_impl(L, 0); +} + +static int statement_fetchtable(lua_State *L) { + return statement_fetch_impl(L, 1); +} + +static int statement_gc(lua_State *L) { + /* always free the handle */ + statement_close(L); + + return 0; +} + + +static const luaL_Reg statement_methods[] = { + {"close", statement_close}, + {"execute", statement_execute}, + {"fetch", statement_fetch}, + {"fetchtable", statement_fetchtable}, + {NULL, NULL} +}; + +static const luaL_Reg statement_class_methods[] = { + {NULL, NULL} +}; + +int dbd_sqlite3_statement_create(lua_State *L, connection_t *conn, const char *sql_query) { + statement_t *statement = NULL; + + statement = (statement_t *)lua_newuserdata(L, sizeof(statement_t)); + statement->sqlite = conn->sqlite; + statement->stmt = NULL; + statement->more_data = 0; + + if (sqlite3_prepare_v2(statement->sqlite, sql_query, strlen(sql_query), &statement->stmt, NULL) != SQLITE_OK) { + luaL_error(L, "Failed to prepare statement: %s", sqlite3_errmsg(statement->sqlite)); + lua_pushnil(L); + return 1; + } + + luaL_getmetatable(L, DBD_SQLITE_STATEMENT); + lua_setmetatable(L, -2); + + return 1; +} + +int dbd_sqlite3_statement(lua_State *L) { + luaL_newmetatable(L, DBD_SQLITE_STATEMENT); + luaL_register(L, 0, statement_methods); + lua_pushvalue(L,-1); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, statement_gc); + lua_setfield(L, -2, "__gc"); + + luaL_register(L, DBD_SQLITE_STATEMENT, statement_class_methods); + + return 1; +}