Licence Build Status Coverage Status
- prepared query
- bind parameters (input/output)
- bind column
- async mode for statements
- catalog functions
- luasql compatable module
- C API to create Lua object based on existed ODBC handle
- assert method rise error as object.
This works fine on Lua > 5.1 and on LuaJIT but on Lua 5.1 it results message as
lua.exe: (error object is not a string). But it allows wrap code inpcallfunction and handle errors as object(with access to SQLCODE and SQLSTATE). To change this behavior set-DLODBC_ASSERT_TOSTRINGflag in compile time.
Insert multiple rows
odbc = require "odbc" dbassert = odbc.assert cnn = odbc.connect('EmptyDB') cnn:setautocommit(false) stmt = cnn:prepare("insert into test_table(f1, f2) values(?, ?)") f1 = stmt:vbind_param_ulong(1) for i = 1, 5 do f1:set(i) -- just set data stmt:bindnum(2, i) -- each time call SQLBindParameter dbassert(stmt:execute()) end dbassert( cnn:commit() )
Select resultset
odbc = require "odbc" dbassert = odbc.assert cnn = odbc.connect('EmptyDB') stmt = cnn:execute('select f1, f2 from test_table order by 1') stmt:foreach(function(f1, f2) if f1 == 2 then return true end end) assert(stmt:closed()) -- foreach close cursor assert(not stmt:destroyed()) -- statement valid stmt:execute('select f1, f2 from test_table order by 1') f1, f2 = stmt:fetch()
Input/Output parameters
odbc = require "odbc" dbassert = odbc.assert cnn = odbc.connect('EmptyDB') stmt = dbassert(cnn:prepare("{?= call dba.fn_test(?)}")) ret = stmt:vbind_param_ulong(1, ret, odbc.PARAM_OUTPUT) val = stmt:vbind_param_char(2, "hello") -- default odbc.PARAM_INPUT dbassert(stmt:execute()) print(ret:get()) stmt:reset() stmt:vbind_col(1, ret) dbassert(stmt:execute('select 321')) stmt:vfetch() print(ret:get())
Use async mode
local odbc = require "odbc" local dbassert = odbc.assert cnn = odbc.connect('EmptyDB') stmt = cnn:prepare('select f1, f2 from test_table order by 1') local f1 = stmt:vbind_col_ulong(1) local f2 = stmt:vbind_col_ulong(2) stmt:setasyncmode(true) local COUNTER = 0 function async(stmt, f, ...) while true do local ok, err = f(stmt, ...) if ok ~= 'timeout' then return ok, err end COUNTER = COUNTER + 1 end end dbassert(async(stmt, stmt.execute)) while(async(stmt, stmt.vfetch))do print(f1:get(),f2:get()) end print("execute counter:", COUNTER)
Use C API
static void luaX_call_method(lua_State *L, const char *name, int nargs, int nresults){ int obj_index = -nargs - 1; lua_getfield(L, obj_index, name); lua_insert(L, obj_index - 1); return lua_call(L, nargs + 1, nresults); } static int odbc_first_row_impl(lua_State *L){ SQLHSTMT *pstmt = (SQLHSTMT *)lua_touserdata(L, lua_upvalueindex(1)); lua_settop(L, 1); // sql // wrap existed handle to lua object lodbc_statement(L, *pstmt, 0); // sql, stmt lua_insert(L, 1); lua_insert(L, 1); // stmt, sql luaX_call_method(L, "execute", 1, 2); // [nil/stmt], [err/nil] // here we should check error and ether execute return recordset lua_pop(L, 1); //stmt luaX_call_method(L, "fetch", 0, LUA_MULTRET); return lua_gettop(L); } static int odbc_first_row(lua_State *L){ int res; { // this is may be cpp scope (we can use RAII) // get existed handle from somewhere(e.g. prepared pool) SQLHSTMT hstmt = ... lua_pushlightuserdata(L, &hstmt); lua_pushcclosure(L, odbc_first_row_impl, 1); lua_insert(L, 1); res = lua_pcall(L, lua_gettop(L)-1, LUA_MULTRET, 0); // cleanup } if(res) return lua_error(L); return lua_gettop(L); }
And from Lua we can call this function just like ... = odbc.first_row("select ...")
Implementaion of dba API