summaryrefslogtreecommitdiff
path: root/lib/lua/sqlite/sqlite.c
diff options
context:
space:
mode:
authormbalmer <mbalmer@NetBSD.org>2011-10-15 10:26:30 +0000
committermbalmer <mbalmer@NetBSD.org>2011-10-15 10:26:30 +0000
commit58c6bbcc757d78432ce9f7f640206578a8536a2f (patch)
treec3cb4c3960da9c6cccc63d2b7169a2d511f910da /lib/lua/sqlite/sqlite.c
parent409457836a8ec7269ed8048da5d9efee0a0d8dd4 (diff)
A Lua module to access SQLite databases.
Diffstat (limited to 'lib/lua/sqlite/sqlite.c')
-rw-r--r--lib/lua/sqlite/sqlite.c481
1 files changed, 481 insertions, 0 deletions
diff --git a/lib/lua/sqlite/sqlite.c b/lib/lua/sqlite/sqlite.c
new file mode 100644
index 00000000000..eb5cff975b0
--- /dev/null
+++ b/lib/lua/sqlite/sqlite.c
@@ -0,0 +1,481 @@
+/* $NetBSD: sqlite.c,v 1.1 2011/10/15 10:26:30 mbalmer Exp $ */
+
+/*
+ * Copyright (c) 2011 Marc Balmer <marc@msys.ch>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* SQLite interface for Lua */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <sqlite3.h>
+#include <unistd.h>
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+#define SQLITE_DB_METATABLE "SQLite database connection methods"
+#define SQLITE_STMT_METATABLE "SQLite statement methods"
+
+int luaopen_sqlite(lua_State*);
+
+static void
+sqlite_error(lua_State *L, const char *fmt, ...)
+{
+ va_list ap;
+ int len;
+ char *msg;
+
+ va_start(ap, fmt);
+ len = vasprintf(&msg, fmt, ap);
+ va_end(ap);
+
+ if (len != -1) {
+ lua_pushstring(L, msg);
+ free(msg);
+ } else
+ lua_pushstring(L, "vasprintf failed");
+ lua_error(L);
+}
+
+static int
+sqlite_initialize(lua_State *L)
+{
+ lua_pushinteger(L, sqlite3_initialize());
+ return 1;
+}
+
+static int
+sqlite_shutdown(lua_State *L)
+{
+ lua_pushinteger(L, sqlite3_shutdown());
+ return 1;
+}
+
+static int
+sqlite_open(lua_State *L)
+{
+ sqlite3 **db;
+
+ db = lua_newuserdata(L, sizeof(sqlite3 *));
+ lua_pushinteger(L, sqlite3_open_v2(luaL_checkstring(L, -3), db,
+ (int)luaL_checkinteger(L, -2), NULL));
+
+ luaL_getmetatable(L, SQLITE_DB_METATABLE);
+ lua_setmetatable(L, -3);
+ return 2;
+
+}
+
+static int
+sqlite_libversion(lua_State *L)
+{
+ lua_pushstring(L, sqlite3_libversion());
+ return 1;
+}
+
+static int
+sqlite_libversion_number(lua_State *L)
+{
+ lua_pushinteger(L, sqlite3_libversion_number());
+ return 1;
+}
+
+static int
+sqlite_sourceid(lua_State *L)
+{
+ lua_pushstring(L, sqlite3_sourceid());
+ return 1;
+}
+
+static int
+db_close(lua_State *L)
+{
+ sqlite3 **db;
+
+ db = luaL_checkudata(L, 1, SQLITE_DB_METATABLE);
+ lua_pushinteger(L, sqlite3_close(*db));
+ return 1;
+
+}
+
+static int
+db_prepare(lua_State *L)
+{
+ sqlite3 **db;
+ sqlite3_stmt **stmt;
+ const char *sql;
+
+ db = luaL_checkudata(L, 1, SQLITE_DB_METATABLE);
+ stmt = lua_newuserdata(L, sizeof(sqlite3_stmt *));
+ sql = luaL_checkstring(L, 2);
+ lua_pushinteger(L, sqlite3_prepare_v2(*db, sql,
+ (int)strlen(sql) + 1, stmt, NULL));
+ luaL_getmetatable(L, SQLITE_STMT_METATABLE);
+ lua_setmetatable(L, -3);
+ return 2;
+
+}
+
+static int
+db_exec(lua_State *L)
+{
+ sqlite3 **db;
+
+ db = luaL_checkudata(L, 1, SQLITE_DB_METATABLE);
+ lua_pushinteger(L, sqlite3_exec(*db, lua_tostring(L, 2), NULL,
+ NULL, NULL));
+ return 1;
+}
+
+static int
+db_errcode(lua_State *L)
+{
+ sqlite3 **db;
+
+ db = luaL_checkudata(L, 1, SQLITE_DB_METATABLE);
+ lua_pushinteger(L, sqlite3_errcode(*db));
+ return 1;
+}
+
+static int
+db_errmsg(lua_State *L)
+{
+ sqlite3 **db;
+
+ db = luaL_checkudata(L, 1, SQLITE_DB_METATABLE);
+ lua_pushstring(L, sqlite3_errmsg(*db));
+ return 1;
+}
+
+static int
+db_get_autocommit(lua_State *L)
+{
+ sqlite3 **db;
+
+ db = luaL_checkudata(L, 1, SQLITE_DB_METATABLE);
+ lua_pushboolean(L, sqlite3_get_autocommit(*db));
+ return 1;
+}
+
+static int
+stmt_bind(lua_State *L)
+{
+ sqlite3_stmt **stmt;
+ int pidx;
+
+ stmt = luaL_checkudata(L, 1, SQLITE_STMT_METATABLE);
+ pidx = (int)luaL_checkinteger(L, 2);
+
+ switch (lua_type(L, 3)) {
+ case LUA_TNUMBER:
+ lua_pushinteger(L, sqlite3_bind_double(*stmt, pidx,
+ lua_tonumber(L, 3)));
+ break;
+ case LUA_TSTRING:
+ lua_pushinteger(L, sqlite3_bind_text(*stmt, pidx,
+ lua_tostring(L, 3), -1, NULL));
+ break;
+ case LUA_TNIL:
+ lua_pushinteger(L, sqlite3_bind_null(*stmt, pidx));
+ break;
+ default:
+ sqlite_error(L, "unsupported data type %s",
+ luaL_typename(L, 3));
+ }
+ return 1;
+}
+
+static int
+stmt_bind_parameter_count(lua_State *L)
+{
+ sqlite3_stmt **stmt;
+
+ stmt = luaL_checkudata(L, 1, SQLITE_STMT_METATABLE);
+ lua_pushinteger(L, sqlite3_bind_parameter_count(*stmt));
+ return 1;
+}
+
+static int
+stmt_bind_parameter_index(lua_State *L)
+{
+ sqlite3_stmt **stmt;
+
+ stmt = luaL_checkudata(L, 1, SQLITE_STMT_METATABLE);
+ lua_pushinteger(L, sqlite3_bind_parameter_index(*stmt,
+ lua_tostring(L, 2)));
+ return 1;
+}
+
+static int
+stmt_bind_parameter_name(lua_State *L)
+{
+ sqlite3_stmt **stmt;
+ int pidx;
+
+ stmt = luaL_checkudata(L, 1, SQLITE_STMT_METATABLE);
+ pidx = (int)luaL_checkinteger(L, 2);
+ lua_pushstring(L, sqlite3_bind_parameter_name(*stmt, pidx));
+ return 1;
+}
+
+static int
+stmt_step(lua_State *L)
+{
+ sqlite3_stmt **stmt;
+
+ stmt = luaL_checkudata(L, 1, SQLITE_STMT_METATABLE);
+ lua_pushinteger(L, sqlite3_step(*stmt));
+ return 1;
+}
+
+static int
+stmt_column_name(lua_State *L)
+{
+ sqlite3_stmt **stmt;
+ int cidx;
+
+ stmt = luaL_checkudata(L, 1, SQLITE_STMT_METATABLE);
+ cidx = (int)luaL_checkinteger(L, 2) - 1;
+
+ lua_pushstring(L, sqlite3_column_name(*stmt, cidx));
+ return 1;
+}
+
+static int
+stmt_column_count(lua_State *L)
+{
+ sqlite3_stmt **stmt;
+
+ stmt = luaL_checkudata(L, 1, SQLITE_STMT_METATABLE);
+ lua_pushinteger(L, sqlite3_column_count(*stmt));
+ return 1;
+}
+
+static int
+stmt_column(lua_State *L)
+{
+ sqlite3_stmt **stmt;
+ int cidx;
+
+ stmt = luaL_checkudata(L, 1, SQLITE_STMT_METATABLE);
+ cidx = (int)luaL_checkinteger(L, 2) - 1;
+
+ switch (sqlite3_column_type(*stmt, cidx)) {
+ case SQLITE_INTEGER:
+ lua_pushinteger(L, sqlite3_column_int(*stmt, cidx));
+ break;
+ case SQLITE_FLOAT:
+ lua_pushnumber(L, sqlite3_column_double(*stmt, cidx));
+ break;
+ case SQLITE_TEXT:
+ lua_pushstring(L, (const char *)sqlite3_column_text(*stmt,
+ cidx));
+ break;
+ case SQLITE_BLOB:
+ case SQLITE_NULL:
+ lua_pushnil(L);
+ break;
+ }
+ return 1;
+}
+
+static int
+stmt_reset(lua_State *L)
+{
+ sqlite3_stmt **stmt;
+
+ stmt = luaL_checkudata(L, 1, SQLITE_STMT_METATABLE);
+ sqlite3_reset(*stmt);
+ return 0;
+}
+
+static int
+stmt_clear_bindings(lua_State *L)
+{
+ sqlite3_stmt **stmt;
+
+ stmt = luaL_checkudata(L, 1, SQLITE_STMT_METATABLE);
+ sqlite3_clear_bindings(*stmt);
+ return 0;
+}
+
+static int
+stmt_finalize(lua_State *L)
+{
+ sqlite3_stmt **stmt;
+
+ stmt = luaL_checkudata(L, 1, SQLITE_STMT_METATABLE);
+ sqlite3_finalize(*stmt);
+ return 0;
+}
+
+struct constant {
+ const char *name;
+ int value;
+};
+
+static const struct constant sqlite_constant[] = {
+ /* SQLite return codes */
+ { "OK", SQLITE_OK },
+ { "ERROR", SQLITE_ERROR },
+ { "INTERNAL", SQLITE_INTERNAL },
+ { "PERM", SQLITE_PERM },
+ { "ABORT", SQLITE_ABORT },
+ { "BUSY", SQLITE_BUSY },
+ { "LOCKED", SQLITE_LOCKED },
+ { "NOMEM", SQLITE_NOMEM },
+ { "READONLY", SQLITE_READONLY },
+ { "INTERRUPT", SQLITE_INTERRUPT },
+ { "IOERR", SQLITE_IOERR },
+ { "CORRUPT", SQLITE_CORRUPT },
+ { "FULL", SQLITE_FULL },
+ { "CANTOPEN", SQLITE_CANTOPEN },
+ { "EMPTY", SQLITE_EMPTY },
+ { "SCHEMA", SQLITE_SCHEMA },
+ { "TOOBIG", SQLITE_TOOBIG },
+ { "CONSTRAINT", SQLITE_CONSTRAINT },
+ { "MISMATCH", SQLITE_MISMATCH },
+ { "MISUSE", SQLITE_MISUSE },
+ { "NOLFS", SQLITE_NOLFS },
+ { "AUTH", SQLITE_AUTH },
+ { "FORMAT", SQLITE_FORMAT },
+ { "RANGE", SQLITE_RANGE },
+ { "NOTADB", SQLITE_NOTADB },
+
+ { "ROW", SQLITE_ROW },
+ { "DONE", SQLITE_DONE },
+
+ /* File modes */
+ { "OPEN_READONLY", SQLITE_OPEN_READONLY },
+ { "OPEN_READWRITE", SQLITE_OPEN_READWRITE },
+ { "OPEN_CREATE", SQLITE_OPEN_CREATE },
+
+ { NULL, 0 }
+};
+
+static void
+gpio_set_info(lua_State *L)
+{
+ lua_pushliteral(L, "_COPYRIGHT");
+ lua_pushliteral(L, "Copyright (C) 2011 Marc Balmer <marc@msys.ch>");
+ lua_settable(L, -3);
+ lua_pushliteral(L, "_DESCRIPTION");
+ lua_pushliteral(L, "SQLite interface for Lua");
+ lua_settable(L, -3);
+ lua_pushliteral(L, "_VERSION");
+ lua_pushliteral(L, "sqlite 1.0.0");
+ lua_settable(L, -3);
+}
+
+int
+luaopen_sqlite(lua_State* L)
+{
+ static const struct luaL_Reg sqlite_methods[] = {
+ { "initialize", sqlite_initialize },
+ { "shutdown", sqlite_shutdown },
+ { "open", sqlite_open },
+ { "libversion", sqlite_libversion },
+ { "libversion_number", sqlite_libversion_number },
+ { "sourceid", sqlite_sourceid },
+ { NULL, NULL }
+ };
+ static const struct luaL_Reg db_methods[] = {
+ { "close", db_close },
+ { "prepare", db_prepare },
+ { "exec", db_exec },
+ { "errcode", db_errcode },
+ { "errmsg", db_errmsg },
+ { "get_autocommit", db_get_autocommit },
+ { NULL, NULL }
+ };
+ static const struct luaL_Reg stmt_methods[] = {
+ { "bind", stmt_bind },
+ { "bind_parameter_count", stmt_bind_parameter_count },
+ { "bind_parameter_index", stmt_bind_parameter_index },
+ { "bind_parameter_name", stmt_bind_parameter_name },
+ { "step", stmt_step },
+ { "column", stmt_column },
+ { "reset", stmt_reset },
+ { "clear_bindings", stmt_clear_bindings },
+ { "finalize", stmt_finalize },
+ { "column_name", stmt_column_name },
+ { "column_count", stmt_column_count },
+ { NULL, NULL }
+ };
+ int n;
+
+ sqlite3_initialize();
+
+ luaL_register(L, "sqlite", sqlite_methods);
+ gpio_set_info(L);
+
+ /* The database connection metatable */
+ if (luaL_newmetatable(L, SQLITE_DB_METATABLE)) {
+ luaL_register(L, NULL, db_methods);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, db_close);
+ lua_settable(L, -3);
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, -2);
+ lua_settable(L, -3);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushliteral(L, "must not access this metatable");
+ lua_settable(L, -3);
+ }
+ lua_pop(L, 1);
+
+ /* The statement metatable */
+ if (luaL_newmetatable(L, SQLITE_STMT_METATABLE)) {
+ luaL_register(L, NULL, stmt_methods);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, stmt_finalize);
+ lua_settable(L, -3);
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, -2);
+ lua_settable(L, -3);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushliteral(L, "must not access this metatable");
+ lua_settable(L, -3);
+ }
+ lua_pop(L, 1);
+
+ for (n = 0; sqlite_constant[n].name != NULL; n++) {
+ lua_pushinteger(L, sqlite_constant[n].value);
+ lua_setfield(L, -2, sqlite_constant[n].name);
+ };
+ return 1;
+}