pax_global_header00006660000000000000000000000064134170543050014514gustar00rootroot0000000000000052 comment=73a234c4689e4f87b7520276b6159cc7f6cfd6e0 luadbi-0.7.2/000077500000000000000000000000001341705430500127625ustar00rootroot00000000000000luadbi-0.7.2/.luacheckrc000066400000000000000000000001661341705430500150720ustar00rootroot00000000000000std = "min" files["tests"] = { std = "max+busted", new_globals = { "DBI", "dbh", "db_type", "config", }; } luadbi-0.7.2/.travis.yml000066400000000000000000000024021341705430500150710ustar00rootroot00000000000000language: python sudo: true services: - mysql - postgresql env: - LUA="5.1" - LUA="5.2" - LUA="5.3" before_install: - sudo apt-get -qq update - sudo apt-get install -y libmysqlclient-dev libsqlite3-dev postgresql-server-dev-all - sudo pip install hererocks - hererocks ~/hererocks -r^ --lua $LUA - export PATH=$PATH:~/hererocks/bin - eval $(luarocks path --bin) - luarocks install luacheck - luarocks install busted install: - luarocks make luadbi-scm-0.rockspec - luarocks make luadbi-mysql-scm-0.rockspec - luarocks make luadbi-postgresql-scm-0.rockspec - luarocks make luadbi-sqlite3-scm-0.rockspec before_script: - mysql -u root -e 'CREATE DATABASE luadbi;' - mysql -u root -e "CREATE USER 'luadbi'@'localhost' IDENTIFIED BY 'testing12345!!!';" - mysql -u root -e "GRANT ALL ON luadbi.* TO 'luadbi'@'localhost';" - mysql -u root luadbi < tests/schemas/mysql.sql - psql -c "CREATE DATABASE luadbi;" -U postgres - psql -c "CREATE USER luadbi WITH PASSWORD 'testinguser-12345!!!';" -U postgres - psql luadbi < tests/schemas/postgresql.sql - cat tests/schemas/sqlite3.sql | sqlite3 tests/sqlite3-test script: - luacheck DBI.lua - luacheck tests || true - cd tests && busted run_tests.lua branches: only: - master luadbi-0.7.2/COPYING000066400000000000000000000020671341705430500140220ustar00rootroot00000000000000Copyright (c) 2008-2010 Neil Richardson (nrich@ii.net) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. luadbi-0.7.2/DBI.lua000066400000000000000000000034711341705430500140700ustar00rootroot00000000000000#!/usr/bin/lua local _M = {} -- Driver to module mapping local name_to_module = { MySQL = 'dbd.mysql', PostgreSQL = 'dbd.postgresql', SQLite3 = 'dbd.sqlite3', DB2 = 'dbd.db2', Oracle = 'dbd.oracle', ODBC = 'dbd.odbc' } local string = require('string') -- Returns a list of available drivers -- based on run time loading local function available_drivers() local available = {} for driver, modulefile in pairs(name_to_module) do local m, _ = pcall(require, modulefile) if m then table.insert(available, driver) end end -- no drivers available if #available < 1 then available = {'(None)'} end return available end -- High level DB connection function -- This should be used rather than DBD.{Driver}.New function _M.Connect(driver, ...) local modulefile = name_to_module[driver] if not modulefile then local available = table.concat(available_drivers(), ',') error(string.format("Driver '%s' not found. Available drivers are: %s", driver, available)) end local m, _ = pcall(require, modulefile) if not m then -- cannot load the module, we cannot continue local available = table.concat(available_drivers(), ',') error(string.format('Cannot load driver %s. Available drivers are: %s', driver, available)) end return package.loaded[modulefile].New(...) end -- Help function to do prepare and execute in -- a single step function _M.Do(dbh, sql, ...) local sth, err = dbh:prepare(sql) if not sth then return false, err end local ok ok, err = sth:execute(...) if not ok then return false, err end return sth:affected() end -- List drivers available on this system function _M.Drivers() return available_drivers() end -- Versioning Information _M._VERSION = '0.7' return _M luadbi-0.7.2/INSTALL000066400000000000000000000024621341705430500140170ustar00rootroot00000000000000= Dependencies = Before attempting to build LuaDBI the development libaries for each database must be installed. For Debian/Ubuntu systems, the list of required dependancies are: * libsqlite3-dev * libmysqlclient15-dev * libpq-dev * db2exc (optional for DB2 support) * oracle-xe-client (optional for Oracle support) = Building = Run `make` (or `make free`) in the source directory to build the Open Source database drivers. To build the drivers for DB2 and Oracle, run `make all`. == Windows == Inside the vc++ directory are build projects for Visual C++ to build LuaDBI for Windows. = Make Targets = * make free - builds MySQL, PostgreSQL and SQLite3 drivers * make all - as above, but also builds DB2 and Oracle drivers * make mysql * make psql * make sqlite3 * make db2 * make oracle = Make Targets (install) = * make install_free - builds and installs MySQL, PostgreSQL and SQLite3 drivers * make install_all - as above, but also builds and installs DB2 and Oracle drivers * make install_mysql * make install_psql * make install_sqlite3 * make install_db2 * make install_oracle = Installation = Please consult your distributions documentation on installing Lua modules. Please note that both the database binary driver packages (*.so|*.dll) and DBI.lua must be installed correctly to use LuaDBI luadbi-0.7.2/Makefile000066400000000000000000000122621341705430500144250ustar00rootroot00000000000000CC ?= cc AR ?= ar rcu RANLIB ?= ranlib RM ?= rm -rf MKDIR ?= mkdir -p INSTALL ?= install INSTALL_PROGRAM ?= $(INSTALL) INSTALL_DATA ?= $(INSTALL) -m 644 LUA_V ?= 5.1 LUA_LDIR ?= /usr/share/lua/$(LUA_V) LUA_CDIR ?= /usr/lib/lua/$(LUA_V) COMMON_CFLAGS ?= -g -pedantic -Wall -O2 -shared -fPIC -DPIC -std=c99 LUA_INC ?= -I/usr/include/lua$(LUA_V) MYSQL_INC ?= -I/usr/include/mysql PSQL_INC ?= -I/usr/include/postgresql SQLITE3_INC ?= -I/usr/include DB2_INC ?= -I/opt/ibm/db2exc/V9.5/include ORACLE_INC ?= -I/usr/lib/oracle/xe/app/oracle/product/10.2.0/client/rdbms/public CF = $(LUA_INC) $(COMMON_CFLAGS) $(CFLAGS) -I. COMMON_LDFLAGS ?= -shared MYSQL_LDFLAGS ?= -lmysqlclient PSQL_LDFLAGS ?= -lpq SQLITE3_LDFLAGS ?= -lsqlite3 DB2_LDFLAGS ?= -L/opt/ibm/db2exc/V9.5/lib64 -L/opt/ibm/db2exc/V9.5/lib32 -ldb2 ORACLE_LDFLAGS ?= -L/usr/lib/oracle/xe/app/oracle/product/10.2.0/client/lib/ -locixe LF = $(COMMON_LDFLAGS) $(LDFLAGS) MYSQL_FLAGS = $(CF) $(LF) $(MYSQL_INC) $(MYSQL_LDFLAGS) PSQL_FLAGS = $(CF) $(LF) $(PSQL_INC) $(PSQL_LDFLAGS) SQLITE3_FLAGS = $(CF) $(LF) $(SQLITE3_INC) $(SQLITE3_LDFLAGS) DB2_FLAGS = $(CF) $(LF) $(DB2_INC) $(DB2_LDFLAGS) ORACLE_FLAGS = $(CF) $(LF) $(ORACLE_INC) $(ORACLE_LDFLAGS) -DORA_ENABLE_PING -DORA_ENABLE_TAF BUILDDIR = build DBDMYSQL = dbd/mysql.so DBDPSQL = dbd/postgresql.so DBDSQLITE3 = dbd/sqlite3.so DBDDB2 = dbd/db2.so DBDORACLE = dbd/oracle.so OBJS = build/dbd_common.o MYSQL_OBJS = $(OBJS) build/dbd_mysql_main.o build/dbd_mysql_connection.o build/dbd_mysql_statement.o PSQL_OBJS = $(OBJS) build/dbd_postgresql_main.o build/dbd_postgresql_connection.o build/dbd_postgresql_statement.o SQLITE3_OBJS = $(OBJS) build/dbd_sqlite3_main.o build/dbd_sqlite3_connection.o build/dbd_sqlite3_statement.o DB2_OBJS = $(OBJS) build/dbd_db2_main.o build/dbd_db2_connection.o build/dbd_db2_statement.o ORACLE_OBJS = $(OBJS) build/dbd_oracle_main.o build/dbd_oracle_connection.o build/dbd_oracle_statement.o free: mysql psql sqlite3 all: mysql psql sqlite3 db2 oracle mysql: $(BUILDDIR) $(MYSQL_OBJS) $(CC) $(MYSQL_OBJS) -o $(DBDMYSQL) $(MYSQL_FLAGS) psql: $(BUILDDIR) $(PSQL_OBJS) $(CC) $(PSQL_OBJS) -o $(DBDPSQL) $(PSQL_FLAGS) sqlite3: $(BUILDDIR) $(SQLITE3_OBJS) $(CC) $(SQLITE3_OBJS) -o $(DBDSQLITE3) $(SQLITE3_FLAGS) db2: $(BUILDDIR) $(DB2_OBJS) $(CC) $(DB2_OBJS) -o $(DBDDB2) $(DB2_FLAGS) oracle: $(BUILDDIR) $(ORACLE_OBJS) $(CC) $(ORACLE_OBJS) -o $(DBDORACLE) $(ORACLE_FLAGS) clean: $(RM) $(MYSQL_OBJS) $(PSQL_OBJS) $(SQLITE3_OBJS) $(DB2_OBJS) $(ORACLE_OBJS) $(DBDMYSQL) $(DBDPSQL) $(DBDSQLITE3) $(DBDDB2) $(DBDORACLE) build/dbd_common.o: dbd/common.c dbd/common.h $(CC) -c -o $@ $< $(CF) build/dbd_mysql_connection.o: dbd/mysql/connection.c dbd/mysql/dbd_mysql.h dbd/common.h $(CC) -c -o $@ $< $(MYSQL_FLAGS) build/dbd_mysql_main.o: dbd/mysql/main.c dbd/mysql/dbd_mysql.h dbd/common.h $(CC) -c -o $@ $< $(MYSQL_FLAGS) build/dbd_mysql_statement.o: dbd/mysql/statement.c dbd/mysql/dbd_mysql.h dbd/common.h $(CC) -c -o $@ $< $(MYSQL_FLAGS) build/dbd_postgresql_connection.o: dbd/postgresql/connection.c dbd/postgresql/dbd_postgresql.h dbd/common.h $(CC) -c -o $@ $< $(PSQL_FLAGS) build/dbd_postgresql_main.o: dbd/postgresql/main.c dbd/postgresql/dbd_postgresql.h dbd/common.h $(CC) -c -o $@ $< $(PSQL_FLAGS) build/dbd_postgresql_statement.o: dbd/postgresql/statement.c dbd/postgresql/dbd_postgresql.h dbd/common.h $(CC) -c -o $@ $< $(PSQL_FLAGS) build/dbd_sqlite3_connection.o: dbd/sqlite3/connection.c dbd/sqlite3/dbd_sqlite3.h dbd/common.h $(CC) -c -o $@ $< $(SQLITE3_FLAGS) build/dbd_sqlite3_main.o: dbd/sqlite3/main.c dbd/sqlite3/dbd_sqlite3.h dbd/common.h $(CC) -c -o $@ $< $(SQLITE3_FLAGS) build/dbd_sqlite3_statement.o: dbd/sqlite3/statement.c dbd/sqlite3/dbd_sqlite3.h dbd/common.h $(CC) -c -o $@ $< $(SQLITE3_FLAGS) build/dbd_db2_connection.o: dbd/db2/connection.c dbd/db2/dbd_db2.h dbd/common.h $(CC) -c -o $@ $< $(DB2_FLAGS) build/dbd_db2_main.o: dbd/db2/main.c dbd/db2/dbd_db2.h dbd/common.h $(CC) -c -o $@ $< $(DB2_FLAGS) build/dbd_db2_statement.o: dbd/db2/statement.c dbd/db2/dbd_db2.h dbd/common.h $(CC) -c -o $@ $< $(DB2_FLAGS) build/dbd_oracle_connection.o: dbd/oracle/connection.c dbd/oracle/dbd_oracle.h dbd/common.h $(CC) -c -o $@ $< $(ORACLE_FLAGS) build/dbd_oracle_main.o: dbd/oracle/main.c dbd/oracle/dbd_oracle.h dbd/common.h $(CC) -c -o $@ $< $(ORACLE_FLAGS) build/dbd_oracle_statement.o: dbd/oracle/statement.c dbd/oracle/dbd_oracle.h dbd/common.h $(CC) -c -o $@ $< $(ORACLE_FLAGS) build: $(MKDIR) ${BUILDDIR} install_lua: $(INSTALL_DATA) -D DBI.lua $(DESTDIR)$(LUA_LDIR)/DBI.lua install_mysql: mysql install_lua $(INSTALL_PROGRAM) -D $(DBDMYSQL) $(DESTDIR)$(LUA_CDIR)/$(DBDMYSQL) install_psql: psql install_lua $(INSTALL_PROGRAM) -D $(DBDPSQL) $(DESTDIR)$(LUA_CDIR)/$(DBDPSQL) install_sqlite3: sqlite3 install_lua $(INSTALL_PROGRAM) -D $(DBDSQLITE3) $(DESTDIR)$(LUA_CDIR)/$(DBDSQLITE3) install_db2: db2 install_lua $(INSTALL_PROGRAM) -D $(DBDDB2) $(DESTDIR)$(LUA_CDIR)/$(DBDDB2) install_oracle: oracle install_lua $(INSTALL_PROGRAM) -D $(DBDORACLE) $(DESTDIR)$(LUA_CDIR)/$(DBDORACLE) install_free: install_lua install_mysql install_psql install_sqlite3 install_all: install_lua install_mysql install_psql install_sqlite3 install_db2 install_oracle luadbi-0.7.2/README.md000066400000000000000000000011701341705430500142400ustar00rootroot00000000000000LuaDBI is a database interface library for Lua. It is designed to provide a RDBMS agnostic API for handling database operations. LuaDBI also provides support for prepared statement handles, placeholders and bind parameters for all database operations. Currently LuaDBI supports DB2, Oracle, MySQL, PostgreSQL and SQLite databases with native database drivers. This version supports Lua 5.1, 5.2, and 5.3. [![Build Status](https://travis-ci.org/mwild1/luadbi.svg?branch=master)](https://travis-ci.org/mwild1/luadbi) Documentation is in the 'wiki' branch. You may also [browse it online](https://zadzmo.org/code/luadbi/wiki) luadbi-0.7.2/dbd/000077500000000000000000000000001341705430500135135ustar00rootroot00000000000000luadbi-0.7.2/dbd/common.c000066400000000000000000000062371341705430500151570ustar00rootroot00000000000000#include const char *dbd_strlower(char *in) { char *s = in; while(*s) { *s= (*s <= 'Z' && *s >= 'A') ? (*s - 'A') + 'a' : *s; s++; } return in; } /* * replace '?' placeholders with {native_prefix}\d+ placeholders * to be compatible with native API */ char *dbd_replace_placeholders(lua_State *L, char native_prefix, const char *sql) { size_t len = strlen(sql); int num_placeholders = 0; int extra_space = 0; size_t i; char *newsql; int newpos = 1; int ph_num = 1; int in_quote = 0; char format_str[4]; format_str[0] = native_prefix; format_str[1] = '%'; format_str[2] = 'u'; format_str[3] = '\0'; /* * dumb count of all '?' * this will match more placeholders than necessesary * but it's safer to allocate more placeholders at the * cost of a few bytes than risk a buffer overflow */ for (i = 1; i < len; i++) { if (sql[i] == '?') { num_placeholders++; } } /* * this is MAX_PLACEHOLDER_SIZE-1 because the '?' is * replaced with '{native_prefix}' */ extra_space = num_placeholders * (MAX_PLACEHOLDER_SIZE-1); /* * allocate a new string for the converted SQL statement */ newsql = calloc(len+extra_space+1, sizeof(char)); if(!newsql) { lua_pushliteral(L, "out of memory"); /* lua_error does not return. */ lua_error(L); } /* * copy first char. In valid SQL this cannot be a placeholder */ newsql[0] = sql[0]; /* * only replace '?' not in a single quoted string */ for (i = 1; i < len; i++) { /* * don't change the quote flag if the ''' is preceded * by a '\' to account for escaping */ if (sql[i] == '\'' && sql[i-1] != '\\') { in_quote = !in_quote; } if (sql[i] == '?' && !in_quote) { size_t n; if (ph_num > MAX_PLACEHOLDERS) { luaL_error(L, "Sorry, you are using more than %d placeholders. Use %c{num} format instead", MAX_PLACEHOLDERS, native_prefix); } n = snprintf(&newsql[newpos], MAX_PLACEHOLDER_SIZE, format_str, ph_num++); newpos += n; } else { newsql[newpos] = sql[i]; newpos++; } } /* * terminate string on the last position */ newsql[newpos] = '\0'; /* fprintf(stderr, "[%s]\n", newsql); */ return newsql; } void dbd_register(lua_State *L, const char *name, const luaL_Reg *methods, const luaL_Reg *class_methods, lua_CFunction gc, lua_CFunction tostring) { /* Create a new metatable with the given name and then assign the methods * to it. Set the __index, __gc and __tostring fields appropriately. */ luaL_newmetatable(L, name); #if LUA_VERSION_NUM < 502 luaL_register(L, 0, methods); #else luaL_setfuncs(L, methods, 0); #endif lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); lua_pushcfunction(L, gc); lua_setfield(L, -2, "__gc"); lua_pushcfunction(L, tostring); lua_setfield(L, -2, "__tostring"); /* Create a new table and register the class methods with it */ lua_newtable(L); #if LUA_VERSION_NUM < 502 luaL_register(L, 0, class_methods); #else luaL_setfuncs(L, class_methods, 0); #endif } luadbi-0.7.2/dbd/common.h000066400000000000000000000104271341705430500151600ustar00rootroot00000000000000#include #include #include #include #include #include #if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501) #include #endif #ifdef _WIN32 #define LUA_EXPORT __declspec(dllexport) #else #define LUA_EXPORT #endif #ifdef _MSC_VER /* all MS compilers define this (version) */ #define snprintf _snprintf #endif /* * * Table construction helper functions * * LUA_PUSH_ATTRIB_* creates string indexed (hashmap) * LUA_PUSH_ARRAY_* creates integer indexed (array) * */ #define LUA_PUSH_ATTRIB_INT(n, v) \ lua_pushstring(L, n); \ lua_pushinteger(L, v); \ lua_rawset(L, -3); #define LUA_PUSH_ATTRIB_FLOAT(n, v) \ lua_pushstring(L, n); \ lua_pushnumber(L, v); \ lua_rawset(L, -3); #define LUA_PUSH_ATTRIB_STRING_BY_LENGTH(n, v, len) \ lua_pushstring(L, n); \ lua_pushlstring(L, v, len); \ lua_rawset(L, -3); #define LUA_PUSH_ATTRIB_STRING(n, v) \ lua_pushstring(L, n); \ lua_pushstring(L, v); \ lua_rawset(L, -3); #define LUA_PUSH_ATTRIB_BOOL(n, v) \ lua_pushstring(L, n); \ lua_pushboolean(L, v); \ lua_rawset(L, -3); #define LUA_PUSH_ATTRIB_NIL(n) \ lua_pushstring(L, n); \ lua_pushnil(L); \ lua_rawset(L, -3); #define LUA_PUSH_ARRAY_INT(n, v) \ lua_pushinteger(L, v); \ lua_rawseti(L, -2, n); \ n++; #define LUA_PUSH_ARRAY_FLOAT(n, v) \ lua_pushnumber(L, v); \ lua_rawseti(L, -2, n); \ n++; #define LUA_PUSH_ARRAY_STRING(n, v) \ lua_pushstring(L, v); \ lua_rawseti(L, -2, n); \ n++; #define LUA_PUSH_ARRAY_STRING_BY_LENGTH(n, v, len) \ lua_pushlstring(L, v, len); \ lua_rawseti(L, -2, n); \ n++; #define LUA_PUSH_ARRAY_BOOL(n, v) \ lua_pushboolean(L, v); \ lua_rawseti(L, -2, n); \ n++; #define LUA_PUSH_ARRAY_NIL(n) \ lua_pushnil(L); \ lua_rawseti(L, -2, n); \ n++; /* * * Describes SQL to Lua API type conversions * */ typedef enum lua_push_type { LUA_PUSH_NIL = 0, LUA_PUSH_INTEGER, LUA_PUSH_NUMBER, LUA_PUSH_STRING, LUA_PUSH_BOOLEAN, LUA_PUSH_MAX } lua_push_type_t; /* * used for placeholder translations * from '?' to the .\d{4} */ #define MAX_PLACEHOLDERS 9999 #define MAX_PLACEHOLDER_SIZE (1+4) /* .\d{4} */ /* * * Common error strings * defined here for consistency in driver implementations * */ #define DBI_ERR_CONNECTION_FAILED "Failed to connect to database: %s" #define DBI_ERR_DB_UNAVAILABLE "Database not available" #define DBI_ERR_EXECUTE_INVALID "Execute called on a closed or invalid statement" #define DBI_ERR_EXECUTE_FAILED "Execute failed %s" #define DBI_ERR_FETCH_INVALID "Fetch called on a closed or invalid statement" #define DBI_ERR_FETCH_FAILED "Fetch failed %s" #define DBI_ERR_PARAM_MISCOUNT "Statement expected %d parameters but received %d" #define DBI_ERR_BINDING_PARAMS "Error binding statement parameters: %s" #define DBI_ERR_BINDING_EXEC "Error executing statement parameters: %s" #define DBI_ERR_FETCH_NO_EXECUTE "Fetch called before execute" #define DBI_ERR_BINDING_RESULTS "Error binding statement results: %s" #define DBI_ERR_UNKNOWN_PUSH "Unknown push type in result set" #define DBI_ERR_ALLOC_STATEMENT "Error allocating statement handle: %s" #define DBI_ERR_PREP_STATEMENT "Error preparing statement handle: %s" #define DBI_ERR_INVALID_PORT "Invalid port: %d" #define DBI_ERR_ALLOC_RESULT "Error allocating result set: %s" #define DBI_ERR_DESC_RESULT "Error describing result set: %s" #define DBI_ERR_BINDING_TYPE_ERR "Unknown or unsupported type `%s'" #define DBI_ERR_INVALID_STATEMENT "Invalid statement handle" #define DBI_ERR_NOT_IMPLEMENTED "Method %s.%s is not implemented" #define DBI_ERR_QUOTING_STR "Error quoting string: %s" #define DBI_ERR_STATEMENT_BROKEN "Statement unavailable: database closed" /* * convert string to lower case */ const char *dbd_strlower(char *in); /* * replace '?' placeholders with .\d+ placeholders * to be compatible with the native driver API */ char *dbd_replace_placeholders(lua_State *L, char native_prefix, const char *sql); void dbd_register(lua_State *L, const char *name, const luaL_Reg *methods, const luaL_Reg *class_methods, lua_CFunction gc, lua_CFunction tostring); luadbi-0.7.2/dbd/db2/000077500000000000000000000000001341705430500141625ustar00rootroot00000000000000luadbi-0.7.2/dbd/db2/connection.c000066400000000000000000000143301341705430500164660ustar00rootroot00000000000000#include "dbd_db2.h" #include "db2_common.h" int dbd_db2_statement_create(lua_State *L, connection_t *conn, const char *sql_query); static int commit(connection_t *conn) { SQLRETURN rc = SQL_SUCCESS; rc = SQLEndTran(SQL_HANDLE_DBC, conn->db2, SQL_COMMIT); return rc != SQL_SUCCESS; } static int rollback(connection_t *conn) { SQLRETURN rc = SQL_SUCCESS; rc = SQLEndTran(SQL_HANDLE_DBC, conn->db2, SQL_ROLLBACK); return rc != SQL_SUCCESS; } /* * connection = DBD.DB2.New(dbname, user, password, host, port) */ static int connection_new(lua_State *L) { int n = lua_gettop(L); connection_t *conn = NULL; SQLRETURN rc = SQL_SUCCESS; const char *user = NULL; const char *password = NULL; const char *db = NULL; SQLCHAR message[SQL_MAX_MESSAGE_LENGTH + 1]; /* db, user, password */ switch(n) { case 5: case 4: case 3: if (lua_isnil(L, 3) == 0) password = luaL_checkstring(L, 3); case 2: if (lua_isnil(L, 2) == 0) user = luaL_checkstring(L, 2); case 1: /* * db is the only mandatory parameter */ db = luaL_checkstring(L, 1); } conn = (connection_t *)lua_newuserdata(L, sizeof(connection_t)); /* allocate an environment handle */ rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &conn->env); if (rc != SQL_SUCCESS) { lua_pushnil(L); lua_pushfstring(L, DBI_ERR_CONNECTION_FAILED, "Cannot allocate environment handle"); return 2; } /* set attribute to enable application to run as ODBC 3.0 application */ rc = SQLSetEnvAttr(conn->env, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0); if (rc != SQL_SUCCESS) { lua_pushnil(L); lua_pushfstring(L, DBI_ERR_CONNECTION_FAILED, "Cannot set ODBC version attribute"); return 2; } /* allocate a database connection handle */ rc = SQLAllocHandle(SQL_HANDLE_DBC, conn->env, &conn->db2); if (rc != SQL_SUCCESS) { lua_pushnil(L); lua_pushfstring(L, DBI_ERR_CONNECTION_FAILED, "Cannot allocate database handle"); return 2; } /* set AUTOCOMMIT off */ rc = SQLSetConnectAttr(conn->db2, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_OFF, SQL_NTS); if (rc != SQL_SUCCESS) { lua_pushnil(L); lua_pushfstring(L, DBI_ERR_CONNECTION_FAILED, "Cannot turn off autocommit"); return 2; } /* connect to the database */ rc = SQLConnect(conn->db2, (SQLCHAR *)db, SQL_NTS, (SQLCHAR *)user, SQL_NTS, (SQLCHAR *)password, SQL_NTS); if (rc != SQL_SUCCESS) { db2_dbc_diag(conn->db2, message, sizeof(message)); lua_pushnil(L); lua_pushfstring(L, DBI_ERR_CONNECTION_FAILED, message); return 2; } luaL_getmetatable(L, DBD_DB2_CONNECTION); lua_setmetatable(L, -2); return 1; } /* * success = connection:autocommit(on) */ static int connection_autocommit(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_DB2_CONNECTION); int on = lua_toboolean(L, 2); int err = 0; if (conn->db2) { int onval = on ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF; SQLRETURN rc = SQLSetConnectAttr(conn->db2, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)onval, SQL_NTS); err = rc != SQL_SUCCESS; } lua_pushboolean(L, !err); return 1; } /* * success = connection:close() */ static int connection_close(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_DB2_CONNECTION); int disconnect = 0; if (conn->db2) { rollback(conn); /* disconnect from the database */ (void)SQLDisconnect(conn->db2); /* free connection handle */ (void)SQLFreeHandle(SQL_HANDLE_DBC, conn->db2); conn->db2 = 0; } if (conn->env) { /* free environment handle */ (void)SQLFreeHandle(SQL_HANDLE_ENV, conn->env); } lua_pushboolean(L, disconnect); return 1; } /* * success = connection:commit() */ static int connection_commit(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_DB2_CONNECTION); int err = 1; if (conn->db2) { err = commit(conn); } lua_pushboolean(L, !err); return 1; } /* * ok = connection:ping() */ static int connection_ping(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_DB2_CONNECTION); int ok = 0; if (conn->db2) { ok = 1; } lua_pushboolean(L, ok); return 1; } /* * statement = connection:prepare(sql_string) */ static int connection_prepare(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_DB2_CONNECTION); if (conn->db2) { return dbd_db2_statement_create(L, conn, luaL_checkstring(L, 2)); } lua_pushnil(L); lua_pushstring(L, DBI_ERR_DB_UNAVAILABLE); return 2; } /* * quoted = connection:quote(str) */ static int connection_quote(lua_State *L) { luaL_error(L, DBI_ERR_NOT_IMPLEMENTED, DBD_DB2_CONNECTION, "quote"); return 0; } /* * success = connection:rollback() */ static int connection_rollback(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_DB2_CONNECTION); int err = 1; if (conn->db2) { err = rollback(conn); } lua_pushboolean(L, !err); return 1; } /* * last_id = connection:last_id() */ static int connection_lastid(lua_State *L) { luaL_error(L, DBI_ERR_NOT_IMPLEMENTED, DBD_DB2_CONNECTION, "last_id"); return 0; } /* * __gc */ static int connection_gc(lua_State *L) { /* always close the connection */ connection_close(L); return 0; } /* * __tostring */ static int connection_tostring(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_DB2_CONNECTION); lua_pushfstring(L, "%s: %p", DBD_DB2_CONNECTION, conn); return 1; } int dbd_db2_connection(lua_State *L) { static const luaL_Reg connection_methods[] = { {"autocommit", connection_autocommit}, {"close", connection_close}, {"commit", connection_commit}, {"ping", connection_ping}, {"prepare", connection_prepare}, {"quote", connection_quote}, {"rollback", connection_rollback}, {"last_id", connection_lastid}, {NULL, NULL} }; static const luaL_Reg connection_class_methods[] = { {"New", connection_new}, {NULL, NULL} }; dbd_register(L, DBD_DB2_CONNECTION, connection_methods, connection_class_methods, connection_gc, connection_tostring); return 1; } luadbi-0.7.2/dbd/db2/db2_common.c000066400000000000000000000011001341705430500163350ustar00rootroot00000000000000#include "dbd_db2.h" #include "db2_common.h" void db2_stmt_diag(SQLHANDLE stmt, SQLCHAR *msg, SQLINTEGER msglen) { SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]; SQLINTEGER sqlcode; SQLSMALLINT length; SQLGetDiagRec(SQL_HANDLE_STMT, stmt, 1, sqlstate, &sqlcode, msg, msglen, &length); } void db2_dbc_diag(SQLHANDLE dbc, SQLCHAR *msg, SQLINTEGER msglen) { SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]; SQLINTEGER sqlcode; SQLSMALLINT length; SQLGetDiagRec(SQL_HANDLE_DBC, dbc, 1, sqlstate, &sqlcode, msg, msglen, &length); } luadbi-0.7.2/dbd/db2/db2_common.h000066400000000000000000000003551341705430500163550ustar00rootroot00000000000000#ifndef DBD_DB2_COMMON_H #define DBD_DB2_COMMON_H void db2_stmt_diag(SQLHANDLE stmt, SQLCHAR *msg, SQLINTEGER msglen); void db2_dbc_diag(SQLHANDLE dbc, SQLCHAR *msg, SQLINTEGER msglen); #endif /* DBD_DB2_COMMON_H */ luadbi-0.7.2/dbd/db2/dbd_db2.h000066400000000000000000000020561341705430500156160ustar00rootroot00000000000000#undef UNICODE #include #include #include #include #define DBD_DB2_CONNECTION "DBD.DB2.Connection" #define DBD_DB2_STATEMENT "DBD.DB2.Statement" /* * result set metadata */ typedef union _resultset_data { SQLCHAR *str; lua_Number number; lua_Integer integer; int boolean; } resultset_data_t; typedef struct _resultset { SQLSMALLINT name_len; SQLSMALLINT type; SQLUINTEGER size; SQLSMALLINT scale; SQLINTEGER actual_len; lua_push_type_t lua_type; resultset_data_t data; SQLCHAR name[32]; } resultset_t; /* * connection object implentation */ typedef struct _connection { SQLHANDLE env; SQLHANDLE db2; } connection_t; /* * statement object implementation */ typedef struct _statement { resultset_t * resultset; unsigned char *buffer; SQLSMALLINT num_result_columns; /* variable for SQLNumResultCols */ SQLHANDLE stmt; SQLHANDLE db2; int cursor_open; SQLSMALLINT num_params; unsigned char *parambuf; } statement_t; luadbi-0.7.2/dbd/db2/main.c000066400000000000000000000003671341705430500152600ustar00rootroot00000000000000#include "dbd_db2.h" int dbd_db2_connection(lua_State *L); int dbd_db2_statement(lua_State *L); /* * library entry point */ LUA_EXPORT int luaopen_dbd_db2(lua_State *L) { dbd_db2_statement(L); dbd_db2_connection(L); return 1; } luadbi-0.7.2/dbd/db2/statement.c000066400000000000000000000313561341705430500163420ustar00rootroot00000000000000#include "dbd_db2.h" #include "db2_common.h" #define BIND_BUFFER_SIZE 1024 static lua_push_type_t db2_to_lua_push(unsigned int db2_type) { lua_push_type_t lua_type; switch(db2_type) { case SQL_BOOLEAN: lua_type = LUA_PUSH_BOOLEAN; case SQL_SMALLINT: case SQL_INTEGER: lua_type = LUA_PUSH_INTEGER; break; case SQL_FLOAT: case SQL_REAL: case SQL_DOUBLE: case SQL_DECIMAL: lua_type = LUA_PUSH_NUMBER; break; break; default: lua_type = LUA_PUSH_STRING; } return lua_type; } /* * num_affected_rows = statement:affected() */ static int statement_affected(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_DB2_STATEMENT); SQLINTEGER affected; if (!statement->stmt) { luaL_error(L, DBI_ERR_INVALID_STATEMENT); } (void)SQLRowCount(statement->stmt, &affected); lua_pushinteger(L, affected); return 1; } /* * free cursor and associated memory */ static void free_cursor(statement_t *statement) { if (statement->cursor_open) { SQLFreeStmt(statement->stmt, SQL_CLOSE); statement->cursor_open = 0; } } /* * success = statement:close() */ static int statement_close(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_DB2_STATEMENT); free_cursor(statement); if (statement->resultset) { free(statement->resultset); statement->resultset = NULL; } if (statement->parambuf) { free(statement->parambuf); statement->parambuf = NULL; } statement->num_result_columns = 0; if (statement->stmt) { SQLFreeHandle(SQL_HANDLE_STMT, statement->stmt); statement->stmt = SQL_NULL_HSTMT; } return 0; } /* * column_names = statement:columns() */ static int statement_columns(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_DB2_STATEMENT); int i; int d; if (!statement->resultset) { lua_pushnil(L); return 1; } d = 1; lua_newtable(L); for (i = 0; i < statement->num_result_columns; i++) { const char *name = dbd_strlower((char *)statement->resultset[i].name); LUA_PUSH_ARRAY_STRING(d, name); } return 1; } /* * success = statement:execute(...) */ static int statement_execute(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_DB2_STATEMENT); int n = lua_gettop(L); int p; int errflag = 0; const char *errstr = NULL; SQLRETURN rc = SQL_SUCCESS; unsigned char *buffer = statement->parambuf; int offset = 0; SQLCHAR message[SQL_MAX_MESSAGE_LENGTH + 1]; if (!statement->stmt) { lua_pushboolean(L, 0); lua_pushstring(L, DBI_ERR_EXECUTE_INVALID); return 2; } /* If the cursor is open from a previous execute, close it */ free_cursor(statement); if (statement->num_params != n-1) { /* * SQLExecute does not handle this condition, * and the client library will fill unset params * with NULLs */ lua_pushboolean(L, 0); lua_pushfstring(L, DBI_ERR_PARAM_MISCOUNT, statement->num_params, n-1); return 2; } for (p = 2; p <= n; p++) { int i = p - 1; int type = lua_type(L, p); char err[64]; const char *str = NULL; size_t len = 0; double *num; int *boolean; const static SQLLEN nullvalue = SQL_NULL_DATA; switch(type) { case LUA_TNIL: rc = SQLBindParameter(statement->stmt, i, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, (SQLPOINTER)0, 0, (SQLPOINTER)&nullvalue); errflag = rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO; break; case LUA_TNUMBER: num = (double *)(buffer + offset); *num = lua_tonumber(L, p); offset += sizeof(double); rc = SQLBindParameter(statement->stmt, i, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DECIMAL, 10, 0, (SQLPOINTER)num, 0, NULL); errflag = rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO; break; case LUA_TSTRING: str = lua_tolstring(L, p, &len); rc = SQLBindParameter(statement->stmt, i, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 0, 0, (SQLPOINTER)str, len, NULL); errflag = rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO; break; case LUA_TBOOLEAN: boolean = (int *)(buffer + offset); *boolean = lua_toboolean(L, p); offset += sizeof(int); rc = SQLBindParameter(statement->stmt, i, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, (SQLPOINTER)boolean, len, NULL); errflag = rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO; break; default: /* * Unknown/unsupported value type */ errflag = 1; snprintf(err, sizeof(err)-1, DBI_ERR_BINDING_TYPE_ERR, lua_typename(L, type)); errstr = err; } if (errflag) break; } if (errflag) { lua_pushboolean(L, 0); if (errstr) { lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errstr); } else { db2_stmt_diag(statement->stmt, message, sizeof(message)); lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, message); } return 2; } rc = SQLExecute(statement->stmt); if (rc != SQL_SUCCESS) { db2_stmt_diag(statement->stmt, message, sizeof(message)); lua_pushnil(L); lua_pushfstring(L, DBI_ERR_PREP_STATEMENT, message); return 2; } statement->cursor_open = 1; lua_pushboolean(L, 1); return 1; } /* * must be called after an execute */ static int statement_fetch_impl(lua_State *L, statement_t *statement, int named_columns) { int i; int d; SQLCHAR message[SQL_MAX_MESSAGE_LENGTH + 1]; SQLRETURN rc; if (!statement->cursor_open) goto nodata; /* fetch each row, and display */ rc = SQLFetch(statement->stmt); if (rc == SQL_NO_DATA_FOUND) { free_cursor(statement); goto nodata; } if (rc != SQL_SUCCESS) { db2_stmt_diag(statement->stmt, message, sizeof(message)); luaL_error(L, DBI_ERR_FETCH_FAILED, message); } d = 1; lua_newtable(L); for (i = 0; i < statement->num_result_columns; i++) { resultset_t *rs = &statement->resultset[i]; SQLCHAR *name = rs->name; lua_push_type_t lua_type = rs->lua_type; resultset_data_t *data = &(rs->data); if (rs->actual_len == SQL_NULL_DATA) lua_type = LUA_PUSH_NIL; if (named_columns) lua_pushstring(L, (const char *)name); switch (lua_type) { case LUA_PUSH_NIL: lua_pushnil(L); break; case LUA_PUSH_INTEGER: lua_pushinteger(L, data->integer); break; case LUA_PUSH_NUMBER: lua_pushnumber(L, data->number); break; case LUA_PUSH_BOOLEAN: lua_pushboolean(L, data->boolean); break; case LUA_PUSH_STRING: lua_pushstring(L, (const char *)data->str); break; default: luaL_error(L, DBI_ERR_UNKNOWN_PUSH); } if (named_columns) lua_rawset(L, -3); else { lua_rawseti(L, -2, d); d++; } } return 1; nodata: lua_pushnil(L); return 1; } static int next_iterator(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, lua_upvalueindex(1), DBD_DB2_STATEMENT); int named_columns = lua_toboolean(L, lua_upvalueindex(2)); return statement_fetch_impl(L, statement, named_columns); } /* * table = statement:fetch(named_indexes) */ static int statement_fetch(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_DB2_STATEMENT); int named_columns = lua_toboolean(L, 2); return statement_fetch_impl(L, statement, named_columns); } /* * num_rows = statement:rowcount() */ static int statement_rowcount(lua_State *L) { luaL_error(L, DBI_ERR_NOT_IMPLEMENTED, DBD_DB2_STATEMENT, "rowcount"); return 0; } /* * iterfunc = statement:rows(named_indexes) */ static int statement_rows(lua_State *L) { if (lua_gettop(L) == 1) { lua_pushvalue(L, 1); lua_pushboolean(L, 0); } else { lua_pushvalue(L, 1); lua_pushboolean(L, lua_toboolean(L, 2)); } lua_pushcclosure(L, next_iterator, 2); return 1; } /* * __gc */ static int statement_gc(lua_State *L) { /* always free the handle */ statement_close(L); return 0; } /* * __tostring */ static int statement_tostring(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_DB2_STATEMENT); lua_pushfstring(L, "%s: %p", DBD_DB2_STATEMENT, statement); return 1; } int dbd_db2_statement_create(lua_State *L, connection_t *conn, const char *sql_query) { SQLRETURN rc = SQL_SUCCESS; statement_t *statement = NULL; SQLHANDLE stmt; SQLCHAR message[SQL_MAX_MESSAGE_LENGTH + 1]; SQLCHAR *buffer = NULL; int buflen; SQLSMALLINT sqlctype; SQLPOINTER dataptr; int datalen; resultset_t *resultset = NULL; int i; rc = SQLAllocHandle(SQL_HANDLE_STMT, conn->db2, &stmt); if (rc != SQL_SUCCESS) { db2_dbc_diag(conn->db2, message, sizeof(message)); lua_pushnil(L); lua_pushfstring(L, DBI_ERR_ALLOC_STATEMENT, message); return 2; } /* * turn off deferred prepare * statements will be sent to the server at prepare time, * and therefore we can catch errors now rather * than at execute time */ rc = SQLSetStmtAttr(stmt,SQL_ATTR_DEFERRED_PREPARE,(SQLPOINTER)SQL_DEFERRED_PREPARE_OFF,0); rc = SQLPrepare(stmt, (SQLCHAR *)sql_query, SQL_NTS); if (rc != SQL_SUCCESS) { db2_stmt_diag(stmt, message, sizeof(message)); lua_pushnil(L); lua_pushfstring(L, DBI_ERR_PREP_STATEMENT, message); return 2; } statement = (statement_t *)lua_newuserdata(L, sizeof(statement_t)); statement->stmt = stmt; statement->db2 = conn->db2; statement->resultset = NULL; statement->cursor_open = 0; statement->num_params = 0; statement->parambuf = NULL; /* * identify the number of input parameters */ rc = SQLNumParams(stmt, &statement->num_params); if (rc != SQL_SUCCESS) { db2_stmt_diag(stmt, message, sizeof(message)); lua_pushboolean(L, 0); lua_pushfstring(L, DBI_ERR_PREP_STATEMENT, message); return 2; } if (statement->num_params > 0) { statement->parambuf = (unsigned char *)malloc(sizeof(double) * statement->num_params); } /* * identify the number of output columns */ rc = SQLNumResultCols(stmt, &statement->num_result_columns); if (statement->num_result_columns > 0) { resultset = (resultset_t *)malloc(sizeof(resultset_t) * statement->num_result_columns); memset(resultset, 0, sizeof(resultset_t) * statement->num_result_columns); buflen = 0; for (i = 0; i < statement->num_result_columns; i++) { /* * return a set of attributes for a column */ rc = SQLDescribeCol(stmt, (SQLSMALLINT)(i + 1), resultset[i].name, sizeof(resultset[i].name), &resultset[i].name_len, &resultset[i].type, &resultset[i].size, &resultset[i].scale, NULL); if (rc != SQL_SUCCESS) { db2_stmt_diag(stmt, message, sizeof(message)); lua_pushnil(L); lua_pushfstring(L, DBI_ERR_DESC_RESULT, message); return 2; } resultset[i].lua_type = db2_to_lua_push(resultset[i].type); if (resultset[i].lua_type == LUA_PUSH_STRING) buflen += (resultset[i].size + 1 + 3) & ~3; } if (buflen > 0) buffer = malloc(buflen); for (i = 0; i < statement->num_result_columns; i++) { switch (resultset[i].lua_type) { case LUA_PUSH_INTEGER: sqlctype = SQL_C_LONG; dataptr = &resultset[i].data.integer; datalen = 0; break; case LUA_PUSH_NUMBER: sqlctype = SQL_C_DOUBLE; dataptr = &resultset[i].data.number; datalen = 0; break; default: sqlctype = SQL_C_CHAR; resultset[i].data.str = buffer; dataptr = buffer; datalen = resultset[i].size + 1; buffer += (datalen + 3) & ~3; break; } rc = SQLBindCol(stmt, (SQLSMALLINT)(i + 1), sqlctype, dataptr, datalen, &resultset[i].actual_len); if (rc != SQL_SUCCESS) { db2_stmt_diag(stmt, message, sizeof(message)); lua_pushnil(L); lua_pushfstring(L, DBI_ERR_ALLOC_RESULT, message); return 2; } } statement->resultset = resultset; } luaL_getmetatable(L, DBD_DB2_STATEMENT); lua_setmetatable(L, -2); return 1; } int dbd_db2_statement(lua_State *L) { static const luaL_Reg statement_methods[] = { {"affected", statement_affected}, {"close", statement_close}, {"columns", statement_columns}, {"execute", statement_execute}, {"fetch", statement_fetch}, {"rowcount", statement_rowcount}, {"rows", statement_rows}, {NULL, NULL} }; static const luaL_Reg statement_class_methods[] = { {NULL, NULL} }; dbd_register(L, DBD_DB2_STATEMENT, statement_methods, statement_class_methods, statement_gc, statement_tostring); return 1; } luadbi-0.7.2/dbd/mysql/000077500000000000000000000000001341705430500146605ustar00rootroot00000000000000luadbi-0.7.2/dbd/mysql/connection.c000066400000000000000000000125061341705430500171670ustar00rootroot00000000000000#include "dbd_mysql.h" int dbd_mysql_statement_create(lua_State *L, connection_t *conn, const char *sql_query); /* * connection,err = DBD.MySQl.New(dbname, user, password, host, port) */ static int connection_new(lua_State *L) { int n = lua_gettop(L); connection_t *conn = NULL; const char *host = NULL; const char *user = NULL; const char *password = NULL; const char *db = NULL; int port = 0; const char *unix_socket = NULL; int client_flag = 0; /* TODO always 0, set flags from options table */ /* db, user, password, host, port */ switch (n) { case 5: if (lua_isnil(L, 5) == 0) port = luaL_checkinteger(L, 5); // fallthrough case 4: if (lua_isnil(L, 4) == 0) host = luaL_checkstring(L, 4); if (host != NULL) { if (host[0] == '/') { unix_socket = host; host = NULL; }; }; // fallthrough case 3: if (lua_isnil(L, 3) == 0) password = luaL_checkstring(L, 3); // fallthrough case 2: if (lua_isnil(L, 2) == 0) user = luaL_checkstring(L, 2); // fallthrough case 1: /* * db is the only mandatory parameter */ db = luaL_checkstring(L, 1); // fallthrough } conn = (connection_t *)lua_newuserdata(L, sizeof(connection_t)); conn->mysql = mysql_init(NULL); if (!mysql_real_connect(conn->mysql, host, user, password, db, port, unix_socket, client_flag)) { lua_pushnil(L); lua_pushfstring(L, DBI_ERR_CONNECTION_FAILED, mysql_error(conn->mysql)); return 2; } /* * by default turn off autocommit */ mysql_autocommit(conn->mysql, 0); luaL_getmetatable(L, DBD_MYSQL_CONNECTION); lua_setmetatable(L, -2); return 1; } /* * success = connection:autocommit(on) */ static int connection_autocommit(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_MYSQL_CONNECTION); int on = lua_toboolean(L, 2); int err = 0; if (conn->mysql) { err = mysql_autocommit(conn->mysql, on); } lua_pushboolean(L, !err); return 1; } /* * success = connection:close() */ static int connection_close(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_MYSQL_CONNECTION); int disconnect = 0; if (conn->mysql) { mysql_close(conn->mysql); disconnect = 1; conn->mysql = NULL; } lua_pushboolean(L, disconnect); return 1; } /* * success = connection:commit() */ static int connection_commit(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_MYSQL_CONNECTION); int err = 0; if (conn->mysql) { err = mysql_commit(conn->mysql); } lua_pushboolean(L, !err); return 1; } /* * ok = connection:ping() */ static int connection_ping(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_MYSQL_CONNECTION); int err = 1; if (conn->mysql) { err = mysql_ping(conn->mysql); } lua_pushboolean(L, !err); return 1; } /* * statement,err = connection:prepare(sql_string) */ static int connection_prepare(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_MYSQL_CONNECTION); if (conn->mysql) { return dbd_mysql_statement_create(L, conn, luaL_checkstring(L, 2)); } lua_pushnil(L); lua_pushstring(L, DBI_ERR_DB_UNAVAILABLE); return 2; } /* * quoted = connection:quote(str) */ static int connection_quote(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_MYSQL_CONNECTION); size_t len; const char *from = luaL_checklstring(L, 2, &len); char *to = (char *)calloc(len*2+1, sizeof(char)); int quoted_len; if (!conn->mysql) { luaL_error(L, DBI_ERR_DB_UNAVAILABLE); } quoted_len = mysql_real_escape_string(conn->mysql, to, from, len); lua_pushlstring(L, to, quoted_len); free(to); return 1; } /* * success = connection:rollback() */ static int connection_rollback(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_MYSQL_CONNECTION); int err = 0; if (conn->mysql) { err = mysql_rollback(conn->mysql); } lua_pushboolean(L, !err); return 1; } /* * last_id = statement:last_id() */ static int connection_lastid(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_MYSQL_CONNECTION); lua_pushinteger(L, mysql_insert_id( conn->mysql )); return 1; } /* * __gc */ static int connection_gc(lua_State *L) { /* always close the connection */ connection_close(L); return 0; } /* * __tostring */ static int connection_tostring(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_MYSQL_CONNECTION); lua_pushfstring(L, "%s: %p", DBD_MYSQL_CONNECTION, conn); return 1; } int dbd_mysql_connection(lua_State *L) { static const luaL_Reg connection_methods[] = { {"autocommit", connection_autocommit}, {"close", connection_close}, {"commit", connection_commit}, {"ping", connection_ping}, {"prepare", connection_prepare}, {"quote", connection_quote}, {"rollback", connection_rollback}, {"last_id", connection_lastid}, {NULL, NULL} }; static const luaL_Reg connection_class_methods[] = { {"New", connection_new}, {NULL, NULL} }; dbd_register(L, DBD_MYSQL_CONNECTION, connection_methods, connection_class_methods, connection_gc, connection_tostring); return 1; } luadbi-0.7.2/dbd/mysql/dbd_mysql.h000066400000000000000000000012431341705430500170070ustar00rootroot00000000000000#ifdef _MSC_VER /* all MS compilers define this (version) */ #include #endif #include #include #define DBD_MYSQL_CONNECTION "DBD.MySQL.Connection" #define DBD_MYSQL_STATEMENT "DBD.MySQL.Statement" /* * connection object implementation */ typedef struct _connection { MYSQL *mysql; } connection_t; /* * statement object implementation */ typedef struct _statement { connection_t *conn; MYSQL_STMT *stmt; MYSQL_RES *metadata; /* result dataset metadata */ unsigned long *lengths; /* length of retrieved data we have to keep this from bind time to result retrival time */ } statement_t; luadbi-0.7.2/dbd/mysql/main.c000066400000000000000000000004021341705430500157440ustar00rootroot00000000000000#include "dbd_mysql.h" int dbd_mysql_connection(lua_State *L); int dbd_mysql_statement(lua_State *L); /* * library entry point */ LUA_EXPORT int luaopen_dbd_mysql(lua_State *L) { dbd_mysql_statement(L); dbd_mysql_connection(L); return 1; } luadbi-0.7.2/dbd/mysql/statement.c000066400000000000000000000347531341705430500170440ustar00rootroot00000000000000#include "dbd_mysql.h" static lua_push_type_t mysql_to_lua_push(unsigned int mysql_type) { lua_push_type_t lua_type; switch(mysql_type) { case MYSQL_TYPE_NULL: lua_type = LUA_PUSH_NIL; break; case MYSQL_TYPE_TINY: case MYSQL_TYPE_YEAR: case MYSQL_TYPE_SHORT: case MYSQL_TYPE_INT24: case MYSQL_TYPE_LONG: lua_type = LUA_PUSH_INTEGER; break; case MYSQL_TYPE_FLOAT: case MYSQL_TYPE_DOUBLE: case MYSQL_TYPE_LONGLONG: lua_type = LUA_PUSH_NUMBER; break; default: lua_type = LUA_PUSH_STRING; } return lua_type; } static size_t mysql_buffer_size(MYSQL_FIELD *field) { unsigned int mysql_type = field->type; size_t size = 0; switch (mysql_type) { case MYSQL_TYPE_TINY: size = 1; break; case MYSQL_TYPE_YEAR: case MYSQL_TYPE_SHORT: size = 2; break; case MYSQL_TYPE_INT24: size = 4; break; case MYSQL_TYPE_LONG: size = 4; break; case MYSQL_TYPE_LONGLONG: size = 8; break; case MYSQL_TYPE_FLOAT: size = 4; break; case MYSQL_TYPE_DOUBLE: size = 8; break; case MYSQL_TYPE_TIME: case MYSQL_TYPE_DATE: case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_TIMESTAMP: size = sizeof(MYSQL_TIME); break; default: size = field->length; } return size; } /* * num_affected_rows = statement:affected() */ static int statement_affected(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_MYSQL_STATEMENT); if (!statement->stmt) { luaL_error(L, DBI_ERR_INVALID_STATEMENT); } lua_pushinteger(L, mysql_stmt_affected_rows(statement->stmt)); return 1; } /* * success = statement:close() */ static int statement_close(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_MYSQL_STATEMENT); if (statement->metadata) { mysql_free_result(statement->metadata); statement->metadata = NULL; } if (statement->lengths) { free(statement->lengths); statement->lengths = NULL; } if (statement->stmt) { mysql_stmt_close(statement->stmt); statement->stmt = NULL; } lua_pushboolean(L, 1); return 1; } /* * column_names = statement:columns() */ static int statement_columns(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_MYSQL_STATEMENT); MYSQL_FIELD *fields; int i; int num_columns; int d = 1; if (!statement->stmt) { luaL_error(L, DBI_ERR_INVALID_STATEMENT); return 0; } fields = mysql_fetch_fields(statement->metadata); num_columns = mysql_num_fields(statement->metadata); lua_newtable(L); for (i = 0; i < num_columns; i++) { const char *name = fields[i].name; LUA_PUSH_ARRAY_STRING(d, name); } return 1; } /* * success,err = statement:execute(...) */ static int statement_execute(lua_State *L) { int n = lua_gettop(L); statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_MYSQL_STATEMENT); int num_bind_params = n - 1; int expected_params; unsigned char *buffer = NULL; int offset = 0; MYSQL_BIND *bind = NULL; MYSQL_RES *metadata = NULL; char *error_message = NULL; char *errstr = NULL; int p; /* * Sanity check(s) */ if (statement->conn->mysql == NULL) { lua_pushstring(L, DBI_ERR_STATEMENT_BROKEN); lua_error(L); } if (statement->metadata) { /* * free existing metadata from any previous executions */ mysql_free_result(statement->metadata); statement->metadata = NULL; } if (!statement->stmt) { lua_pushboolean(L, 0); lua_pushstring(L, DBI_ERR_EXECUTE_INVALID); return 2; } expected_params = mysql_stmt_param_count(statement->stmt); if (expected_params != num_bind_params) { /* * mysql_stmt_bind_param does not handle this condition, * and the client library will segfault if these do no match */ lua_pushboolean(L, 0); lua_pushfstring(L, DBI_ERR_PARAM_MISCOUNT, expected_params, num_bind_params); return 2; } if (num_bind_params > 0) { bind = malloc(sizeof(MYSQL_BIND) * num_bind_params); if (bind == NULL) { luaL_error(L, "Could not alloc bind params\n"); } buffer = (unsigned char *)malloc(num_bind_params * sizeof(double)); memset(bind, 0, sizeof(MYSQL_BIND) * num_bind_params); } for (p = 2; p <= n; p++) { int type = lua_type(L, p); int i = p - 2; const char *str = NULL; size_t *str_len = NULL; double *num = NULL; int *boolean = NULL; char err[64]; switch(type) { case LUA_TNIL: bind[i].buffer_type = MYSQL_TYPE_NULL; bind[i].is_null = (int*)1; break; case LUA_TBOOLEAN: boolean = (int *)(buffer + offset); offset += sizeof(int); *boolean = lua_toboolean(L, p); bind[i].buffer_type = MYSQL_TYPE_LONG; bind[i].is_null = (int*)0; bind[i].buffer = (char *)boolean; bind[i].length = 0; break; case LUA_TNUMBER: /* * num needs to be it's own * memory here */ num = (double *)(buffer + offset); offset += sizeof(double); *num = lua_tonumber(L, p); bind[i].buffer_type = MYSQL_TYPE_DOUBLE; bind[i].is_null = (int*)0; bind[i].buffer = (char *)num; bind[i].length = 0; break; case LUA_TSTRING: str_len = (size_t *)(buffer + offset); offset += sizeof(size_t); str = lua_tolstring(L, p, str_len); bind[i].buffer_type = MYSQL_TYPE_STRING; bind[i].is_null = (int*)0; bind[i].buffer = (char *)str; bind[i].length = str_len; break; default: snprintf(err, sizeof(err)-1, DBI_ERR_BINDING_TYPE_ERR, lua_typename(L, type)); errstr = err; error_message = DBI_ERR_BINDING_PARAMS; goto cleanup; } } if (mysql_stmt_bind_param(statement->stmt, bind)) { error_message = DBI_ERR_BINDING_PARAMS; goto cleanup; } if (mysql_stmt_execute(statement->stmt)) { error_message = DBI_ERR_BINDING_EXEC; goto cleanup; } metadata = mysql_stmt_result_metadata(statement->stmt); if (metadata) { mysql_stmt_store_result(statement->stmt); } cleanup: if (bind) { free(bind); } if (buffer) { free(buffer); } if (error_message) { lua_pushboolean(L, 0); lua_pushfstring(L, error_message, errstr ? errstr : mysql_stmt_error(statement->stmt)); return 2; } statement->metadata = metadata; lua_pushboolean(L, 1); return 1; } static int statement_fetch_impl(lua_State *L, statement_t *statement, int named_columns) { int column_count, fetch_result_ok; MYSQL_BIND *bind = NULL; const char *error_message = NULL; if (!statement->stmt) { luaL_error(L, DBI_ERR_FETCH_INVALID); return 0; } if (!statement->metadata) { luaL_error(L, DBI_ERR_FETCH_NO_EXECUTE); return 0; } column_count = mysql_num_fields(statement->metadata); if (column_count > 0) { int i; MYSQL_FIELD *fields; if (statement->lengths) { free(statement->lengths); statement->lengths = NULL; } statement->lengths = calloc(column_count, sizeof(unsigned long)); bind = malloc(sizeof(MYSQL_BIND) * column_count); memset(bind, 0, sizeof(MYSQL_BIND) * column_count); fields = mysql_fetch_fields(statement->metadata); for (i = 0; i < column_count; i++) { unsigned int length = mysql_buffer_size(&fields[i]); if (length > sizeof(MYSQL_TIME)) { bind[i].buffer = NULL; bind[i].buffer_length = 0; } else { char *buffer = (char *)malloc(length); memset(buffer, 0, length); bind[i].buffer = buffer; bind[i].buffer_length = length; } bind[i].buffer_type = fields[i].type; bind[i].length = &(statement->lengths[i]); } if (mysql_stmt_bind_result(statement->stmt, bind)) { error_message = DBI_ERR_BINDING_RESULTS; goto cleanup; } fetch_result_ok = mysql_stmt_fetch(statement->stmt); if (fetch_result_ok == 0 || fetch_result_ok == MYSQL_DATA_TRUNCATED) { int d = 1; lua_newtable(L); for (i = 0; i < column_count; i++) { lua_push_type_t lua_push = mysql_to_lua_push(fields[i].type); const char *name = fields[i].name; if (bind[i].buffer == NULL) { char *buffer = (char *)calloc(statement->lengths[i]+1, sizeof(char)); bind[i].buffer = buffer; bind[i].buffer_length = statement->lengths[i]; mysql_stmt_fetch_column(statement->stmt, &bind[i], i, 0); } 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) { if (fields[i].type == MYSQL_TYPE_YEAR || fields[i].type == MYSQL_TYPE_SHORT) { if (named_columns) { LUA_PUSH_ATTRIB_INT(name, *(short *)(bind[i].buffer)); } else { LUA_PUSH_ARRAY_INT(d, *(short *)(bind[i].buffer)); } } else if (fields[i].type == MYSQL_TYPE_TINY) { if (named_columns) { LUA_PUSH_ATTRIB_INT(name, (int)*(char *)(bind[i].buffer)); } else { LUA_PUSH_ARRAY_INT(d, (int)*(char *)(bind[i].buffer)); } } else { if (named_columns) { LUA_PUSH_ATTRIB_INT(name, *(int *)(bind[i].buffer)); } else { LUA_PUSH_ARRAY_INT(d, *(int *)(bind[i].buffer)); } } } else if (lua_push == LUA_PUSH_NUMBER) { if (fields[i].type == MYSQL_TYPE_FLOAT) { if (named_columns) { LUA_PUSH_ATTRIB_FLOAT(name, *(float *)(bind[i].buffer)); } else { LUA_PUSH_ARRAY_FLOAT(d, *(float *)(bind[i].buffer)); } } else if (fields[i].type == MYSQL_TYPE_DOUBLE) { if (named_columns) { LUA_PUSH_ATTRIB_FLOAT(name, *(double *)(bind[i].buffer)); } else { LUA_PUSH_ARRAY_FLOAT(d, *(double *)(bind[i].buffer)); } } else { if (named_columns) { LUA_PUSH_ATTRIB_FLOAT(name, *(long long *)(bind[i].buffer)); } else { LUA_PUSH_ARRAY_FLOAT(d, *(long long *)(bind[i].buffer)); } } } else if (lua_push == LUA_PUSH_STRING) { if (fields[i].type == MYSQL_TYPE_TIMESTAMP || fields[i].type == MYSQL_TYPE_DATETIME) { char str[20]; struct st_mysql_time *t = bind[i].buffer; snprintf(str, 20, "%d-%02d-%02d %02d:%02d:%02d", t->year, t->month, t->day, t->hour, t->minute, t->second); if (named_columns) { LUA_PUSH_ATTRIB_STRING(name, str); } else { LUA_PUSH_ARRAY_STRING(d, str); } } else if (fields[i].type == MYSQL_TYPE_TIME) { char str[9]; struct st_mysql_time *t = bind[i].buffer; snprintf(str, 9, "%02d:%02d:%02d", t->hour, t->minute, t->second); if (named_columns) { LUA_PUSH_ATTRIB_STRING(name, str); } else { LUA_PUSH_ARRAY_STRING(d, str); } } else if (fields[i].type == MYSQL_TYPE_DATE) { char str[20]; struct st_mysql_time *t = bind[i].buffer; snprintf(str, 11, "%d-%02d-%02d", t->year, t->month, t->day); if (named_columns) { LUA_PUSH_ATTRIB_STRING(name, str); } else { LUA_PUSH_ARRAY_STRING(d, str); } } else { if (named_columns) { LUA_PUSH_ATTRIB_STRING_BY_LENGTH(name, bind[i].buffer, *bind[i].length); } else { LUA_PUSH_ARRAY_STRING_BY_LENGTH(d, bind[i].buffer, *bind[i].length); } } } else if (lua_push == LUA_PUSH_BOOLEAN) { if (named_columns) { LUA_PUSH_ATTRIB_BOOL(name, *(int *)(bind[i].buffer)); } else { LUA_PUSH_ARRAY_BOOL(d, *(int *)(bind[i].buffer)); } } else { luaL_error(L, DBI_ERR_UNKNOWN_PUSH); } } } else { lua_pushnil(L); } } cleanup: if (bind) { int i; for (i = 0; i < column_count; i++) { free(bind[i].buffer); } free(bind); } if (error_message) { luaL_error(L, error_message, mysql_stmt_error(statement->stmt)); return 0; } return 1; } static int next_iterator(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, lua_upvalueindex(1), DBD_MYSQL_STATEMENT); int named_columns = lua_toboolean(L, lua_upvalueindex(2)); return statement_fetch_impl(L, statement, named_columns); } /* * table = statement:fetch(named_indexes) */ static int statement_fetch(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_MYSQL_STATEMENT); int named_columns = lua_toboolean(L, 2); return statement_fetch_impl(L, statement, named_columns); } /* * num_rows = statement:rowcount() */ static int statement_rowcount(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_MYSQL_STATEMENT); if (!statement->stmt) { luaL_error(L, DBI_ERR_INVALID_STATEMENT); } lua_pushinteger(L, mysql_stmt_num_rows(statement->stmt)); return 1; } /* * iterfunc = statement:rows(named_indexes) */ static int statement_rows(lua_State *L) { if (lua_gettop(L) == 1) { lua_pushvalue(L, 1); lua_pushboolean(L, 0); } else { lua_pushvalue(L, 1); lua_pushboolean(L, lua_toboolean(L, 2)); } lua_pushcclosure(L, next_iterator, 2); return 1; } /* * __gc */ static int statement_gc(lua_State *L) { /* always free the handle */ statement_close(L); return 0; } /* * __tostring */ static int statement_tostring(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_MYSQL_STATEMENT); lua_pushfstring(L, "%s: %p", DBD_MYSQL_STATEMENT, statement); return 1; } int dbd_mysql_statement_create(lua_State *L, connection_t *conn, const char *sql_query) { unsigned long sql_len = strlen(sql_query); statement_t *statement = NULL; MYSQL_STMT *stmt = mysql_stmt_init(conn->mysql); if (!stmt) { lua_pushnil(L); lua_pushfstring(L, DBI_ERR_ALLOC_STATEMENT, mysql_error(conn->mysql)); return 2; } if (mysql_stmt_prepare(stmt, sql_query, sql_len)) { lua_pushnil(L); lua_pushfstring(L, DBI_ERR_PREP_STATEMENT, mysql_stmt_error(stmt)); return 2; } statement = (statement_t *)lua_newuserdata(L, sizeof(statement_t)); statement->conn = conn; statement->stmt = stmt; statement->metadata = NULL; statement->lengths = NULL; /* mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (int*)0); */ luaL_getmetatable(L, DBD_MYSQL_STATEMENT); lua_setmetatable(L, -2); return 1; } int dbd_mysql_statement(lua_State *L) { static const luaL_Reg statement_methods[] = { {"affected", statement_affected}, {"close", statement_close}, {"columns", statement_columns}, {"execute", statement_execute}, {"fetch", statement_fetch}, {"rowcount", statement_rowcount}, {"rows", statement_rows}, {NULL, NULL} }; static const luaL_Reg statement_class_methods[] = { {NULL, NULL} }; dbd_register(L, DBD_MYSQL_STATEMENT, statement_methods, statement_class_methods, statement_gc, statement_tostring); return 1; } luadbi-0.7.2/dbd/oracle/000077500000000000000000000000001341705430500147605ustar00rootroot00000000000000luadbi-0.7.2/dbd/oracle/connection.c000066400000000000000000000411601341705430500172650ustar00rootroot00000000000000#include "dbd_oracle.h" struct _oracleconst { const char *name; int val; }; static const struct _oracleconst constants[] = { { "OCI_FO_END", OCI_FO_END }, { "OCI_FO_ABORT", OCI_FO_ABORT }, { "OCI_FO_REAUTH", OCI_FO_REAUTH }, { "OCI_FO_BEGIN", OCI_FO_BEGIN }, { "OCI_FO_ERROR", OCI_FO_ERROR }, { "OCI_FO_RETRY", OCI_FO_RETRY }, { "OCI_FO_NONE", OCI_FO_NONE }, { "OCI_FO_SESSION", OCI_FO_SESSION }, { "OCI_FO_SELECT", OCI_FO_SELECT }, { "OCI_FO_TXNAL", OCI_FO_TXNAL }, { NULL, 0 } }; int dbd_oracle_statement_create(lua_State *L, connection_t *conn, const char *sql_query); static int commit(connection_t *conn) { int rc = OCITransCommit(conn->svc, conn->err, OCI_DEFAULT); return rc; } static int rollback(connection_t *conn) { int rc = OCITransRollback(conn->svc, conn->err, OCI_DEFAULT); return rc; } #ifdef ORA_ENABLE_TAF static sb4 taf_cbk(svchp, envhp, fo_ctx, fo_type, fo_event ) dvoid * svchp; dvoid * envhp; dvoid *fo_ctx; ub4 fo_type; ub4 fo_event; { /* fo_ctx is our 'conn' struct. */ connection_t *conn = (connection_t *)fo_ctx; /* If we haven't registered a callback, then we're done. */ if (!conn->cbfuncidx) return 0; /* Otherwise, call the callback with whatever we're being told; get * the return value; and process it appropriately. We expect a * single boolean return value, which defines whether or not we * should interrupt the normal flow. Returning a false value will * continue normally; returning a true value will cause us to return * OCI_FO_RETRY (currently, the only interrupt flag that the Oracle * API supports). * * We pass these integer arguments to the callback function: * - fo_type (OCI_FO_NONE, OCI_FO_SESSION, OCI_FO_SELECT, OCI_FO_TXNAL * - fo_event (OCI_FO_BEGIN, OCI_FO_ABORT, OCI_FO_END, OCI_FO_REAUTH * And an optional callback context argument, if one was provided. * * We expect one boolean in return. If it returns no values at all, * we'll raise an exception. */ lua_State *L = conn->L; /* Find the callback function and set up its arguments */ lua_rawgeti(L, LUA_REGISTRYINDEX, conn->cbfuncidx); lua_pushinteger(L, fo_type); lua_pushinteger(L, fo_event); if (conn->cbargidx) { lua_rawgeti(L, LUA_REGISTRYINDEX, conn->cbargidx); } else { lua_pushnil(L); } lua_call(L, 3, 1); int retval = lua_toboolean(L, -1); lua_pop(L, 1); if (retval) return OCI_FO_RETRY; return 0; } #endif static void RaiseErrorOnFailure(lua_State *L, int statusCode, OCIError *errhp, const char *msg) { char errbuf[100]; int errcode; switch (statusCode) { case OCI_SUCCESS: case OCI_SUCCESS_WITH_INFO: return; case OCI_NEED_DATA: strcpy(errbuf, "OCI_NEED_DATA"); break; case OCI_NO_DATA: strcpy(errbuf, "OCI_NO_DATA"); break; case OCI_ERROR: OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, (text *)errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); break; case OCI_INVALID_HANDLE: strcpy(errbuf, "OCI_INVALID_HANDLE"); break; case OCI_STILL_EXECUTING: strcpy(errbuf, "OCI_STILL_EXECUTE"); break; case OCI_CONTINUE: strcpy(errbuf, "OCI_CONTINUE"); break; default: strcpy(errbuf, "Unknown OCI error"); break; } luaL_error(L, "%s: %s", msg, errbuf); } /* * connection,err = DBD.Oracle.New(dbfile) */ static int connection_new(lua_State *L) { int n = lua_gettop(L); int rc = 0; const char *user = NULL; const char *password = NULL; const char *db = NULL; /* This code leaks many of these if there are errors setting up * the initial connection. FIXME: address this. */ OCIEnv *env = NULL; OCIError *err = NULL; OCISvcCtx *svc = NULL; OCIServer *svr = NULL; OCISession *sess = NULL; connection_t *conn = NULL; /* db, user, password */ switch(n) { case 5: case 4: case 3: if (lua_isnil(L, 3) == 0) password = luaL_checkstring(L, 3); case 2: if (lua_isnil(L, 2) == 0) user = luaL_checkstring(L, 2); case 1: /* * db is the only mandatory parameter */ db = luaL_checkstring(L, 1); } /* * initialise OCI * * Much of this connection mechanism comes directly from oracle: * http://www.oracle.com/technetwork/database/windows/fscawp32-130265.pdf */ OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, (dvoid * (*)(dvoid *, size_t))0, (dvoid * (*)(dvoid *, dvoid *, size_t))0, (void (*)(dvoid *, dvoid *))0); /* * initialise environment */ OCIEnvNlsCreate((OCIEnv **)&env, OCI_DEFAULT, 0, NULL, NULL, NULL, 0, 0, 0, 0); /* * server contexts */ OCIHandleAlloc((dvoid *)env, (dvoid **)&err, OCI_HTYPE_ERROR, 0, (dvoid **)0); OCIHandleAlloc((dvoid *)env, (dvoid **)&svc, OCI_HTYPE_SVCCTX, 0, (dvoid **)0); OCIHandleAlloc((dvoid *)env, (dvoid **)&svr, OCI_HTYPE_SERVER, 0, (dvoid **)0); OCIAttrSet(svc, OCI_HTYPE_SVCCTX, svr, (ub4) 0, OCI_ATTR_SERVER, err); OCIHandleAlloc((dvoid *)env, (dvoid**)&sess, OCI_HTYPE_SESSION, 0, (dvoid **)0); rc = OCIAttrSet((dvoid *)sess, (ub4)OCI_HTYPE_SESSION, (dvoid *)user, (ub4)strlen(user), (ub4) OCI_ATTR_USERNAME, err); RaiseErrorOnFailure(L, rc, err, "setting username"); rc = OCIAttrSet((dvoid *)sess, (ub4)OCI_HTYPE_SESSION, (dvoid *)password, (ub4)strlen(password), (ub4) OCI_ATTR_PASSWORD, err); RaiseErrorOnFailure(L, rc, err, "setting password"); rc = OCIServerAttach((OCIServer *)svr, (OCIError *)err, (CONST text *)db, (sb4)strlen(db), (ub4)0); RaiseErrorOnFailure(L, rc, err, "setting server instance"); rc = OCISessionBegin(svc, err, sess, OCI_CRED_RDBMS, (ub4) OCI_DEFAULT); RaiseErrorOnFailure(L, rc, err, "logging in"); rc = OCIAttrSet(svc, OCI_HTYPE_SVCCTX, sess, (ub4) 0, OCI_ATTR_SESSION, err); if (rc != OCI_SUCCESS) { char errbuf[100]; int errcode; OCIErrorGet ((dvoid *) err, (ub4) 1, (text *) NULL, (sb4 *)&errcode, (text *)errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); lua_pushnil(L); lua_pushfstring(L, DBI_ERR_CONNECTION_FAILED, errbuf); return 2; } /* We'll need the connection info for the TAF callback, so the * struct needs to be created here and initialized, in case TAF * gets invoked during login. */ conn = (connection_t *)lua_newuserdata(L, sizeof(connection_t)); conn->oracle = env; conn->err = err; conn->svc = svc; conn->svr = svr; conn->autocommit = 0; conn->prefetch_mem = 1024 * 1024; conn->prefetch_rows = 1000000; conn->cbfuncidx = 0; #ifdef ORA_ENABLE_TAF /* Register a callback for TAF events. This is a stub, so the user doesn't have to set the callback until after they've connected (the Oracle API requires that we set it before we connect). If the app doesn't support TAF ... well, I might have to rethink this. */ OCIFocbkStruct FailoverInfo; FailoverInfo.fo_ctx = conn; FailoverInfo.callback_function = taf_cbk; rc = OCIAttrSet(svr, (ub4) OCI_HTYPE_SERVER, (dvoid *) &FailoverInfo, (ub4) 0, OCI_ATTR_FOCBK, err); RaiseErrorOnFailure(L, rc, err, "registering TAF callback"); #endif conn->L = L; /* Get the remote database version */ text vbuf[256]; ub4 vnum; rc = OCIServerRelease(svc, err, vbuf, sizeof(vbuf), OCI_HTYPE_SVCCTX, &vnum); conn->vnum = vnum; /* Get default character set info */ size_t rsize = 0; rc = OCINlsEnvironmentVariableGet(&conn->charsetid,(size_t) 0, OCI_NLS_CHARSET_ID, 0, &rsize); rc = OCINlsEnvironmentVariableGet(&conn->ncharsetid, (size_t) 0, OCI_NLS_NCHARSET_ID, 0, &rsize); luaL_getmetatable(L, DBD_ORACLE_CONNECTION); lua_setmetatable(L, -2); return 1; } /* * success = connection:autocommit(on) */ static int connection_autocommit(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_ORACLE_CONNECTION); int on = lua_toboolean(L, 2); int err = 1; if (conn->oracle) { if (on) rollback(conn); conn->autocommit = on; err = 0; } lua_pushboolean(L, !err); return 1; } /* * success = connection:close() */ static int connection_close(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_ORACLE_CONNECTION); int disconnect = 0; if (conn->oracle) { rollback(conn); OCILogoff(conn->svc, conn->err); if (conn->svc) OCIHandleFree((dvoid *)conn->svc, OCI_HTYPE_ENV); if (conn->err) OCIHandleFree((dvoid *)conn->err, OCI_HTYPE_ERROR); if (conn->srv) OCIHandleFree((dvoid *)conn->svr, OCI_HTYPE_SERVER); if (conn->cbfuncidx) luaL_unref(L, LUA_REGISTRYINDEX, conn->cbfuncidx); if (conn->cbargidx) luaL_unref(L, LUA_REGISTRYINDEX, conn->cbargidx); disconnect = 1; conn->oracle = NULL; } lua_pushboolean(L, disconnect); return 1; } /* * success = connection:commit() */ static int connection_commit(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_ORACLE_CONNECTION); int err = 1; if (conn->oracle) { err = commit(conn); } lua_pushboolean(L, !err); return 1; } /* * ok = connection:ping() */ static int connection_ping(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_ORACLE_CONNECTION); int ok = 0; if (conn->oracle) { /* Not all Oracle client libraries have OCIPing, and it's pretty * much impossible to tell which client version is installed * programmatically. Rely on a compile-time decision by the * operator. */ int rc; if ( #ifndef ORA_ENABLE_PING 1 || #endif (MAJOR_NUMVSN(conn->vnum) < 10) || (MAJOR_NUMVSN(conn->vnum) == 10 && MINOR_NUMRLS(conn->vnum) < 2) ) { // client or server does not support ping; query the version number as a no-op text vbuf[2]; // we're just discarding this; give it one char + a null terminator space ub4 vnum; rc = OCIServerRelease(conn->svc, conn->err, vbuf, sizeof(vbuf), OCI_HTYPE_SVCCTX, &vnum); } else { #ifdef ORA_ENABLE_PING rc = OCIPing(conn->svc, conn->err, OCI_DEFAULT); #endif } ok = (rc == OCI_SUCCESS); } lua_pushboolean(L, ok); return 1; } /* * statement,err = connection:prepare(sql_str) */ static int connection_prepare(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_ORACLE_CONNECTION); if (conn->oracle) { return dbd_oracle_statement_create(L, conn, luaL_checkstring(L, 2)); } lua_pushnil(L); lua_pushstring(L, DBI_ERR_DB_UNAVAILABLE); return 2; } /* * quoted = connection:quote(str) */ static int connection_quote(lua_State *L) { luaL_error(L, DBI_ERR_NOT_IMPLEMENTED, DBD_ORACLE_CONNECTION, "quote"); return 0; } /* * success = connection:rollback() */ static int connection_rollback(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_ORACLE_CONNECTION); int err = 1; if (conn->oracle) { err = rollback(conn); } lua_pushboolean(L, !err); return 1; } /* * last_id = connection:last_id() */ static int connection_lastid(lua_State *L) { luaL_error(L, DBI_ERR_NOT_IMPLEMENTED, DBD_ORACLE_CONNECTION, "last_id"); return 0; } /* * version = connection:version() */ static int connection_version(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_ORACLE_CONNECTION); lua_pushinteger(L, conn->vnum); return 1; } /* * rows = connection:prefetch_rows(optional new_rows) * * Sets the prefetch cache row limit (in rows); default 1 million. * Disable by setting to 0 before creating a statement handle. */ static int connection_prefetch_rows(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_ORACLE_CONNECTION); if (lua_gettop(L) == 2) { // A number may be passed in if we want to set the value conn->prefetch_rows = lua_tointeger(L, 2); } lua_pushinteger(L, conn->prefetch_rows); return 1; } /* * mem = connection:prefetch_mem(optional new_mem) * * Sets the prefetch cache memory limit (in bytes); default 1024Kb. * Disable by setting to 0 before creating a statement handle. */ static int connection_prefetch_mem(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_ORACLE_CONNECTION); if (lua_gettop(L) == 2) { // A number may be passed in if we want to set the value conn->prefetch_mem = lua_tointeger(L, 2); } lua_pushinteger(L, conn->prefetch_mem); return 1; } /* * charset = connection:charset() */ static int connection_charset(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_ORACLE_CONNECTION); if (lua_gettop(L) == 2) { // A number may be passed in if we want to set the value conn->charsetid = lua_tointeger(L, 2); } lua_pushinteger(L, conn->charsetid); return 1; } /* * ncharset = connection:ncharset() */ static int connection_ncharset(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_ORACLE_CONNECTION); if (lua_gettop(L) == 2) { // A number may be passed in if we want to set the value conn->ncharsetid = lua_tointeger(L, 2); } lua_pushinteger(L, conn->ncharsetid); return 1; } /* * __gc */ static int connection_gc(lua_State *L) { /* always close the connection */ connection_close(L); return 0; } /* * __tostring */ static int connection_tostring(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_ORACLE_CONNECTION); lua_pushfstring(L, "%s: %p", DBD_ORACLE_CONNECTION, conn); return 1; } /* * bool = connection:taf_available() */ static int connection_taf_available(lua_State *L) { #ifdef ORA_ENABLE_TAF connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_ORACLE_CONNECTION); int rc = -1; ub4 can_taf = 0xFFFF; ub4 ct_size = sizeof(can_taf); if (conn->oracle) { rc = OCIAttrGet((CONST dvoid *)conn->svr, (ub4)OCI_HTYPE_SERVER, (dvoid *)&can_taf, (ub4 *)&ct_size, (ub4)OCI_ATTR_TAF_ENABLED, (OCIError *)conn->err); RaiseErrorOnFailure(L, rc, conn->err, "checking TAF"); } lua_pushboolean(L, (rc == OCI_SUCCESS) && can_taf); #else lua_pushboolean(L, 0); #endif return 1; } /* * connection:taf_callback(cb, arg) * * sets a callback for Oracle Transparent Application Failover events. * 'arg' is optional, but is passed to the callback if provided. */ static int connection_taf_callback(lua_State *L) { #ifdef ORA_ENABLE_TAF connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_ORACLE_CONNECTION); if ((lua_gettop(L) != 2 && lua_gettop(L) != 3) || !lua_isfunction(L, 2)) { luaL_error(L, "Wrong number or incorrect type of arguments to taf_callback(func, arg)"); } /* Release any previous callback if we had one */ if (conn->cbfuncidx) { luaL_unref(L, LUA_REGISTRYINDEX, conn->cbfuncidx); conn->cbfuncidx = 0; } if (conn->cbargidx) { luaL_unref(L, LUA_REGISTRYINDEX, conn->cbargidx); conn->cbargidx = 0; } /* Store the callback in the global Lua registry */ lua_pushvalue(L, 2); conn->cbfuncidx = luaL_ref(L, LUA_REGISTRYINDEX); conn->L = L; if (lua_gettop(L) == 3) { /* Store the callback argument too */ lua_pushvalue(L, 3); conn->cbargidx = luaL_ref(L, LUA_REGISTRYINDEX); } #endif return 0; } int dbd_oracle_connection(lua_State *L) { /* * instance methods */ static const luaL_Reg connection_methods[] = { {"autocommit", connection_autocommit}, {"close", connection_close}, {"commit", connection_commit}, {"ping", connection_ping}, {"prepare", connection_prepare}, {"quote", connection_quote}, {"rollback", connection_rollback}, {"last_id", connection_lastid}, // Oracle-specific methods {"version", connection_version}, {"prefetch_rows", connection_prefetch_rows}, {"prefetch_mem", connection_prefetch_mem}, {"charset", connection_charset}, {"ncharset", connection_ncharset}, {"taf_available", connection_taf_available}, {"taf_callback", connection_taf_callback}, {NULL, NULL} }; /* * class methods */ static const luaL_Reg connection_class_methods[] = { {"New", connection_new}, {NULL, NULL} }; dbd_register(L, DBD_ORACLE_CONNECTION, connection_methods, connection_class_methods, connection_gc, connection_tostring); /* Register Oracle constants in our new metatable */ luaL_getmetatable(L, DBD_ORACLE_CONNECTION); const struct _oracleconst *p = constants; while (p->name) { lua_pushstring(L, p->name); lua_pushinteger(L, p->val); lua_rawset(L, -3); p++; } lua_pop(L, 1); return 1; } luadbi-0.7.2/dbd/oracle/dbd_oracle.h000066400000000000000000000031421341705430500172070ustar00rootroot00000000000000#include #include #define DBD_ORACLE_CONNECTION "DBD.Oracle.Connection" #define DBD_ORACLE_STATEMENT "DBD.Oracle.Statement" /* Oracle macros to parse version number, per * https://docs.oracle.com/en/database/oracle/oracle-database/12.2/lnoci/miscellaneous-functions.html */ #define MAJOR_NUMVSN(v) ((sword)(((v) >> 24) & 0x000000FF)) /* version number */ #define MINOR_NUMRLS(v) ((sword)(((v) >> 20) & 0x0000000F)) /* release number */ #define UPDATE_NUMUPD(v) ((sword)(((v) >> 12) & 0x000000FF)) /* update number */ #define PORT_REL_NUMPRL(v) ((sword)(((v) >> 8) & 0x0000000F)) /* port release number */ #define PORT_UPDATE_NUMPUP(v) ((sword)(((v) >> 0) & 0x000000FF)) /* port update number */ typedef struct _bindparams { OCIParam *param; text *name; ub4 name_len; ub2 data_type; ub2 max_len; char *data; OCIDefine *define; sb2 null; ub2 ret_len; ub2 ret_err; ub4 csid; ub4 csform; ub2 charset; ub2 ncharset; } bindparams_t; /* * connection object */ typedef struct _connection { OCIEnv *oracle; OCISvcCtx *svc; OCIServer *svr; OCIError *err; OCIServer *srv; OCISession *auth; int autocommit; ub2 charsetid; ub2 ncharsetid; ub4 vnum; ub4 prefetch_mem; ub4 prefetch_rows; int cbfuncidx; int cbargidx; lua_State *L; } connection_t; /* * statement object */ typedef struct _statement { OCIStmt *stmt; connection_t *conn; int num_columns; bindparams_t *bind; int metadata; /* cache handling */ ub4 prefetch_mem; ub4 prefetch_rows; } statement_t; luadbi-0.7.2/dbd/oracle/main.c000066400000000000000000000004121341705430500160450ustar00rootroot00000000000000#include "dbd_oracle.h" int dbd_oracle_connection(lua_State *L); int dbd_oracle_statement(lua_State *L); /* * library entry point */ LUA_EXPORT int luaopen_dbd_oracle(lua_State *L) { dbd_oracle_statement(L); dbd_oracle_connection(L); return 1; } luadbi-0.7.2/dbd/oracle/statement.c000066400000000000000000000431011341705430500171270ustar00rootroot00000000000000#include "dbd_oracle.h" #define ORA_US7ASCII_CSID 1 #define ORA_UTF8_CSID 871 #define ORA_AL32UTF8_CSID 873 #define ORA_UTF16_CSID 2000 #define CS_IS_UTF8( x ) ( ( (x) == ORA_UTF8_CSID ) || ( (x) == ORA_AL32UTF8_CSID ) ) #define CSFORM_IMPLIED_CSID( x,y ) ( ( (x) == SQLCS_NCHAR ) ? y->ncharsetid : y->charsetid ) #define CSFORM_IMPLIES_UTF8( x,y ) ( CS_IS_UTF8( CSFORM_IMPLIED_CSID ( x,y ) ) ) /* * Converts SQLite types to Lua types */ static lua_push_type_t oracle_to_lua_push(unsigned int oracle_type, int null) { lua_push_type_t lua_type; if (null) return LUA_PUSH_NIL; switch(oracle_type) { case SQLT_NUM: case SQLT_FLT: lua_type = LUA_PUSH_NUMBER; break; case SQLT_INT: lua_type = LUA_PUSH_INTEGER; break; default: lua_type = LUA_PUSH_STRING; } return lua_type; } /* * Fetch metadata from the database */ static void statement_fetch_metadata(lua_State *L, statement_t *statement) { bindparams_t *bind; int i; char errbuf[100]; sb4 errcode; int rc; if (statement->metadata) return; #if 0 // staged for later, when we'll pre-check the attribute sizes and // types in order to set up the prefetch cache more intelligently rc = OCIStmtExecute( statement->conn->svc, statement->stmt, statement->conn->err, (ub4)0, // type == OCI_STMT_SELECT ? 0 : 1, (ub4)0, (CONST OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_DESCRIBE_ONLY ); if (rc) { OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, (sb4 *)&errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); luaL_error(L, "describe %s", errbuf); } #endif ub4 prefetch_mem = statement->prefetch_mem; if (prefetch_mem) { if (OCIAttrSet(statement->stmt, OCI_HTYPE_STMT, &prefetch_mem, sizeof(prefetch_mem), OCI_ATTR_PREFETCH_MEMORY, statement->conn->err) != OCI_SUCCESS) { OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, (sb4 *)&errcode, (text *)errbuf, (ub4) sizeof(errbuf), (ub4)OCI_HTYPE_ERROR); luaL_error(L, "prefetch_mem set %s", errbuf); } } ub4 prefetch_rows = statement->prefetch_rows; if (prefetch_rows) { if (OCIAttrSet(statement->stmt, OCI_HTYPE_STMT, &prefetch_rows, sizeof(prefetch_rows), OCI_ATTR_PREFETCH_ROWS, statement->conn->err) != OCI_SUCCESS) { OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, (sb4 *)&errcode, (text *)errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); luaL_error(L, "prefetch_rows set %s", errbuf); } } statement->bind = (bindparams_t *)malloc(sizeof(bindparams_t) * statement->num_columns); memset(statement->bind, 0, sizeof(bindparams_t) * statement->num_columns); bind = statement->bind; for (i = 0; i < statement->num_columns; i++) { rc = OCIParamGet(statement->stmt, OCI_HTYPE_STMT, statement->conn->err, (dvoid **)&bind[i].param, i+1); if (rc) { OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, (sb4 *)&errcode, (text *) errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); luaL_error(L, "param get %s", errbuf); } rc = OCIAttrGet(bind[i].param, OCI_DTYPE_PARAM, (dvoid *)&(bind[i].name), (ub4 *)&(bind[i].name_len), OCI_ATTR_NAME, statement->conn->err); if (rc) { OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, (sb4 *)&errcode, (text *) errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); luaL_error(L, "name get %s", errbuf); } rc = OCIAttrGet(bind[i].param, OCI_DTYPE_PARAM, (dvoid *)&(bind[i].data_type), (ub4 *)0, OCI_ATTR_DATA_TYPE, statement->conn->err); if (rc) { OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, (sb4 *)&errcode, (text *) errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); luaL_error(L, "datatype get %s", errbuf); } rc = OCIAttrGet(bind[i].param, OCI_DTYPE_PARAM, (dvoid *)&(bind[i].max_len), 0, OCI_ATTR_DATA_SIZE, statement->conn->err); if (rc) { OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, (sb4 *)&errcode, (text *) errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); luaL_error(L, "datasize get %s", errbuf); } #ifdef OCI_ATTR_CHARSET_ID rc = OCIAttrGet(bind[i].param, OCI_DTYPE_PARAM, (dvoid *)&bind[i].csid, 0, OCI_ATTR_CHARSET_ID, statement->conn->err); rc = OCIAttrGet(bind[i].param, OCI_DTYPE_PARAM, (dvoid *)&bind[i].csform, 0, OCI_ATTR_CHARSET_FORM, statement->conn->err); #endif switch (bind[i].data_type) { case SQLT_CHR: // VARCHAR2 ("character string") // sometimes o11 returns 0 as the length. Substitute an // arbitrary default. if (bind[i].max_len == 0) { bind[i].max_len = 4000; } /* Fallthrough to UTF8 handling... */ case SQLT_AFC: // CHAR ("ANSI fixed character") /* If the field's charset isn't UTF-8, but the session * environment implies UTF-8, then we have to account for * the extra required space manually. */ #ifdef OCI_ATTR_CHARSET_ID if (!CS_IS_UTF8(bind[i].csid) && CSFORM_IMPLIES_UTF8(bind[i].csform, statement->conn) ) #endif bind[i].max_len *= 4; break; case SQLT_TIMESTAMP: case SQLT_TIMESTAMP_TZ: case SQLT_TIMESTAMP_LTZ: // size depends on the NLS default date format. Assume a generous default. bind[i].max_len = 200; break; default: // Unhandled type... // printf("type %d [%d]\n", bind[i].data_type, bind[i].max_len); break; } if (bind[i].data_type == SQLT_BLOB || bind[i].data_type == SQLT_CLOB) { // BLOB and CLOB types are segregated because we want to // retrieve them as different types. This also sets us up // to be able to call this with OCI_DYNAMIC_FETCH later: // retrieving the LOB in chunks. bind[i].data = calloc(bind[i].max_len, sizeof(char)); rc = OCIDefineByPos(statement->stmt, &bind[i].define, statement->conn->err, (ub4)i+1, bind[i].data, bind[i].max_len, bind[i].data_type == SQLT_BLOB ? SQLT_BIN : SQLT_CHR, (dvoid *)&(bind[i].null), (ub2 *)&(bind[i].ret_len), (ub2 *)&(bind[i].ret_err), (ub4)OCI_DEFAULT); } else { // This is a SQLT_STR return value, which needs space for a // NULL terminating character. Add 4 bytes in case it's // UTF-8. bind[i].max_len+=4; bind[i].data = calloc(bind[i].max_len, sizeof(char)); rc = OCIDefineByPos(statement->stmt, &bind[i].define, statement->conn->err, (ub4)i+1, bind[i].data, bind[i].max_len, SQLT_STR, (dvoid *)&(bind[i].null), (ub2 *)&(bind[i].ret_len), (ub2 *)&(bind[i].ret_err), (ub4)OCI_DEFAULT); } if (rc) { OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, (sb4 *)&errcode, (text *) errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR); luaL_error(L, "define by pos %s", errbuf); } } statement->metadata = 1; } /* * num_affected_rows = statement:affected() */ static int statement_affected(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_ORACLE_STATEMENT); int affected; if (!statement->stmt) { luaL_error(L, DBI_ERR_INVALID_STATEMENT); } /* * get number of affected rows */ OCIAttrGet( (dvoid *)statement->stmt, (ub4)OCI_HTYPE_STMT, (dvoid *)&affected, (ub4 *)0, (ub4)OCI_ATTR_ROW_COUNT, statement->conn->err ); lua_pushinteger(L, affected); return 1; } /* * success = statement:close() */ int statement_close(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_ORACLE_STATEMENT); int ok = 0; if (statement->stmt) { OCIHandleFree((dvoid *)statement->stmt, OCI_HTYPE_STMT); /* Free handles */ statement->stmt = NULL; } if (statement->bind) { free(statement->bind); statement->bind = NULL; } lua_pushboolean(L, ok); return 1; } /* * column_names = statement:columns() */ static int statement_columns(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_ORACLE_STATEMENT); int i; int d = 1; if (!statement->stmt) { luaL_error(L, DBI_ERR_INVALID_STATEMENT); return 0; } statement_fetch_metadata(L, statement); lua_newtable(L); for (i = 0; i < statement->num_columns; i++) { const char *name = dbd_strlower((char *)statement->bind[i].name); LUA_PUSH_ARRAY_STRING(d, name); } return 1; } /* * success,err = statement:execute(...) */ int statement_execute(lua_State *L) { int n = lua_gettop(L); statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_ORACLE_STATEMENT); int p; int errflag = 0; const char *errstr = NULL; int num_columns; int rc; char errbuf[100]; sb4 errcode; ub2 type; if (!statement->stmt) { lua_pushboolean(L, 0); lua_pushstring(L, DBI_ERR_EXECUTE_INVALID); return 2; } for (p = 2; p <= n; p++) { int i = p - 1; int type = lua_type(L, p); char err[64]; const char *value; size_t val_size; OCIBind *bnd = (OCIBind *)0; switch(type) { case LUA_TNIL: errflag = OCIBindByPos( statement->stmt, &bnd, statement->conn->err, i, NULL, 0, SQLT_CHR, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, OCI_DEFAULT); break; case LUA_TNUMBER: case LUA_TSTRING: case LUA_TBOOLEAN: value = lua_tolstring(L, p, &val_size); errflag = OCIBindByPos( statement->stmt, &bnd, statement->conn->err, (ub4)i, (dvoid *)value, (sb4)val_size, (ub2)SQLT_CHR, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, (ub4)OCI_DEFAULT); break; default: /* * Unknown/unsupported value type */ errflag = 1; snprintf(err, sizeof(err)-1, DBI_ERR_BINDING_TYPE_ERR, lua_typename(L, type)); errstr = err; } if (errflag) break; } if (errflag) { lua_pushboolean(L, 0); if (errstr) lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errstr); else { OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, (sb4 *)&errcode, (text *) errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errbuf); } return 2; } /* * statement type */ rc = OCIAttrGet( (dvoid *)statement->stmt, (ub4)OCI_HTYPE_STMT, (dvoid *)&type, (ub4 *)0, (ub4)OCI_ATTR_STMT_TYPE, statement->conn->err ); if (rc) { OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, (sb4 *)&errcode, (text *) errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); lua_pushboolean(L, 0); lua_pushfstring(L, "Error getting type: %s", errbuf); return 2; } /* * execute statement */ rc = OCIStmtExecute( statement->conn->svc, statement->stmt, statement->conn->err, type == OCI_STMT_SELECT ? 0 : 1, (ub4)0, (CONST OCISnapshot *)NULL, (OCISnapshot *)NULL, statement->conn->autocommit ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT ); if (rc) { OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, (sb4 *)&errcode, (text *) errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); lua_pushboolean(L, 0); lua_pushfstring(L, DBI_ERR_BINDING_EXEC, errbuf); return 2; } /* * get number of columns */ rc = OCIAttrGet( (dvoid *)statement->stmt, (ub4)OCI_HTYPE_STMT, (dvoid *)&num_columns, (ub4 *)0, (ub4)OCI_ATTR_PARAM_COUNT, statement->conn->err ); if (rc) { OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, (sb4 *)&errcode, (text *) errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); lua_pushboolean(L, 0); lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errbuf); return 2; } statement->num_columns = num_columns; lua_pushboolean(L, 1); return 1; } /* * must be called after an execute */ static int statement_fetch_impl(lua_State *L, statement_t *statement, int named_columns) { sword status; bindparams_t *bind; char errbuf[100]; sb4 errcode; if (!statement->stmt) { luaL_error(L, DBI_ERR_FETCH_INVALID); return 0; } statement_fetch_metadata(L, statement); bind = statement->bind; status = OCIStmtFetch(statement->stmt, statement->conn->err, 1, OCI_FETCH_NEXT, OCI_DEFAULT); if (status == OCI_NO_DATA) { /* No more rows */ lua_pushnil(L); return 1; } // Loop through the fields, even on error; the error might be 1406 (truncated column), and we might want to return partial results... if (statement->num_columns) { int i; int d = 1; lua_newtable(L); for (i = 0; i < statement->num_columns; i++) { lua_push_type_t lua_push = oracle_to_lua_push(bind[i].data_type, bind[i].null); const char *name = dbd_strlower((char *)bind[i].name); const char *data = bind[i].data; size_t data_size = bind[i].ret_len; if ((bind[i].data_type == SQLT_BLOB || bind[i].data_type == SQLT_CLOB) && status == 1 && bind[i].ret_err == 1406) { // Allow partial return from a LOB status = 0; } else if (bind[i].ret_err != 0 && !(bind[i].ret_err == 1405 && bind[i].null)) { // If we need debugging... // printf("Error %d with column %.*s\n", bind[i].ret_err, bind[i].name_len, bind[i].name); } 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 = atoi(data); 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 = strtod(data, NULL); if (named_columns) { LUA_PUSH_ATTRIB_FLOAT(name, val); } else { LUA_PUSH_ARRAY_FLOAT(d, val); } } else if (lua_push == LUA_PUSH_STRING) { if (named_columns) { LUA_PUSH_ATTRIB_STRING_BY_LENGTH(name, data, data_size); } else { LUA_PUSH_ARRAY_STRING_BY_LENGTH(d, data, data_size); } } else if (lua_push == LUA_PUSH_BOOLEAN) { int val = atoi(data); if (named_columns) { LUA_PUSH_ATTRIB_BOOL(name, val); } else { LUA_PUSH_ARRAY_BOOL(d, val); } } else { luaL_error(L, DBI_ERR_UNKNOWN_PUSH); } } } else { /* * no columns returned by statement? */ lua_pushnil(L); } if (status != OCI_SUCCESS) { OCIErrorGet((dvoid *)statement->conn->err, (ub4)1, (text *)NULL, (sb4 *)&errcode, (text *) errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR); luaL_error(L, DBI_ERR_FETCH_FAILED, errbuf); } return 1; } static int next_iterator(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, lua_upvalueindex(1), DBD_ORACLE_STATEMENT); int named_columns = lua_toboolean(L, lua_upvalueindex(2)); return statement_fetch_impl(L, statement, named_columns); } /* * table = statement:fetch(named_indexes) */ static int statement_fetch(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_ORACLE_STATEMENT); int named_columns = lua_toboolean(L, 2); return statement_fetch_impl(L, statement, named_columns); } /* * num_rows = statement:rowcount() */ static int statement_rowcount(lua_State *L) { luaL_error(L, DBI_ERR_NOT_IMPLEMENTED, DBD_ORACLE_STATEMENT, "rowcount"); return 0; } /* * iterfunc = statement:rows(named_indexes) */ static int statement_rows(lua_State *L) { if (lua_gettop(L) == 1) { lua_pushvalue(L, 1); lua_pushboolean(L, 0); } else { lua_pushvalue(L, 1); lua_pushboolean(L, lua_toboolean(L, 2)); } lua_pushcclosure(L, next_iterator, 2); return 1; } /* * __gc */ static int statement_gc(lua_State *L) { /* always free the handle */ statement_close(L); return 0; } /* * __tostring */ static int statement_tostring(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_ORACLE_STATEMENT); lua_pushfstring(L, "%s: %p", DBD_ORACLE_STATEMENT, statement); return 1; } int dbd_oracle_statement_create(lua_State *L, connection_t *conn, const char *sql_query) { statement_t *statement = NULL; OCIStmt *stmt; char *new_sql; /* * convert SQL string into a Oracle API compatible SQL statement */ new_sql = dbd_replace_placeholders(L, ':', sql_query); OCIHandleAlloc((dvoid *)conn->oracle, (dvoid **)&stmt, OCI_HTYPE_STMT, 0, (dvoid **)0); OCIStmtPrepare(stmt, conn->err, (CONST text *)new_sql, (ub4)strlen(new_sql), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT); free(new_sql); statement = (statement_t *)lua_newuserdata(L, sizeof(statement_t)); statement->conn = conn; statement->stmt = stmt; statement->num_columns = 0; statement->bind = NULL; statement->metadata = 0; statement->prefetch_mem = conn->prefetch_mem; statement->prefetch_rows = conn->prefetch_rows; luaL_getmetatable(L, DBD_ORACLE_STATEMENT); lua_setmetatable(L, -2); return 1; } int dbd_oracle_statement(lua_State *L) { static const luaL_Reg statement_methods[] = { {"affected", statement_affected}, {"close", statement_close}, {"columns", statement_columns}, {"execute", statement_execute}, {"fetch", statement_fetch}, {"rowcount", statement_rowcount}, {"rows", statement_rows}, {NULL, NULL} }; static const luaL_Reg statement_class_methods[] = { {NULL, NULL} }; dbd_register(L, DBD_ORACLE_STATEMENT, statement_methods, statement_class_methods, statement_gc, statement_tostring); return 1; } luadbi-0.7.2/dbd/postgresql/000077500000000000000000000000001341705430500157165ustar00rootroot00000000000000luadbi-0.7.2/dbd/postgresql/connection.c000066400000000000000000000151311341705430500202220ustar00rootroot00000000000000#include "dbd_postgresql.h" int dbd_postgresql_statement_create(lua_State *L, connection_t *conn, const char *sql_query); static int run(connection_t *conn, const char *command) { PGresult *result = PQexec(conn->postgresql, command); ExecStatusType status; if (!result) return 1; status = PQresultStatus(result); PQclear(result); if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) return 1; return 0; } static int commit(connection_t *conn) { return run(conn, "COMMIT"); } static int begin(connection_t *conn) { return run(conn, "BEGIN"); } static int rollback(connection_t *conn) { return run(conn, "ROLLBACK"); } /* * connection = DBD.PostgreSQL.New(dbname, user, password, host, port) */ static int connection_new(lua_State *L) { int n = lua_gettop(L); connection_t *conn = NULL; const char *host = NULL; const char *user = NULL; const char *password = NULL; const char *db = NULL; const char *port = NULL; const char *options = NULL; /* TODO always NULL */ const char *tty = NULL; /* TODO always NULL */ char portbuf[18]; /* db, user, password, host, port */ switch (n) { case 5: if (lua_isnil(L, 5) == 0) { int pport = luaL_checkinteger(L, 5); if (pport >= 1 && pport <= 65535) { snprintf(portbuf, sizeof(portbuf), "%d", pport); port = portbuf; } else { luaL_error(L, DBI_ERR_INVALID_PORT, pport); } } // fallthrough case 4: if (lua_isnil(L, 4) == 0) host = luaL_checkstring(L, 4); // fallthrough case 3: if (lua_isnil(L, 3) == 0) password = luaL_checkstring(L, 3); // fallthrough case 2: if (lua_isnil(L, 2) == 0) user = luaL_checkstring(L, 2); // fallthrough case 1: /* * db is the only mandatory parameter */ db = luaL_checkstring(L, 1); // fallthrough } conn = (connection_t *)lua_newuserdata(L, sizeof(connection_t)); conn->postgresql = PQsetdbLogin(host, port, options, tty, db, user, password); conn->statement_id = 0; conn->autocommit = 0; begin(conn); if (PQstatus(conn->postgresql) != CONNECTION_OK) { lua_pushnil(L); lua_pushfstring(L, DBI_ERR_CONNECTION_FAILED, PQerrorMessage(conn->postgresql)); return 2; } luaL_getmetatable(L, DBD_POSTGRESQL_CONNECTION); lua_setmetatable(L, -2); return 1; } /* * success = connection:autocommit(on) */ static int connection_autocommit(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_CONNECTION); int on = lua_toboolean(L, 2); int err = 0; if (conn->postgresql) { if (on != conn->autocommit) { if (on) err = rollback(conn); else err = begin(conn); } conn->autocommit = on; } lua_pushboolean(L, !err); return 1; } /* * success = connection:close() */ static int connection_close(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_CONNECTION); int disconnect = 0; if (conn->postgresql) { /* * if autocommit is turned off, we probably * want to rollback any outstanding transactions. */ if (!conn->autocommit) rollback(conn); PQfinish(conn->postgresql); disconnect = 1; conn->postgresql = NULL; } lua_pushboolean(L, disconnect); return 1; } /* * success = connection:commit() */ static int connection_commit(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_CONNECTION); int err = 0; if (conn->postgresql) { commit(conn); if (!conn->autocommit) err = begin(conn); else err = 1; } lua_pushboolean(L, !err); return 1; } /* * ok = connection:ping() */ static int connection_ping(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_CONNECTION); int ok = 0; if (conn->postgresql) { ConnStatusType status = PQstatus(conn->postgresql); if (status == CONNECTION_OK) ok = 1; } lua_pushboolean(L, ok); return 1; } /* * statement = connection:prepare(sql_string) */ static int connection_prepare(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_CONNECTION); if (conn->postgresql) { return dbd_postgresql_statement_create(L, conn, luaL_checkstring(L, 2)); } lua_pushnil(L); lua_pushstring(L, DBI_ERR_DB_UNAVAILABLE); return 2; } /* * quoted = connection:quote(str) */ static int connection_quote(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_CONNECTION); size_t len; const char *from = luaL_checklstring(L, 2, &len); char *to = (char *)calloc(len*2+1, sizeof(char)); int err = 0; int quoted_len; if (!conn->postgresql) { luaL_error(L, DBI_ERR_DB_UNAVAILABLE); } quoted_len = PQescapeStringConn(conn->postgresql, to, from, len, &err); if (err) { free(to); luaL_error(L, DBI_ERR_QUOTING_STR, PQerrorMessage(conn->postgresql)); } lua_pushlstring(L, to, quoted_len); free(to); return 1; } /* * success = connection:rollback() */ static int connection_rollback(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_CONNECTION); int err = 0; if (conn->postgresql) { rollback(conn); if (!conn->autocommit) err = begin(conn); else err = 1; } lua_pushboolean(L, !err); return 1; } /* * last_id = connection:last_id() */ static int connection_lastid(lua_State *L) { luaL_error(L, DBI_ERR_NOT_IMPLEMENTED, DBD_POSTGRESQL_CONNECTION, "last_id"); return 0; } /* * __gc */ static int connection_gc(lua_State *L) { /* always close the connection */ connection_close(L); return 0; } /* * __tostring */ static int connection_tostring(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_CONNECTION); lua_pushfstring(L, "%s: %p", DBD_POSTGRESQL_CONNECTION, conn); return 1; } int dbd_postgresql_connection(lua_State *L) { static const luaL_Reg connection_methods[] = { {"autocommit", connection_autocommit}, {"close", connection_close}, {"commit", connection_commit}, {"ping", connection_ping}, {"prepare", connection_prepare}, {"quote", connection_quote}, {"rollback", connection_rollback}, {"last_id", connection_lastid}, {NULL, NULL} }; static const luaL_Reg connection_class_methods[] = { {"New", connection_new}, {NULL, NULL} }; dbd_register(L, DBD_POSTGRESQL_CONNECTION, connection_methods, connection_class_methods, connection_gc, connection_tostring); return 1; } luadbi-0.7.2/dbd/postgresql/dbd_postgresql.h000066400000000000000000000012531341705430500211040ustar00rootroot00000000000000#include #include /* * length of a prepared statement ID * dbd-postgresql-\d{17}\0 */ #define IDLEN 15+17+1 #define DBD_POSTGRESQL_CONNECTION "DBD.PostgreSQL.Connection" #define DBD_POSTGRESQL_STATEMENT "DBD.PostgreSQL.Statement" /* * connection object implentation */ typedef struct _connection { PGconn *postgresql; int autocommit; unsigned int statement_id; /* sequence for statement IDs */ } connection_t; /* * statement object implementation */ typedef struct _statement { connection_t *conn; PGresult *result; char name[IDLEN]; /* statement ID */ int tuple; /* number of rows returned */ } statement_t; luadbi-0.7.2/dbd/postgresql/main.c000066400000000000000000000004411341705430500170050ustar00rootroot00000000000000#include "dbd_postgresql.h" int dbd_postgresql_connection(lua_State *L); int dbd_postgresql_statement(lua_State *L); /* * library entry point */ LUA_EXPORT int luaopen_dbd_postgresql(lua_State *L) { dbd_postgresql_statement(L); dbd_postgresql_connection(L); return 1; } luadbi-0.7.2/dbd/postgresql/statement.c000066400000000000000000000273061341705430500200760ustar00rootroot00000000000000#include "dbd_postgresql.h" #define BOOLOID 16 #define INT2OID 21 #define INT4OID 23 #define INT8OID 20 #define FLOAT4OID 700 #define FLOAT8OID 701 #define DECIMALOID 1700 static lua_push_type_t postgresql_to_lua_push(unsigned int postgresql_type) { lua_push_type_t lua_type; switch(postgresql_type) { case INT2OID: case INT4OID: case INT8OID: lua_type = LUA_PUSH_INTEGER; break; case FLOAT4OID: case FLOAT8OID: case DECIMALOID: lua_type = LUA_PUSH_NUMBER; break; case BOOLOID: lua_type = LUA_PUSH_BOOLEAN; break; default: lua_type = LUA_PUSH_STRING; } return lua_type; } static int deallocate(statement_t *statement) { char command[IDLEN+13]; PGresult *result; ExecStatusType status; /* * It's possible to get here with a closed database handle * - either by a mistake by the calling Lua program, or by * garbage collection. Don't die in that case. */ if (statement->conn->postgresql) { snprintf(command, IDLEN+13, "DEALLOCATE \"%s\"", statement->name); result = PQexec(statement->conn->postgresql, command); if (!result) return 1; status = PQresultStatus(result); PQclear(result); if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) return 1; } return 0; } /* * num_affected_rows = statement:affected() */ static int statement_affected(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_STATEMENT); if (!statement->result) { luaL_error(L, DBI_ERR_INVALID_STATEMENT); } lua_pushinteger(L, atoi(PQcmdTuples(statement->result))); return 1; } /* * success = statement:close() */ static int statement_close(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_STATEMENT); if (statement->result) { /* * Deallocate prepared statement on the * server side */ deallocate(statement); PQclear(statement->result); statement->result = NULL; } return 0; } /* * column_names = statement:columns() */ static int statement_columns(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_STATEMENT); int i; int num_columns; int d = 1; if (!statement->result) { luaL_error(L, DBI_ERR_INVALID_STATEMENT); return 0; } num_columns = PQnfields(statement->result); lua_newtable(L); for (i = 0; i < num_columns; i++) { const char *name = PQfname(statement->result, i); LUA_PUSH_ARRAY_STRING(d, name); } return 1; } /* * success = statement:execute(...) */ static int statement_execute(lua_State *L) { int n = lua_gettop(L); statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_STATEMENT); int num_bind_params = n - 1; ExecStatusType status; int p; const char *errstr = NULL; const char **params; PGresult *result = NULL; /* * Sanity check - is database still connected? */ if (PQstatus(statement->conn->postgresql) != CONNECTION_OK) { lua_pushstring(L, DBI_ERR_STATEMENT_BROKEN); lua_error(L); } statement->tuple = 0; params = malloc(num_bind_params * sizeof(params)); memset(params, 0, num_bind_params * sizeof(params)); /* * convert and copy parameters into a string array */ for (p = 2; p <= n; p++) { int i = p - 2; int type = lua_type(L, p); char err[64]; switch(type) { case LUA_TNIL: params[i] = NULL; break; case LUA_TBOOLEAN: /* * boolean values in postgresql can either be * t/f or 1/0. Pass integer values rather than * strings to maintain semantic compatibility * with other DBD drivers that pass booleans * as integers. */ params[i] = lua_toboolean(L, p) ? "1" : "0"; break; case LUA_TNUMBER: case LUA_TSTRING: params[i] = lua_tostring(L, p); break; default: snprintf(err, sizeof(err)-1, DBI_ERR_BINDING_TYPE_ERR, lua_typename(L, type)); errstr = err; goto cleanup; } } result = PQexecPrepared( statement->conn->postgresql, statement->name, num_bind_params, (const char **)params, NULL, NULL, 0 ); cleanup: free(params); if (errstr) { lua_pushboolean(L, 0); lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errstr); return 2; } if (!result) { lua_pushboolean(L, 0); lua_pushfstring(L, DBI_ERR_ALLOC_RESULT, PQerrorMessage(statement->conn->postgresql)); return 2; } status = PQresultStatus(result); if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) { lua_pushboolean(L, 0); lua_pushfstring(L, DBI_ERR_BINDING_EXEC, PQresultErrorMessage(result)); return 2; } if (statement->result) { status = PQresultStatus (statement->result); if (status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK) PQclear (statement->result); } statement->result = result; lua_pushboolean(L, 1); return 1; } /* * can only be called after an execute */ static int statement_fetch_impl(lua_State *L, statement_t *statement, int named_columns) { int tuple = statement->tuple++; int i; int num_columns; int d = 1; if (!statement->result) { luaL_error(L, DBI_ERR_FETCH_INVALID); return 0; } if (PQresultStatus(statement->result) != PGRES_TUPLES_OK) { lua_pushnil(L); return 1; } if (tuple >= PQntuples(statement->result)) { lua_pushnil(L); /* no more results */ return 1; } num_columns = PQnfields(statement->result); lua_newtable(L); for (i = 0; i < num_columns; i++) { const char *name = PQfname(statement->result, i); if (PQgetisnull(statement->result, tuple, i)) { if (named_columns) { LUA_PUSH_ATTRIB_NIL(name); } else { LUA_PUSH_ARRAY_NIL(d); } } else { const char *value = PQgetvalue(statement->result, tuple, i); lua_push_type_t lua_push = postgresql_to_lua_push(PQftype(statement->result, i)); /* * data is returned as strings from PSQL * convert them here into Lua types */ 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 = atoi(value); 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 = strtod(value, NULL); if (named_columns) { LUA_PUSH_ATTRIB_FLOAT(name, val); } else { LUA_PUSH_ARRAY_FLOAT(d, val); } } else if (lua_push == LUA_PUSH_STRING) { if (named_columns) { LUA_PUSH_ATTRIB_STRING(name, value); } else { LUA_PUSH_ARRAY_STRING(d, value); } } else if (lua_push == LUA_PUSH_BOOLEAN) { /* * booleans are returned as a string * either 't' or 'f' */ int val = value[0] == 't' ? 1 : 0; if (named_columns) { LUA_PUSH_ATTRIB_BOOL(name, val); } else { LUA_PUSH_ARRAY_BOOL(d, val); } } else { luaL_error(L, DBI_ERR_UNKNOWN_PUSH); } } } return 1; } static int next_iterator(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, lua_upvalueindex(1), DBD_POSTGRESQL_STATEMENT); int named_columns = lua_toboolean(L, lua_upvalueindex(2)); return statement_fetch_impl(L, statement, named_columns); } /* * table = statement:fetch(named_indexes) */ static int statement_fetch(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_STATEMENT); int named_columns = lua_toboolean(L, 2); return statement_fetch_impl(L, statement, named_columns); } /* * num_rows = statement:rowcount() */ static int statement_rowcount(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_STATEMENT); if (!statement->result) { luaL_error(L, DBI_ERR_INVALID_STATEMENT); } lua_pushinteger(L, PQntuples(statement->result)); return 1; } /* * iterfunc = statement:rows(named_indexes) */ static int statement_rows(lua_State *L) { if (lua_gettop(L) == 1) { lua_pushvalue(L, 1); lua_pushboolean(L, 0); } else { lua_pushvalue(L, 1); lua_pushboolean(L, lua_toboolean(L, 2)); } lua_pushcclosure(L, next_iterator, 2); return 1; } /* * __gc */ static int statement_gc(lua_State *L) { /* always free the handle */ statement_close(L); return 0; } /* * __tostring */ static int statement_tostring(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_STATEMENT); lua_pushfstring(L, "%s: %p", DBD_POSTGRESQL_STATEMENT, statement); return 1; } int dbd_postgresql_statement_create(lua_State *L, connection_t *conn, const char *sql_query) { statement_t *statement = NULL; ExecStatusType status; PGresult *result = NULL; char *new_sql; char name[IDLEN]; /* * convert SQL string into a PSQL API compatible SQL statement */ new_sql = dbd_replace_placeholders(L, '$', sql_query); snprintf(name, IDLEN, "dbd-postgresql-%017u", ++conn->statement_id); result = PQprepare(conn->postgresql, name, new_sql, 0, NULL); /* * free converted statement after use */ free(new_sql); if (!result) { lua_pushnil(L); lua_pushfstring(L, DBI_ERR_ALLOC_STATEMENT, PQerrorMessage(conn->postgresql)); return 2; } status = PQresultStatus(result); if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) { const char *err_string = PQresultErrorMessage(result); lua_pushnil(L); lua_pushfstring(L, DBI_ERR_PREP_STATEMENT, err_string); PQclear(result); return 2; } PQclear(result); statement = (statement_t *)lua_newuserdata(L, sizeof(statement_t)); statement->conn = conn; statement->result = NULL; statement->tuple = 0; strncpy(statement->name, name, IDLEN-1); statement->name[IDLEN-1] = '\0'; luaL_getmetatable(L, DBD_POSTGRESQL_STATEMENT); lua_setmetatable(L, -2); return 1; } int dbd_postgresql_statement(lua_State *L) { static const luaL_Reg statement_methods[] = { {"affected", statement_affected}, {"close", statement_close}, {"columns", statement_columns}, {"execute", statement_execute}, {"fetch", statement_fetch}, {"rowcount", statement_rowcount}, {"rows", statement_rows}, {NULL, NULL} }; static const luaL_Reg statement_class_methods[] = { {NULL, NULL} }; dbd_register(L, DBD_POSTGRESQL_STATEMENT, statement_methods, statement_class_methods, statement_gc, statement_tostring); return 1; } luadbi-0.7.2/dbd/sqlite3/000077500000000000000000000000001341705430500150775ustar00rootroot00000000000000luadbi-0.7.2/dbd/sqlite3/connection.c000066400000000000000000000142451341705430500174100ustar00rootroot00000000000000#include "dbd_sqlite3.h" int dbd_sqlite3_statement_create(lua_State *L, connection_t *conn, const char *sql_query); static int run(connection_t *conn, const char *command) { int res = sqlite3_exec(conn->sqlite, command, NULL, NULL, NULL); return res != SQLITE_OK; } static int commit(connection_t *conn) { return run(conn, "COMMIT TRANSACTION"); } static int begin(connection_t *conn) { int err = 0; if (sqlite3_get_autocommit(conn->sqlite)) { err = run(conn, "BEGIN TRANSACTION"); } else { err = 0; } return err; } static int rollback(connection_t *conn) { return run(conn, "ROLLBACK TRANSACTION"); } int try_begin_transaction(connection_t *conn) { if (conn->autocommit) { return 1; } return begin(conn) == 0; } /* * connection,err = DBD.SQLite3.New(dbfile) */ static int connection_new(lua_State *L) { int n = lua_gettop(L); const char *db = NULL; connection_t *conn = NULL; /* db */ switch(n) { default: /* * db is the only mandatory parameter */ db = luaL_checkstring(L, 1); } int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; if (n >= 2) { if (!lua_isnil(L, 2)) flags = luaL_checkinteger(L, 2); } conn = (connection_t *)lua_newuserdata(L, sizeof(connection_t)); if (sqlite3_open_v2(db, &conn->sqlite, flags, NULL) != SQLITE_OK) { lua_pushnil(L); lua_pushfstring(L, DBI_ERR_CONNECTION_FAILED, sqlite3_errmsg(conn->sqlite)); return 2; } conn->autocommit = 0; luaL_getmetatable(L, DBD_SQLITE_CONNECTION); lua_setmetatable(L, -2); return 1; } /* * success = connection:autocommit(on) */ static int connection_autocommit(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_SQLITE_CONNECTION); int on = lua_toboolean(L, 2); int err = 1; if (conn->sqlite) { if (on) { err = rollback(conn); } conn->autocommit = on; } lua_pushboolean(L, !err); return 1; } /* * success = connection:close() */ static int connection_close(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_SQLITE_CONNECTION); int disconnect = 0; if (conn->sqlite) { rollback(conn); sqlite3_close(conn->sqlite); disconnect = 1; conn->sqlite = NULL; } lua_pushboolean(L, disconnect); return 1; } /* * success = connection:commit() */ static int connection_commit(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_SQLITE_CONNECTION); int err = 1; if (conn->sqlite) { err = commit(conn); } lua_pushboolean(L, !err); return 1; } /* * ok = connection:ping() */ static int connection_ping(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_SQLITE_CONNECTION); int ok = 0; if (conn->sqlite) { ok = 1; } lua_pushboolean(L, ok); return 1; } /* * statement,err = connection:prepare(sql_str) */ static int connection_prepare(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_SQLITE_CONNECTION); if (conn->sqlite) { return dbd_sqlite3_statement_create(L, conn, luaL_checkstring(L, 2)); } lua_pushnil(L); lua_pushstring(L, DBI_ERR_DB_UNAVAILABLE); return 2; } /* * quoted = connection:quote(str) */ static int connection_quote(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_SQLITE_CONNECTION); size_t len; const char *from = luaL_checklstring(L, 2, &len); char *to; if (!conn->sqlite) { luaL_error(L, DBI_ERR_DB_UNAVAILABLE); } to = sqlite3_mprintf("%q", from); lua_pushstring(L, to); sqlite3_free(to); return 1; } /* * success = connection:rollback() */ static int connection_rollback(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_SQLITE_CONNECTION); int err = 1; if (conn->sqlite) { err =rollback(conn); } lua_pushboolean(L, !err); return 1; } /* * last_id = connection:last_id() */ static int connection_lastid(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_SQLITE_CONNECTION); lua_pushinteger(L, sqlite3_last_insert_rowid(conn->sqlite)); return 1; } /* * __gc */ static int connection_gc(lua_State *L) { /* always close the connection */ connection_close(L); return 0; } /* * __tostring */ static int connection_tostring(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_SQLITE_CONNECTION); lua_pushfstring(L, "%s: %p", DBD_SQLITE_CONNECTION, conn); return 1; } int dbd_sqlite3_connection(lua_State *L) { /* * instance methods */ static const luaL_Reg connection_methods[] = { {"autocommit", connection_autocommit}, {"close", connection_close}, {"commit", connection_commit}, {"ping", connection_ping}, {"prepare", connection_prepare}, {"quote", connection_quote}, {"rollback", connection_rollback}, {"last_id", connection_lastid}, {NULL, NULL} }; /* * class methods */ static const luaL_Reg connection_class_methods[] = { {"New", connection_new}, {NULL, NULL} }; dbd_register(L, DBD_SQLITE_CONNECTION, connection_methods, connection_class_methods, connection_gc, connection_tostring); /* * Connection flag constants exported in our namespace */ static const struct { const char *name; int value; } sqlite3_constants[] = { "SQLITE_OPEN_READONLY", SQLITE_OPEN_READONLY, "SQLITE_OPEN_READWRITE", SQLITE_OPEN_READWRITE, "SQLITE_OPEN_CREATE", SQLITE_OPEN_CREATE, "SQLITE_OPEN_URI", SQLITE_OPEN_URI, "SQLITE_OPEN_MEMORY", SQLITE_OPEN_MEMORY, "SQLITE_OPEN_NOMUTEX", SQLITE_OPEN_NOMUTEX, "SQLITE_OPEN_FULLMUTEX", SQLITE_OPEN_FULLMUTEX, "SQLITE_OPEN_SHAREDCACHE", SQLITE_OPEN_SHAREDCACHE, "SQLITE_OPEN_PRIVATECACHE", SQLITE_OPEN_PRIVATECACHE, NULL, 0 }; int i = 0; while (sqlite3_constants[i].name) { lua_pushstring(L, sqlite3_constants[i].name); lua_pushinteger(L, sqlite3_constants[i].value); lua_rawset(L, -3); ++i; } return 1; } luadbi-0.7.2/dbd/sqlite3/dbd_sqlite3.h000066400000000000000000000006521341705430500174500ustar00rootroot00000000000000#include #include #define DBD_SQLITE_CONNECTION "DBD.SQLite3.Connection" #define DBD_SQLITE_STATEMENT "DBD.SQLite3.Statement" /* * connection object */ typedef struct _connection { sqlite3 *sqlite; int autocommit; } connection_t; /* * statement object */ typedef struct _statement { connection_t *conn; sqlite3_stmt *stmt; int more_data; int affected; } statement_t; luadbi-0.7.2/dbd/sqlite3/main.c000066400000000000000000000004201341705430500161630ustar00rootroot00000000000000#include "dbd_sqlite3.h" int dbd_sqlite3_connection(lua_State *L); int dbd_sqlite3_statement(lua_State *L); /* * library entry point */ LUA_EXPORT int luaopen_dbd_sqlite3(lua_State *L) { dbd_sqlite3_statement(L); dbd_sqlite3_connection(L); return 1; } luadbi-0.7.2/dbd/sqlite3/statement.c000066400000000000000000000240431341705430500172520ustar00rootroot00000000000000#include "dbd_sqlite3.h" extern int try_begin_transaction(connection_t *conn); extern int try_end_transaction(connection_t *conn); /* * Converts SQLite types to Lua types */ 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; } /* * runs sqlite3_step on a statement handle */ 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; } /* * num_affected_rows = statement:affected() */ static int statement_affected(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_SQLITE_STATEMENT); if (!statement->stmt) { luaL_error(L, DBI_ERR_INVALID_STATEMENT); } lua_pushinteger(L, statement->affected); return 1; } /* * success = statement:close() */ 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; } statement->stmt = NULL; } lua_pushboolean(L, ok); return 1; } /* * column_names = statement:columns() */ static int statement_columns(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_SQLITE_STATEMENT); int i; int num_columns; int d = 1; if (!statement->stmt) { luaL_error(L, DBI_ERR_INVALID_STATEMENT); return 0; } num_columns = sqlite3_column_count(statement->stmt); lua_newtable(L); for (i = 0; i < num_columns; i++) { const char *name = sqlite3_column_name(statement->stmt, i); LUA_PUSH_ARRAY_STRING(d, name); } return 1; } /* * success,err = statement:execute(...) */ 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; int errflag = 0; const char *errstr = NULL; int expected_params; int num_bind_params = n - 1; if (!statement->stmt) { lua_pushboolean(L, 0); lua_pushstring(L, DBI_ERR_EXECUTE_INVALID); return 2; } /* * sanity check: make sure our database handle is still open */ if (!statement->conn->sqlite) { lua_pushstring(L, DBI_ERR_STATEMENT_BROKEN); lua_error(L); } /* * reset the handle before binding params * this will be a NOP if the handle has not * been executed */ if (sqlite3_reset(statement->stmt) != SQLITE_OK) { lua_pushboolean(L, 0); lua_pushfstring(L, DBI_ERR_EXECUTE_FAILED, sqlite3_errmsg(statement->conn->sqlite)); return 2; } sqlite3_clear_bindings(statement->stmt); expected_params = sqlite3_bind_parameter_count(statement->stmt); if (expected_params != num_bind_params) { /* * sqlite3_reset does not handle this condition, * and the client library will fill unset params * with NULLs */ lua_pushboolean(L, 0); lua_pushfstring(L, DBI_ERR_PARAM_MISCOUNT, expected_params, num_bind_params); return 2; } for (p = 2; p <= n; p++) { int i = p - 1; int type = lua_type(L, p); char err[64]; switch(type) { case LUA_TNIL: errflag = sqlite3_bind_null(statement->stmt, i) != SQLITE_OK; break; case LUA_TNUMBER: errflag = sqlite3_bind_double(statement->stmt, i, lua_tonumber(L, p)) != SQLITE_OK; break; case LUA_TSTRING: { size_t len = -1; const char *str = lua_tolstring(L, p, &len); errflag = sqlite3_bind_text(statement->stmt, i, str, len, SQLITE_STATIC) != SQLITE_OK; break; } case LUA_TBOOLEAN: errflag = sqlite3_bind_int(statement->stmt, i, lua_toboolean(L, p)) != SQLITE_OK; break; default: /* * Unknown/unsupported value type */ errflag = 1; snprintf(err, sizeof(err)-1, DBI_ERR_BINDING_TYPE_ERR, lua_typename(L, type)); errstr = err; } if (errflag) break; } if (errflag) { lua_pushboolean(L, 0); if (errstr) lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errstr); else lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, sqlite3_errmsg(statement->conn->sqlite)); return 2; } try_begin_transaction(statement->conn); if (!step(statement)) { lua_pushboolean(L, 0); lua_pushfstring(L, DBI_ERR_EXECUTE_FAILED, sqlite3_errmsg(statement->conn->sqlite)); return 2; } statement->affected = sqlite3_changes(statement->conn->sqlite); lua_pushboolean(L, 1); return 1; } /* * must be called after an execute */ static int statement_fetch_impl(lua_State *L, statement_t *statement, int named_columns) { int num_columns; if (!statement->stmt) { luaL_error(L, DBI_ERR_FETCH_INVALID); return 0; } if (!statement->more_data) { /* * Result set is empty, or not result set returned */ 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, DBI_ERR_UNKNOWN_PUSH); } } } else { /* * no columns returned by statement? */ lua_pushnil(L); } if (step(statement) == 0) { if (sqlite3_reset(statement->stmt) != SQLITE_OK) { /* * reset needs to be called to retrieve the 'real' error message */ luaL_error(L, DBI_ERR_FETCH_FAILED, sqlite3_errmsg(statement->conn->sqlite)); } } return 1; } static int next_iterator(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, lua_upvalueindex(1), DBD_SQLITE_STATEMENT); int named_columns = lua_toboolean(L, lua_upvalueindex(2)); return statement_fetch_impl(L, statement, named_columns); } /* * table = statement:fetch(named_indexes) */ static int statement_fetch(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_SQLITE_STATEMENT); int named_columns = lua_toboolean(L, 2); return statement_fetch_impl(L, statement, named_columns); } /* * iterfunc = statement:rows(named_indexes) */ static int statement_rows(lua_State *L) { if (lua_gettop(L) == 1) { lua_pushvalue(L, 1); lua_pushboolean(L, 0); } else { lua_pushvalue(L, 1); lua_pushboolean(L, lua_toboolean(L, 2)); } lua_pushcclosure(L, next_iterator, 2); return 1; } /* * num_rows = statement:rowcount() */ static int statement_rowcount(lua_State *L) { luaL_error(L, DBI_ERR_NOT_IMPLEMENTED, DBD_SQLITE_STATEMENT, "rowcount"); return 0; } /* * __gc */ static int statement_gc(lua_State *L) { /* always free the handle */ statement_close(L); return 0; } /* * __tostring */ static int statement_tostring(lua_State *L) { statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_SQLITE_STATEMENT); lua_pushfstring(L, "%s: %p", DBD_SQLITE_STATEMENT, statement); return 1; } 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->conn = conn; statement->stmt = NULL; statement->more_data = 0; statement->affected = 0; if (sqlite3_prepare_v2(statement->conn->sqlite, sql_query, strlen(sql_query), &statement->stmt, NULL) != SQLITE_OK) { lua_pushnil(L); lua_pushfstring(L, DBI_ERR_PREP_STATEMENT, sqlite3_errmsg(statement->conn->sqlite)); return 2; } luaL_getmetatable(L, DBD_SQLITE_STATEMENT); lua_setmetatable(L, -2); return 1; } int dbd_sqlite3_statement(lua_State *L) { static const luaL_Reg statement_methods[] = { {"affected", statement_affected}, {"close", statement_close}, {"columns", statement_columns}, {"execute", statement_execute}, {"fetch", statement_fetch}, {"rows", statement_rows}, {"rowcount", statement_rowcount}, {NULL, NULL} }; static const luaL_Reg statement_class_methods[] = { {NULL, NULL} }; dbd_register(L, DBD_SQLITE_STATEMENT, statement_methods, statement_class_methods, statement_gc, statement_tostring); return 1; } luadbi-0.7.2/luadbi-mysql-scm-0.rockspec000066400000000000000000000023431341705430500200370ustar00rootroot00000000000000package = "luadbi-mysql" version = "scm-0" description = { summary = "Database abstraction layer", detailed = [[ LuaDBI is a database interface library for Lua. It is designed to provide a RDBMS agnostic API for handling database operations. LuaDBI also provides support for prepared statement handles, placeholders and bind parameters for all database operations. This rock is the MySQL DBD module. You will also need the base DBI module to use this software. ]], license = "MIT/X11", homepage = "https://github.com/mwild1/luadbi" } source = { url = "git+https://github.com/mwild1/luadbi.git", } dependencies = { "lua >= 5.1", "luadbi = scm" } external_dependencies = { MYSQL = { header = "mysql/mysql.h" } } build = { type = "builtin", modules = { ['dbd.mysql'] = { sources = { 'dbd/common.c', 'dbd/mysql/main.c', 'dbd/mysql/statement.c', 'dbd/mysql/connection.c' }, libraries = { 'mysqlclient' }, incdirs = { "$(MYSQL_INCDIR)/mysql", './' }, libdirs = { "$(MYSQL_LIBDIR)" } } } } luadbi-0.7.2/luadbi-postgresql-scm-0.rockspec000066400000000000000000000025431341705430500210770ustar00rootroot00000000000000package = "luadbi-postgresql" version = "scm-0" description = { summary = "Database abstraction layer", detailed = [[ LuaDBI is a database interface library for Lua. It is designed to provide a RDBMS agnostic API for handling database operations. LuaDBI also provides support for prepared statement handles, placeholders and bind parameters for all database operations. This rock is the PostgreSQL DBD module. You will also need the base DBI module to use this software. ]], license = "MIT/X11", homepage = "https://github.com/mwild1/luadbi" } source = { url = "git+https://github.com/mwild1/luadbi.git", } dependencies = { "lua >= 5.1", "luadbi = scm" } external_dependencies = { POSTGRES = { header = "postgresql/libpq-fe.h" } } build = { type = "builtin", modules = { ['dbd.postgresql'] = { sources = { 'dbd/common.c', 'dbd/postgresql/main.c', 'dbd/postgresql/statement.c', 'dbd/postgresql/connection.c' }, libraries = { 'pq' }, incdirs = { "$(POSTGRES_INCDIR)/postgresql", './' }, libdirs = { "$(POSTGRES_LIBDIR)" } } } }luadbi-0.7.2/luadbi-scm-0.rockspec000066400000000000000000000014501341705430500166720ustar00rootroot00000000000000package = "luadbi" version = "scm-0" description = { summary = "Database abstraction layer", detailed = [[ LuaDBI is a database interface library for Lua. It is designed to provide a RDBMS agnostic API for handling database operations. LuaDBI also provides support for prepared statement handles, placeholders and bind parameters for all database operations. This rock is the front end DBI module. You will need one or more backend DBD drivers to use this software. ]], license = "MIT/X11", homepage = "https://github.com/mwild1/luadbi" } source = { url = "git+https://github.com/mwild1/luadbi.git", } dependencies = { "lua >= 5.1" } build = { type = "builtin", modules = { ["DBI"] = "DBI.lua" } } luadbi-0.7.2/luadbi-sqlite3-scm-0.rockspec000066400000000000000000000024711341705430500202600ustar00rootroot00000000000000package = "luadbi-sqlite3" version = "scm-0" description = { summary = "Database abstraction layer", detailed = [[ LuaDBI is a database interface library for Lua. It is designed to provide a RDBMS agnostic API for handling database operations. LuaDBI also provides support for prepared statement handles, placeholders and bind parameters for all database operations. This rock is the Sqlite3 DBD module. You will also need the base DBI module to use this software. ]], license = "MIT/X11", homepage = "https://github.com/mwild1/luadbi" } source = { url = "git+https://github.com/mwild1/luadbi.git", } dependencies = { "lua >= 5.1", "luadbi = scm" } external_dependencies = { SQLITE = { header = "sqlite3.h" } } build = { type = "builtin", modules = { ['dbd.sqlite3'] = { sources = { 'dbd/common.c', 'dbd/sqlite3/main.c', 'dbd/sqlite3/statement.c', 'dbd/sqlite3/connection.c' }, libraries = { 'sqlite3' }, incdirs = { "$(SQLITE_INCDIR)", './' }, libdirs = { "$(SQLITE_LIBDIR)" } } } }luadbi-0.7.2/tests/000077500000000000000000000000001341705430500141245ustar00rootroot00000000000000luadbi-0.7.2/tests/configs/000077500000000000000000000000001341705430500155545ustar00rootroot00000000000000luadbi-0.7.2/tests/configs/MySQL.lua000066400000000000000000000010001341705430500172130ustar00rootroot00000000000000#!/usr/bin/env lua return { connect = { host = 'localhost', port = 3306, name = 'luadbi', user = 'luadbi', pass = 'testing12345!!!' }, encoding_test = { 12435212, 463769, 8574678, -12435212, 0, 9998212, 7653.25, 7635236, 0.000, -7653.25, 1636.94783, "string 1", "another_string", "really long string with some escapable chars: #&*%#;@'" }, placeholder = '?', have_last_insert_id = true, have_typecasts = false, have_booleans = false, have_rowcount = true } luadbi-0.7.2/tests/configs/PostgreSQL.lua000066400000000000000000000015731341705430500202700ustar00rootroot00000000000000#!/usr/bin/env lua return { connect = { host = 'localhost', name = 'luadbi', user = 'luadbi', pass = 'testinguser-12345!!!' }, encoding_test = { ['::int'] = 12435212, ['::int'] = 463769, ['::int'] = 8574678, ['::int'] = -12435212, ['::int'] = 0, ['::int'] = 9998212, ['::double precision'] = 123412.5235236199951, ['::float'] = 7653.25, ['::float'] = 7635236, ['::float'] = 0.00, ['::float'] = -7653.25, ['::float'] = 1636.94783, ['::decimal'] = 35.34, ['::decimal'] = -3.00, ['::decimal'] = 35848535.24, ['::decimal'] = 0.00, ['::boolean'] = true, ['::boolean'] = false, ['::varchar'] = "string 1", ['::varchar'] = "another_string", ['::text'] = "really long string with some escapable chars: #&*%#;@'" }, placeholder = '$1', have_last_insert_id = false, have_typecasts = true, have_booleans = true, have_rowcount = true } luadbi-0.7.2/tests/configs/SQLite3.lua000066400000000000000000000012451341705430500175050ustar00rootroot00000000000000#!/usr/bin/env lua return { connect = { name = 'sqlite3-test' }, encoding_test = { ['::int'] = 12435212, ['::int'] = 463769, ['::int'] = 8574678, ['::int'] = -12435212, ['::int'] = 0, ['::int'] = 9998212, ['::float'] = 0.00, ['::float'] = -7653.25, ['::float'] = 1636.94783, ['::decimal'] = 35.34, ['::decimal'] = -3.00, ['::decimal'] = 35848535.24, ['::decimal'] = 0.00, ['::varchar'] = "string 1", ['::varchar'] = "another_string", ['::text'] = "really long string with some escapable chars: #&*%#;@'" }, placeholder = '$1', have_last_insert_id = true, have_typecasts = true, have_booleans = false, have_rowcount = false } luadbi-0.7.2/tests/run_tests.lua000077500000000000000000000246141341705430500166670ustar00rootroot00000000000000#!/usr/bin/env lua5.2 package.path = "../?.lua;" .. package.path package.cpath = "../?.so;" .. package.cpath require "luarocks.loader" require 'busted.runner'() local sql_code = { ['encoding'] = "select %s%s as retval;", ['select'] = "select * from select_tests where name = %s;", ['select_multi'] = "select * from select_tests where flag = %s;", ['select_count'] = "select count(*) as total from insert_tests;", ['insert'] = "insert into insert_tests ( val ) values ( %s );", ['insert_returning'] = "insert into insert_tests ( val ) values ( %s ) returning id;", ['insert_select'] = "select * from insert_tests where id = %s;", ['update_all'] = "update update_tests set last_update = %s;", ['update_some'] = "update update_tests set last_update = %s where flag = %s;" } local function code( sql_test_code, arg ) local ret = string.format(sql_code[sql_test_code], config.placeholder, arg) --print(ret) return ret end local function setup_tests() local err DBI = require "DBI" assert.is_not_nil(DBI) dbh, err = DBI.Connect( db_type, config.connect.name, config.connect.user, config.connect.pass, config.connect.host, config.connect.port ) assert.is_nil(err) assert.is_not_nil(dbh) assert.is_not_nil(dbh:autocommit( true )) assert.is_true( dbh:ping() ) return dbh end local function teardown_tests() if dbh then dbh:close() dbh = nil end end local function connection_fail() local dbh2, err = DBI.Connect( db_type, "Bogus1-3jrn23j4n32j4n23jn4@32^$2j", "Bogus2-#*%J#@&*FNM@JK#FM#", "Bogus3-#*NMR@JNM^#M<&$*%" ) assert.is_nil(dbh2) assert.is_string(err) end local function syntax_error() local sth, err = dbh:prepare("Break me 3i5m2r3krm3280j648390j@#(J%28903j523890j623") assert.is_nil(sth) assert.is_string(err) end local function test_encoding() local query for vtype, val in pairs(config.encoding_test) do if config.have_typecasts then query = code('encoding', vtype) else query = code('encoding', '') end local sth = assert.is_not_nil(dbh:prepare(query)) assert.is_not_nil(sth) assert.is_not_nil(sth:execute(val)) local row = sth:rows(true)() assert.is_not_nil(row) assert.is_equal(val, row['retval']) assert.is_equal(type(val), type(row['retval'])) sth:close() end end local function test_select() local sth, err = dbh:prepare(code('select')) local count = 0 local success assert.is_nil(err) assert.is_not_nil(sth) success, err = sth:execute("Row 1") assert.is_true(success) assert.is_nil(err) for row in sth:rows(true) do count = count + 1 if config.have_booleans then assert.is_true(row['flag']) else assert.equals(1, row['flag']) end assert.equals('Row 1', row['name']) assert.is_number(row['maths']) end assert.equals(1, count) if config.have_rowcount then assert.equals(sth:rowcount(), count) end sth:close() end local function test_select_multi() local sth, err = dbh:prepare(code('select_multi')) local count = 0 local success assert.is_nil(err) assert.is_not_nil(sth) success, err = sth:execute(false) assert.is_true(success) assert.is_nil(err) for row in sth:rows(false) do count = count + 1 assert.equals(#row, 4) assert.is_number(row[1]) assert.is_string(row[2]) if config.have_booleans then assert.is_false(row[3]) else assert.equals(0, row[3]) end assert.is_number(row[4]) end assert.equals(2, count) if config.have_rowcount then assert.equals(sth:rowcount(), count) end sth:close() end local function test_insert() local sth, sth2, err, success local stringy = os.date() sth, err = dbh:prepare(code('insert')) assert.is_nil(err) assert.is_not_nil(sth) success, err = sth:execute(stringy) assert.is_true(success) assert.is_nil(err) assert.is_equal(1, sth:affected()) -- -- Grab it back, make sure it's all good -- local id = dbh:last_id() assert.is_not_nil(id) sth:close() sth2, err = dbh:prepare(code('insert_select')) assert.is_nil(err) assert.is_not_nil(sth) success, err = sth2:execute(id) assert.is_true(success) assert.is_nil(err) local row = sth2:rows(false)() assert.is_not_nil(row) assert.are_equal(id, row[1]) assert.are_equal(stringy, row[2]) sth:close() sth2:close() end local function test_insert_multi() local sth, sth2, err, rs, count, success local stringy = os.date() sth, err = dbh:prepare(code('insert')) assert.is_nil(err) assert.is_not_nil(sth) sth2, err = dbh:prepare(sql_code['select_count']) assert.is_nil(err) assert.is_not_nil(sth2) -- -- See how many rows are in the table -- rs, err = sth2:execute() assert.is_nil(err) assert.is_not_nil(rs) local itr = sth2:rows(false) count = itr()[1] -- drain the results - should only be one row but let's be correct while itr() do success = nil end -- -- Reuse the insert statement quite a few times -- for i=1,10 do success, err = sth:execute(stringy .. '-' .. tostring(i)) assert.is_true(success) assert.is_nil(err) assert.is_not_nil(sth) assert.is_equal(1, sth:affected()) end -- -- Make sure all ten inserts succeed by comparing how many -- rows are there now. Also proves selects are reusable. -- rs, err = sth2:execute() assert.is_nil(err) assert.is_not_nil(rs) itr = sth2:rows(false) assert.is_equal(count + 10, itr()[1]) while itr() do success = nil end sth:close() sth2:close() end local function test_insert_returning() local sth, sth2, err, success local stringy = os.date() sth, err = dbh:prepare(code('insert_returning')) assert.is_nil(err) assert.is_not_nil(sth) success, err = sth:execute(stringy) assert.is_nil(err) assert.is_true(success) assert.is_equal(1, sth:rowcount()) -- -- Grab it back, make sure it's all good -- local id_row = sth:rows(false)() assert.is_not_nil(id_row) local id = id_row[1] assert.is_not_nil(id) sth:close() sth2, err = dbh:prepare(code('insert_select')) assert.is_nil(err) assert.is_not_nil(sth) sth2:execute(id) local row = sth2:rows(false)() assert.is_not_nil(row) assert.are_equal(id, row[1]) assert.are_equal(stringy, row[2]) end -- -- Prove affected() is functional. -- local function test_update() -- -- I originally used date handling and set the column -- to NOW(), but Sqlite3 didn't play nice with that. -- local sth, err = dbh:prepare(code('update_all')) local success assert.is_nil(err) assert.is_not_nil(sth) success, err = sth:execute(os.time() - math.random(50, 500)) assert.is_nil(err) assert.is_true(success) assert.equals(4, sth:affected()) sth:close() -- do it again with the flag set, so we get fewer rows, -- just to be sure. -- which also means we need to sleep for a bit. if config.have_booleans then sth, err = dbh:prepare(code('update_some', 'false')) else sth, err = dbh:prepare(code('update_some', '0')) end assert.is_nil(err) assert.is_not_nil(sth) success, err = sth:execute(os.time()) assert.is_nil(err) assert.is_true(success) assert.equals(1, sth:affected()) end -- -- Prove the nonexistant functions aren't there. -- local function test_no_rowcount() local sth, _ = dbh:prepare(code('select')) local success, err = sth:execute("Row 1") assert.is_true(success) assert.is_nil(err) assert.has_error(function() sth:rowcount() end) sth:close() end -- -- Prove there is no insert_id. -- local function test_no_insert_id() local stringy = os.date() local sth, err = dbh:prepare(code('insert')) assert.is_nil(err) assert.is_not_nil(sth) sth:execute(stringy) assert.has_error(function() dbh:insert_id() end) sth:close() end -- -- Prove something sane happens in the event that the database -- handle goes away, but statements are still open. -- local function test_db_close_doesnt_segfault() local sth,err = dbh:prepare("SELECT 1"); assert.is_nil(err) assert.is_not_nil(sth) dbh:close() local sth2 sth2, err = dbh:prepare(code('insert')) assert.is_nil(sth2) assert.is_string(err) dbh = nil assert.has_error(function() sth:execute() end) -- this also shouldn't segfault. sth:close() end local function test_postgres_statement_leak() for i = 1, 10 do local sth = dbh:prepare("SELECT 1"); sth:execute(); for r in sth:rows() do assert(r[1] == 1, "result should be 1") end sth:close(); end for i = 1, 5 do collectgarbage("collect") end do local sth = dbh:prepare("SELECT * from pg_prepared_statements"); sth:execute(); local c = 0; for row in sth:rows() do c = c + 1; end assert(c < 10, "too many prepared statements still exist"); end end describe("PostgreSQL #psql", function() db_type = "PostgreSQL" config = dofile("configs/" .. db_type .. ".lua") -- luacheck: ignore DBI dbh local DBI, dbh setup(setup_tests) it( "Tests login failure", connection_fail ) it( "Tests syntax error", syntax_error ) it( "Tests value encoding", test_encoding ) it( "Tests a simple select", test_select ) it( "Tests multi-row selects", test_select_multi ) it( "Tests inserts", test_insert_returning ) it( "Tests statement reuse", test_insert_multi ) it( "Tests no insert_id", test_no_insert_id ) it( "Tests affected rows", test_update ) it( "Tests for prepared statement leak", test_postgres_statement_leak ) it( "Tests closing dbh doesn't segfault", test_db_close_doesnt_segfault ) teardown(teardown_tests) end) describe("SQLite3 #sqlite3", function() db_type = "SQLite3" config = dofile("configs/" .. db_type .. ".lua") -- luacheck: ignore DBI dbh local DBI, dbh setup(setup_tests) it( "Tests syntax error", syntax_error ) it( "Tests value encoding", test_encoding ) it( "Tests simple selects", test_select ) it( "Tests multi-row selects", test_select_multi ) it( "Tests inserts", test_insert ) it( "Tests statement reuse", test_insert_multi ) it( "Tests no rowcount", test_no_rowcount ) it( "Tests affected rows", test_update ) it( "Tests closing dbh doesn't segfault", test_db_close_doesnt_segfault ) teardown(teardown_tests) end) describe("MySQL #mysql", function() db_type = "MySQL" config = dofile("configs/" .. db_type .. ".lua") -- luacheck: ignore DBI dbh local DBI, dbh setup(setup_tests) it( "Tests login failure", connection_fail ) it( "Tests syntax error", syntax_error ) it( "Tests value encoding", test_encoding ) it( "Tests simple selects", test_select ) it( "Tests multi-row selects", test_select_multi ) it( "Tests inserts", test_insert ) it( "Tests statement reuse", test_insert_multi ) it( "Tests affected rows", test_update ) it( "Tests closing dbh doesn't segfault", test_db_close_doesnt_segfault ) teardown(teardown_tests) end) luadbi-0.7.2/tests/schemas/000077500000000000000000000000001341705430500155475ustar00rootroot00000000000000luadbi-0.7.2/tests/schemas/mysql.sql000066400000000000000000000021701341705430500174350ustar00rootroot00000000000000/* MySQL test schema. */ drop table if exists select_tests; create table select_tests ( id int not null primary key auto_increment, name varchar(255) not null, flag boolean not null, maths int not null ); insert into select_tests ( name, flag, maths ) values ( 'Row 1', true, 12345 ), ( 'Row 2', false, 54321 ), ( 'Row 3', false, 324671 ); grant select on select_tests to 'luadbi'@'%'; drop table if exists insert_tests; create table insert_tests ( id int not null primary key auto_increment, val varchar(255) not null ); grant insert, select on insert_tests to 'luadbi'@'%'; drop table if exists update_tests; create table update_tests ( id int not null primary key auto_increment, name varchar(255) not null, last_update int not null, flag bool not null ); insert into update_tests ( name, last_update, flag ) values ( 'Row 1', UNIX_TIMESTAMP(NOW()), 1 ), ( 'Row 2', UNIX_TIMESTAMP(NOW()), 1 ), ( 'Row 3', UNIX_TIMESTAMP(NOW()), 0 ), ( 'Row 4', UNIX_TIMESTAMP(NOW()), 1 ); grant select, update on update_tests to 'luadbi'@'%'; luadbi-0.7.2/tests/schemas/postgresql.sql000066400000000000000000000020621341705430500204730ustar00rootroot00000000000000/* PostgreSQL test schema. */ drop table if exists select_tests cascade; create table select_tests ( id serial primary key, name varchar(255) not null, flag boolean not null, maths int not null ); insert into select_tests ( name, flag, maths ) values ( 'Row 1', true, 12345 ), ( 'Row 2', false, 54321 ), ( 'Row 3', false, 324671 ); grant select on select_tests to luadbi; drop table if exists insert_tests cascade; create table insert_tests ( id serial primary key, val varchar(255) not null ); grant insert, select on insert_tests to luadbi; grant usage, select on insert_tests_id_seq to luadbi; drop table if exists update_tests; create table update_tests ( id serial primary key, name varchar(255) not null, last_update int not null, flag bool not null ); insert into update_tests ( name, last_update, flag ) values ( 'Row 1', 0, true ), ( 'Row 2', 0, true ), ( 'Row 3', 0, false ), ( 'Row 4', 0, true ); grant select, update on update_tests to luadbi; luadbi-0.7.2/tests/schemas/sqlite3.sql000066400000000000000000000015261341705430500176600ustar00rootroot00000000000000/* SQLite3 test schema. */ drop table if exists select_tests; create table select_tests ( id integer primary key, name varchar(255) not null, flag boolean not null, maths int not null ); insert into select_tests ( name, flag, maths ) values ( 'Row 1', 1, 12345 ), ( 'Row 2', 0, 54321 ), ( 'Row 3', 0, 324671 ); drop table if exists insert_tests; create table insert_tests ( id integer primary key, val varchar(255) not null ); drop table if exists update_tests; create table update_tests ( id integer primary key, name varchar(255) not null, last_update int not null, flag bool not null ); insert into update_tests ( name, last_update, flag ) values ( 'Row 1', 'now', 1 ), ( 'Row 2', 'now', 1 ), ( 'Row 3', 'now', 0 ), ( 'Row 4', 'now', 1 ); luadbi-0.7.2/vc++/000077500000000000000000000000001341705430500135205ustar00rootroot00000000000000luadbi-0.7.2/vc++/dbddb2/000077500000000000000000000000001341705430500146415ustar00rootroot00000000000000luadbi-0.7.2/vc++/dbddb2/dbddb2.vcproj000066400000000000000000000112171341705430500172110ustar00rootroot00000000000000 luadbi-0.7.2/vc++/dbdmysql/000077500000000000000000000000001341705430500153375ustar00rootroot00000000000000luadbi-0.7.2/vc++/dbdmysql/dbdmysql.vcproj000066400000000000000000000113371341705430500204100ustar00rootroot00000000000000 luadbi-0.7.2/vc++/dbdoracle/000077500000000000000000000000001341705430500154375ustar00rootroot00000000000000luadbi-0.7.2/vc++/dbdoracle/dbdoracle.vcproj000066400000000000000000000111221341705430500206000ustar00rootroot00000000000000 luadbi-0.7.2/vc++/dbdpostgresql/000077500000000000000000000000001341705430500163755ustar00rootroot00000000000000luadbi-0.7.2/vc++/dbdpostgresql/dbdpostgresql.vcproj000066400000000000000000000126251341705430500225050ustar00rootroot00000000000000 luadbi-0.7.2/vc++/dbdsqlite3/000077500000000000000000000000001341705430500155565ustar00rootroot00000000000000luadbi-0.7.2/vc++/dbdsqlite3/dbdsqlite3.vcproj000066400000000000000000000112351341705430500210430ustar00rootroot00000000000000 luadbi-0.7.2/vc++/luadbi.sln000066400000000000000000000052351341705430500155030ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 10.00 # Visual C++ Express 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dbdpostgresql", "dbdpostgresql\dbdpostgresql.vcproj", "{7DC4FC36-C3DC-475E-A6DA-CEB4BA237843}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dbdmysql", "dbdmysql\dbdmysql.vcproj", "{C3A5B30E-0471-459E-AFF3-FF54F9F31599}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dbdoracle", "dbdoracle\dbdoracle.vcproj", "{BD3DE628-23AE-416E-A983-8A0E8D4F0E15}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dbddb2", "dbddb2\dbddb2.vcproj", "{9F935BC6-6766-4D60-8C48-9EF607883B7D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dbdsqlite3", "dbdsqlite3\dbdsqlite3.vcproj", "{7B532158-C67A-490D-80EF-FF5552EE38B1}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {7DC4FC36-C3DC-475E-A6DA-CEB4BA237843}.Debug|Win32.ActiveCfg = Debug|Win32 {7DC4FC36-C3DC-475E-A6DA-CEB4BA237843}.Debug|Win32.Build.0 = Debug|Win32 {7DC4FC36-C3DC-475E-A6DA-CEB4BA237843}.Release|Win32.ActiveCfg = Release|Win32 {7DC4FC36-C3DC-475E-A6DA-CEB4BA237843}.Release|Win32.Build.0 = Release|Win32 {C3A5B30E-0471-459E-AFF3-FF54F9F31599}.Debug|Win32.ActiveCfg = Debug|Win32 {C3A5B30E-0471-459E-AFF3-FF54F9F31599}.Debug|Win32.Build.0 = Debug|Win32 {C3A5B30E-0471-459E-AFF3-FF54F9F31599}.Release|Win32.ActiveCfg = Release|Win32 {C3A5B30E-0471-459E-AFF3-FF54F9F31599}.Release|Win32.Build.0 = Release|Win32 {BD3DE628-23AE-416E-A983-8A0E8D4F0E15}.Debug|Win32.ActiveCfg = Debug|Win32 {BD3DE628-23AE-416E-A983-8A0E8D4F0E15}.Debug|Win32.Build.0 = Debug|Win32 {BD3DE628-23AE-416E-A983-8A0E8D4F0E15}.Release|Win32.ActiveCfg = Release|Win32 {BD3DE628-23AE-416E-A983-8A0E8D4F0E15}.Release|Win32.Build.0 = Release|Win32 {9F935BC6-6766-4D60-8C48-9EF607883B7D}.Debug|Win32.ActiveCfg = Debug|Win32 {9F935BC6-6766-4D60-8C48-9EF607883B7D}.Debug|Win32.Build.0 = Debug|Win32 {9F935BC6-6766-4D60-8C48-9EF607883B7D}.Release|Win32.ActiveCfg = Release|Win32 {9F935BC6-6766-4D60-8C48-9EF607883B7D}.Release|Win32.Build.0 = Release|Win32 {7B532158-C67A-490D-80EF-FF5552EE38B1}.Debug|Win32.ActiveCfg = Debug|Win32 {7B532158-C67A-490D-80EF-FF5552EE38B1}.Debug|Win32.Build.0 = Debug|Win32 {7B532158-C67A-490D-80EF-FF5552EE38B1}.Release|Win32.ActiveCfg = Release|Win32 {7B532158-C67A-490D-80EF-FF5552EE38B1}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal