dbd/sqlite3/statement.c

changeset 1
408291a6eb3e
child 2
c4f02fc67e5a
--- /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;    
+}

mercurial