Hello, fellow dev@ people, it's time for my monthly mod_lua rambling! This time, I have set my eyes on creating bindings for the apr_dbd features and mod_dbd in httpd. The purpose of this would be to both enable people to easily use databases for Lua scripts, as well as lua "modules" (hooks) in a way that both minimizes the need for external libraries and takes advantage of mod_dbd if the module is loaded and in use.
While this could also be solved using an external library that was required()'d in the Lua scripts, I feel that it would greatly boost the usage and popularity of mod_lua if it were to be included as a core feature. Otherwise, people would have to go look for external libraries, which would both be redundant, since we already have db features inside httpd, as well as make it more difficult to get things running with mod_lua, as people would have to either resort to luarocks (which I find to be quite lacking) or write/compile libraries themselves. I do not wish to attempt to compare mod_lua to the likes of mod_php, mod_python etc, but the ease of which these modules are hooked up with databases of all sorts is perhaps one of the key elements in their popularity, and I want mod_lua to be just as accessible for the _basic_ needs of a programmer/sysadmin (no, I do not want to bloat it, but I want the core features that you need on a modern web site to be available, and as such, db connectivity is a must) The use-cases for this is many; Authenticating against a database with a different approach than mod_auth_dbd, mass virtual hosting using cached database lookups, web sites like our comments.a.o (which uses the exact same Lua bindings as the one I am proposing, so it's been tested and is working ;) ), my own paste bin site apaste.info (people from #httpd probably know and use this one) and other nifty sorts of hooks and scripts. Database objects will be assigned a metatable with a garbage collector routine that automatically frees database handles when they are no longer used, or they can be manually closed (which is preferred). The bindings I propose can roughly be summarized with these example snippets: ------------------------- Connecting to a database: ------------------------- function handler(r) local db, error = r:dbopen("mod_dbd") -- Open a mod_dbd connection if error then ... end -- or... local db, error = r:dbopen("mysql", "server=localhost,user=root,database=somedb") -- essentially the same as mod_dbd's connection string. do_stuff() db:close() -- close the db handle (can also be done by GC) local still_running = db:active() -- returns false, since we closed -- the connection. end --------- Querying: --------- -- Run a command and get the no. of rows affected: local affected, err = db:do(r, "DELETE FROM `table` WHERE 1") if err then print("DB error: " .. err) else print("Deleted " .. affected .. " rows!") end -- Run a query and get the rows returned: local rows, err = db:query(r, "SELECT `name` FROM `table` WHERE 1") if rows then r:puts("We got " .. #rows " .. " results!") for k, row in pairs(rows) do print("Name: " .. row[1] .. "<br/>") end else r:puts("DB error: " .. err) end -- Run a prepared statement and inject values into it: local rows, err = db:inject(r, "SELECT `name` FROM `tbl` WHERE `id` = %u", 1234) if rows then .... else .... end -------------- Miscellaneous: -------------- -- escaping strings for use in db queries: local escaped = db:escape(r, [[foo"bar'&|baz]]) So, any comments, suggestions, remarks, objections and so on is very much welcomed. If there are no big objections to implementing this feature, I will consider it as lazy consensus and commit the bindings to trunk sometime soon along with updated documentation. With regards, Daniel. PS: I _have_ checked and double checked the code properly this time, so it conforms to the style requirements and works with maintainer mode. I know I usually get something wrong, but this time I think it's as close to perfect as it can get :) (but then again, I always write something bad, so apologies in advance if you find a bug)