lua_dbd.c revision 155bbc7af7b1ce46533c6e273a5921ca75813ad2
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele/**
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele * Licensed to the Apache Software Foundation (ASF) under one or more
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele * contributor license agreements. See the NOTICE file distributed with
5f5d1b4cc970b7f06ff8ef6526128e9a27303d88nd * this work for additional information regarding copyright ownership.
acc36ab93565d2880447d535da6ca6e5feac7a70nd * The ASF licenses this file to You under the Apache License, Version 2.0
acc36ab93565d2880447d535da6ca6e5feac7a70nd * (the "License"); you may not use this file except in compliance with
db479b48bd4d75423ed4a45e15b75089d1a8ad72fielding * the License. You may obtain a copy of the License at
db479b48bd4d75423ed4a45e15b75089d1a8ad72fielding *
db479b48bd4d75423ed4a45e15b75089d1a8ad72fielding * http://www.apache.org/licenses/LICENSE-2.0
db479b48bd4d75423ed4a45e15b75089d1a8ad72fielding *
db479b48bd4d75423ed4a45e15b75089d1a8ad72fielding * Unless required by applicable law or agreed to in writing, software
db479b48bd4d75423ed4a45e15b75089d1a8ad72fielding * distributed under the License is distributed on an "AS IS" BASIS,
acc36ab93565d2880447d535da6ca6e5feac7a70nd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
acc36ab93565d2880447d535da6ca6e5feac7a70nd * See the License for the specific language governing permissions and
acc36ab93565d2880447d535da6ca6e5feac7a70nd * limitations under the License.
acc36ab93565d2880447d535da6ca6e5feac7a70nd */
acc36ab93565d2880447d535da6ca6e5feac7a70nd
acc36ab93565d2880447d535da6ca6e5feac7a70nd
acc36ab93565d2880447d535da6ca6e5feac7a70nd#include "mod_lua.h"
acc36ab93565d2880447d535da6ca6e5feac7a70nd#include "lua_dbd.h"
acc36ab93565d2880447d535da6ca6e5feac7a70nd
acc36ab93565d2880447d535da6ca6e5feac7a70ndAPLOG_USE_MODULE(lua);
7db9f691a00ead175b03335457ca296a33ddf31bndstatic APR_OPTIONAL_FN_TYPE(ap_dbd_close) *lua_ap_dbd_close = NULL;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabelestatic APR_OPTIONAL_FN_TYPE(ap_dbd_open) *lua_ap_dbd_open = NULL;
3ca6ee111e6044cb463e6dc45b9adcfa3050ff00rbowen
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele
e50df6c711553f98103f1e0802f7de8c59be7cddslive
e50df6c711553f98103f1e0802f7de8c59be7cddslivestatic request_rec *ap_lua_check_request_rec(lua_State *L, int index)
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele{
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele request_rec *r;
c449ffd09c6af936695e858cff98916215ff76bckess luaL_checkudata(L, index, "Apache2.Request");
e50df6c711553f98103f1e0802f7de8c59be7cddslive r = lua_unboxpointer(L, index);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele return r;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele}
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele
252b32956857ad89fc9ee708c4c6eb36097a647cerikabelestatic lua_db_handle *lua_get_db_handle(lua_State *L)
e50df6c711553f98103f1e0802f7de8c59be7cddslive{
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele luaL_checktype(L, 1, LUA_TTABLE);
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen lua_rawgeti(L, 1, 0);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele luaL_checktype(L, -1, LUA_TUSERDATA);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele return (lua_db_handle *) lua_topointer(L, -1);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele}
e50df6c711553f98103f1e0802f7de8c59be7cddslive
252b32956857ad89fc9ee708c4c6eb36097a647cerikabelestatic lua_db_result_set *lua_get_result_set(lua_State *L)
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele{
19e48954d3cfb4f573a99866b0071b6aaa62723ckess luaL_checktype(L, 1, LUA_TTABLE);
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen lua_rawgeti(L, 1, 0);
19e48954d3cfb4f573a99866b0071b6aaa62723ckess luaL_checktype(L, -1, LUA_TUSERDATA);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele return (lua_db_result_set *) lua_topointer(L, -1);
e50df6c711553f98103f1e0802f7de8c59be7cddslive}
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen
3f2fa24c621652779fd6706116a35b49c6dc26cand/*
3f2fa24c621652779fd6706116a35b49c6dc26cand =============================================================================
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele db:close(): Closes an open database connection.
e50df6c711553f98103f1e0802f7de8c59be7cddslive =============================================================================
e50df6c711553f98103f1e0802f7de8c59be7cddslive */
252b32956857ad89fc9ee708c4c6eb36097a647cerikabeleint lua_db_close(lua_State *L)
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen{
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele /*~~~~~~~~~~~~~~~~~~~~*/
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele lua_db_handle *db;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele apr_status_t rc = 0;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele /*~~~~~~~~~~~~~~~~~~~~*/
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele db = lua_get_db_handle(L);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele if (db && db->alive) {
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen if (db->type == LUA_DBTYPE_APR_DBD) {
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele rc = apr_dbd_close(db->driver, db->handle);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele if (db->pool) apr_pool_destroy(db->pool);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele }
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele else {
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele lua_ap_dbd_close = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_close);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele if (lua_ap_dbd_close != NULL)
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen if (db->dbdhandle) lua_ap_dbd_close(db->server, db->dbdhandle);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele }
e50df6c711553f98103f1e0802f7de8c59be7cddslive
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele db->driver = NULL;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele db->handle = NULL;
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen db->alive = 0;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele db->pool = NULL;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele }
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele lua_settop(L, 0);
19e48954d3cfb4f573a99866b0071b6aaa62723ckess lua_pushnumber(L, rc);
cf02129aebf73dd0bdf369b172eb481ff76ac5f6colm return 1;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele}
e50df6c711553f98103f1e0802f7de8c59be7cddslive
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele/*
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen =============================================================================
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele db:__gc(): Garbage collecting function.
e50df6c711553f98103f1e0802f7de8c59be7cddslive =============================================================================
19e48954d3cfb4f573a99866b0071b6aaa62723ckess */
19e48954d3cfb4f573a99866b0071b6aaa62723ckessint lua_db_gc(lua_State *L)
19e48954d3cfb4f573a99866b0071b6aaa62723ckess{
19e48954d3cfb4f573a99866b0071b6aaa62723ckess /*~~~~~~~~~~~~~~~~*/
e50df6c711553f98103f1e0802f7de8c59be7cddslive lua_db_handle *db;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele /*~~~~~~~~~~~~~~~~~~~~*/
e50df6c711553f98103f1e0802f7de8c59be7cddslive
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele db = lua_touserdata(L, 1);
19e48954d3cfb4f573a99866b0071b6aaa62723ckess if (db && db->alive) {
19e48954d3cfb4f573a99866b0071b6aaa62723ckess if (db->type == LUA_DBTYPE_APR_DBD) {
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele apr_dbd_close(db->driver, db->handle);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele if (db->pool) apr_pool_destroy(db->pool);
e50df6c711553f98103f1e0802f7de8c59be7cddslive }
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele else {
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele lua_ap_dbd_close = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_close);
19e48954d3cfb4f573a99866b0071b6aaa62723ckess if (lua_ap_dbd_close != NULL)
19e48954d3cfb4f573a99866b0071b6aaa62723ckess if (db->dbdhandle) lua_ap_dbd_close(db->server, db->dbdhandle);
19e48954d3cfb4f573a99866b0071b6aaa62723ckess }
e50df6c711553f98103f1e0802f7de8c59be7cddslive db->driver = NULL;
e50df6c711553f98103f1e0802f7de8c59be7cddslive db->handle = NULL;
e50df6c711553f98103f1e0802f7de8c59be7cddslive db->alive = 0;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele db->pool = NULL;
e50df6c711553f98103f1e0802f7de8c59be7cddslive }
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele lua_settop(L, 0);
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen return 0;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele}
19e48954d3cfb4f573a99866b0071b6aaa62723ckess
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele/*
19e48954d3cfb4f573a99866b0071b6aaa62723ckess =============================================================================
19e48954d3cfb4f573a99866b0071b6aaa62723ckess db:active(): Returns true if the connection to the db is still active.
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele =============================================================================
e50df6c711553f98103f1e0802f7de8c59be7cddslive */
e50df6c711553f98103f1e0802f7de8c59be7cddsliveint lua_db_active(lua_State *L)
e50df6c711553f98103f1e0802f7de8c59be7cddslive{
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen /*~~~~~~~~~~~~~~~~~~~~*/
e50df6c711553f98103f1e0802f7de8c59be7cddslive lua_db_handle *db = 0;
e50df6c711553f98103f1e0802f7de8c59be7cddslive apr_status_t rc = 0;
e50df6c711553f98103f1e0802f7de8c59be7cddslive /*~~~~~~~~~~~~~~~~~~~~*/
e50df6c711553f98103f1e0802f7de8c59be7cddslive
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele db = lua_get_db_handle(L);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele if (db && db->alive) {
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele rc = apr_dbd_check_conn(db->driver, db->pool, db->handle);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele if (rc == APR_SUCCESS) {
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele lua_pushboolean(L, 1);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele return 1;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele }
e50df6c711553f98103f1e0802f7de8c59be7cddslive }
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen lua_pushboolean(L, 0);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele return 1;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele}
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele
e50df6c711553f98103f1e0802f7de8c59be7cddslive/*
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele =============================================================================
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen db:query(statement): Executes the given database query and returns the
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele number of rows affected. If an error is encountered, returns nil as the
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele first parameter and the error message as the second.
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele =============================================================================
e50df6c711553f98103f1e0802f7de8c59be7cddslive */
e50df6c711553f98103f1e0802f7de8c59be7cddsliveint lua_db_query(lua_State *L)
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen{
e50df6c711553f98103f1e0802f7de8c59be7cddslive /*~~~~~~~~~~~~~~~~~~~~~~~*/
e50df6c711553f98103f1e0802f7de8c59be7cddslive lua_db_handle *db = 0;
e50df6c711553f98103f1e0802f7de8c59be7cddslive apr_status_t rc = 0;
a6fc6b44b7f8ad7390864b3555341d3abf867f7end int x = 0;
e50df6c711553f98103f1e0802f7de8c59be7cddslive const char *statement;
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen /*~~~~~~~~~~~~~~~~~~~~~~~*/
e50df6c711553f98103f1e0802f7de8c59be7cddslive luaL_checktype(L, 3, LUA_TSTRING);
e50df6c711553f98103f1e0802f7de8c59be7cddslive statement = lua_tostring(L, 3);
e50df6c711553f98103f1e0802f7de8c59be7cddslive db = lua_get_db_handle(L);
e50df6c711553f98103f1e0802f7de8c59be7cddslive if (db && db->alive)
e50df6c711553f98103f1e0802f7de8c59be7cddslive rc = apr_dbd_query(db->driver, db->handle, &x, statement);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele else {
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele rc = 0;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele x = -1;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele }
e50df6c711553f98103f1e0802f7de8c59be7cddslive
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele if (rc == APR_SUCCESS)
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen lua_pushnumber(L, x);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele else {
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele
e50df6c711553f98103f1e0802f7de8c59be7cddslive /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele const char *err = apr_dbd_error(db->driver, db->handle, rc);
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen lua_pushnil(L);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele if (err) {
e50df6c711553f98103f1e0802f7de8c59be7cddslive lua_pushstring(L, err);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele return 2;
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen }
e50df6c711553f98103f1e0802f7de8c59be7cddslive }
e50df6c711553f98103f1e0802f7de8c59be7cddslive
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele return 1;
e50df6c711553f98103f1e0802f7de8c59be7cddslive}
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele
e50df6c711553f98103f1e0802f7de8c59be7cddslive/*
e50df6c711553f98103f1e0802f7de8c59be7cddslive =============================================================================
e50df6c711553f98103f1e0802f7de8c59be7cddslive db:escape(string): Escapes a string for safe use in the given database type.
e50df6c711553f98103f1e0802f7de8c59be7cddslive =============================================================================
e50df6c711553f98103f1e0802f7de8c59be7cddslive */
19e48954d3cfb4f573a99866b0071b6aaa62723ckessint lua_db_escape(lua_State *L)
19e48954d3cfb4f573a99866b0071b6aaa62723ckess{
19e48954d3cfb4f573a99866b0071b6aaa62723ckess /*~~~~~~~~~~~~~~~~~~~~~*/
19e48954d3cfb4f573a99866b0071b6aaa62723ckess lua_db_handle *db = 0;
19e48954d3cfb4f573a99866b0071b6aaa62723ckess const char *statement;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele const char *escaped = 0;
e50df6c711553f98103f1e0802f7de8c59be7cddslive request_rec *r;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele /*~~~~~~~~~~~~~~~~~~~~~*/
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele r = ap_lua_check_request_rec(L, 2);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele if (r) {
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele luaL_checktype(L, 3, LUA_TSTRING);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele statement = lua_tostring(L, 3);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele db = lua_get_db_handle(L);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele if (db && db->alive) {
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele apr_dbd_init(r->pool);
e50df6c711553f98103f1e0802f7de8c59be7cddslive escaped = apr_dbd_escape(db->driver, r->pool, statement,
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele db->handle);
19e48954d3cfb4f573a99866b0071b6aaa62723ckess if (escaped) {
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele lua_pushstring(L, escaped);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele return 1;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele }
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele }
e50df6c711553f98103f1e0802f7de8c59be7cddslive else {
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele lua_pushnil(L);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele }
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele return (1);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele }
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele return 0;
19e48954d3cfb4f573a99866b0071b6aaa62723ckess}
19e48954d3cfb4f573a99866b0071b6aaa62723ckess
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele/*
a6fc6b44b7f8ad7390864b3555341d3abf867f7end =============================================================================
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele resultset(N): Fetches one or more rows from a result set.
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele =============================================================================
f50095bc3874806a9cc5e7d283dd9051ef8a0df8nd */
252b32956857ad89fc9ee708c4c6eb36097a647cerikabeleint lua_db_get_row(lua_State *L)
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele{
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele int row_no,x,alpha = 0;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele const char *entry, *rowname;
apr_dbd_row_t *row = 0;
lua_db_result_set *res = lua_get_result_set(L);
row_no = luaL_optinteger(L, 2, 0);
if (lua_isboolean(L, 3)) {
alpha = lua_toboolean(L, 3);
}
lua_settop(L,0);
/* Fetch all rows at once? */
if (row_no == 0) {
row_no = 1;
lua_newtable(L);
while (apr_dbd_get_row(res->driver, res->pool, res->results,
&row, -1) != -1)
{
lua_pushinteger(L, row_no);
lua_newtable(L);
for (x = 0; x < res->cols; x++) {
entry = apr_dbd_get_entry(res->driver, row, x);
if (entry) {
if (alpha == 1) {
rowname = apr_dbd_get_name(res->driver,
res->results, x);
lua_pushstring(L, rowname ? rowname : "(oob)");
}
else {
lua_pushinteger(L, x + 1);
}
lua_pushstring(L, entry);
lua_rawset(L, -3);
}
}
lua_rawset(L, -3);
row_no++;
}
return 1;
}
/* Just fetch a single row */
if (apr_dbd_get_row(res->driver, res->pool, res->results,
&row, row_no) != -1)
{
lua_newtable(L);
for (x = 0; x < res->cols; x++) {
entry = apr_dbd_get_entry(res->driver, row, x);
if (entry) {
if (alpha == 1) {
rowname = apr_dbd_get_name(res->driver,
res->results, x);
lua_pushstring(L, rowname ? rowname : "(oob)");
}
else {
lua_pushinteger(L, x + 1);
}
lua_pushstring(L, entry);
lua_rawset(L, -3);
}
}
return 1;
}
return 0;
}
/*
=============================================================================
db:select(statement): Queries the database for the given statement and
returns the rows/columns found as a table. If an error is encountered,
returns nil as the first parameter and the error message as the second.
=============================================================================
*/
int lua_db_select(lua_State *L)
{
/*~~~~~~~~~~~~~~~~~~~~~~~*/
lua_db_handle *db = 0;
apr_status_t rc = 0;
const char *statement;
request_rec *r;
/*~~~~~~~~~~~~~~~~~~~~~~~*/
r = ap_lua_check_request_rec(L, 2);
if (r) {
luaL_checktype(L, 3, LUA_TSTRING);
statement = lua_tostring(L, 3);
db = lua_get_db_handle(L);
if (db && db->alive) {
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
int cols;
apr_dbd_results_t *results = 0;
lua_db_result_set* resultset = NULL;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
rc = apr_dbd_select(db->driver, db->pool, db->handle,
&results, statement, 0);
if (rc == APR_SUCCESS) {
cols = apr_dbd_num_cols(db->driver, results);
if (cols > 0) {
lua_newtable(L);
resultset = lua_newuserdata(L, sizeof(lua_db_result_set));
resultset->cols = cols;
resultset->driver = db->driver;
resultset->pool = db->pool;
resultset->rows = apr_dbd_num_tuples(db->driver, results);
resultset->results = results;
luaL_newmetatable(L, "lua_apr.dbselect");
lua_pushliteral(L, "__call");
lua_pushcfunction(L, lua_db_get_row);
lua_rawset(L, -3);
lua_setmetatable(L, -3);
lua_rawseti(L, -2, 0);
return 1;
}
return 0;
}
else {
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
const char *err = apr_dbd_error(db->driver, db->handle, rc);
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
lua_pushnil(L);
if (err) {
lua_pushstring(L, err);
return 2;
}
}
}
lua_pushboolean(L, 0);
return 1;
}
return 0;
}
/*
=============================================================================
statement:select(var1, var2, var3...): Injects variables into a prepared
statement and returns the number of rows matching the query.
=============================================================================
*/
int lua_db_prepared_select(lua_State *L)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
lua_db_prepared_statement *st = 0;
apr_status_t rc = 0;
const char **vars;
int x, have;
/*~~~~~~~~~~~~~~~~~~~~~~~*/
/* Fetch the prepared statement and the vars passed */
luaL_checktype(L, 1, LUA_TTABLE);
lua_rawgeti(L, 1, 0);
luaL_checktype(L, -1, LUA_TUSERDATA);
st = (lua_db_prepared_statement*) lua_topointer(L, -1);
/* Check if we got enough variables passed on to us.
* This, of course, only works for prepared statements made through lua. */
have = lua_gettop(L) - 2;
if (st->variables != -1 && have < st->variables ) {
lua_pushboolean(L, 0);
lua_pushfstring(L,
"Error in executing prepared statement: Expected %d arguments, got %d.",
st->variables, have);
return 2;
}
vars = apr_pcalloc(st->db->pool, have*sizeof(char *));
for (x = 0; x < have; x++) {
vars[x] = lua_tostring(L, x + 2);
}
/* Fire off the query */
if (st->db && st->db->alive) {
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
int cols;
apr_dbd_results_t *results = 0;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
rc = apr_dbd_pselect(st->db->driver, st->db->pool, st->db->handle,
&results, st->statement, 0, have, vars);
if (rc == APR_SUCCESS) {
/*~~~~~~~~~~~~~~~~~~~~~*/
lua_db_result_set *resultset;
/*~~~~~~~~~~~~~~~~~~~~~*/
cols = apr_dbd_num_cols(st->db->driver, results);
lua_newtable(L);
resultset = lua_newuserdata(L, sizeof(lua_db_result_set));
resultset->cols = cols;
resultset->driver = st->db->driver;
resultset->pool = st->db->pool;
resultset->rows = apr_dbd_num_tuples(st->db->driver, results);
resultset->results = results;
luaL_newmetatable(L, "lua_apr.dbselect");
lua_pushliteral(L, "__call");
lua_pushcfunction(L, lua_db_get_row);
lua_rawset(L, -3);
lua_setmetatable(L, -3);
lua_rawseti(L, -2, 0);
return 1;
}
else {
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
const char *err = apr_dbd_error(st->db->driver, st->db->handle, rc);
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
lua_pushnil(L);
if (err) {
lua_pushstring(L, err);
return 2;
}
return 1;
}
}
lua_pushboolean(L, 0);
lua_pushliteral(L,
"Database connection seems to be closed, please reacquire it.");
return (2);
}
/*
=============================================================================
statement:query(var1, var2, var3...): Injects variables into a prepared
statement and returns the number of rows affected.
=============================================================================
*/
int lua_db_prepared_query(lua_State *L)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
lua_db_prepared_statement *st = 0;
apr_status_t rc = 0;
const char **vars;
int x, have;
/*~~~~~~~~~~~~~~~~~~~~~~~*/
/* Fetch the prepared statement and the vars passed */
luaL_checktype(L, 1, LUA_TTABLE);
lua_rawgeti(L, 1, 0);
luaL_checktype(L, -1, LUA_TUSERDATA);
st = (lua_db_prepared_statement*) lua_topointer(L, -1);
/* Check if we got enough variables passed on to us.
* This, of course, only works for prepared statements made through lua. */
have = lua_gettop(L) - 2;
if (st->variables != -1 && have < st->variables ) {
lua_pushboolean(L, 0);
lua_pushfstring(L,
"Error in executing prepared statement: Expected %d arguments, got %d.",
st->variables, have);
return 2;
}
vars = apr_pcalloc(st->db->pool, have*sizeof(char *));
for (x = 0; x < have; x++) {
vars[x] = lua_tostring(L, x + 2);
}
/* Fire off the query */
if (st->db && st->db->alive) {
/*~~~~~~~~~~~~~~*/
int affected = 0;
/*~~~~~~~~~~~~~~*/
rc = apr_dbd_pquery(st->db->driver, st->db->pool, st->db->handle,
&affected, st->statement, have, vars);
if (rc == APR_SUCCESS) {
lua_pushinteger(L, affected);
return 1;
}
else {
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
const char *err = apr_dbd_error(st->db->driver, st->db->handle, rc);
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
lua_pushnil(L);
if (err) {
lua_pushstring(L, err);
return 2;
}
return 1;
}
}
lua_pushboolean(L, 0);
lua_pushliteral(L,
"Database connection seems to be closed, please reacquire it.");
return (2);
}
/*
=============================================================================
db:prepare(statement): Prepares a statement for later query/select.
Returns a table with a :query and :select function, same as the db funcs.
=============================================================================
*/
int lua_db_prepare(lua_State* L)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~*/
lua_db_handle *db = 0;
apr_status_t rc = 0;
const char *statement, *at;
request_rec *r;
lua_db_prepared_statement* st;
int need = 0;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~*/
r = ap_lua_check_request_rec(L, 2);
if (r) {
apr_dbd_prepared_t *pstatement = NULL;
luaL_checktype(L, 3, LUA_TSTRING);
statement = lua_tostring(L, 3);
/* Count number of variables in statement */
at = ap_strchr_c(statement,'%');
while (at != NULL) {
if (at[1] == '%') {
at++;
}
else {
need++;
}
at = ap_strchr_c(at+1,'%');
}
db = lua_get_db_handle(L);
rc = apr_dbd_prepare(db->driver, r->pool, db->handle, statement,
NULL, &pstatement);
if (rc != APR_SUCCESS) {
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
const char *err = apr_dbd_error(db->driver, db->handle, rc);
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
lua_pushnil(L);
if (err) {
lua_pushstring(L, err);
return 2;
}
return 1;
}
/* Push the prepared statement table */
lua_newtable(L);
st = lua_newuserdata(L, sizeof(lua_db_prepared_statement));
st->statement = pstatement;
st->variables = need;
st->db = db;
lua_pushliteral(L, "select");
lua_pushcfunction(L, lua_db_prepared_select);
lua_rawset(L, -4);
lua_pushliteral(L, "query");
lua_pushcfunction(L, lua_db_prepared_query);
lua_rawset(L, -4);
lua_rawseti(L, -2, 0);
return 1;
}
return 0;
}
/*
=============================================================================
db:prepared(statement): Fetches a prepared statement made through
DBDPrepareSQL.
=============================================================================
*/
int lua_db_prepared(lua_State* L)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~*/
lua_db_handle *db = 0;
const char *tag;
request_rec *r;
lua_db_prepared_statement* st;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~*/
r = ap_lua_check_request_rec(L, 2);
if (r) {
apr_dbd_prepared_t *pstatement = NULL;
db = lua_get_db_handle(L);
luaL_checktype(L, 3, LUA_TSTRING);
tag = lua_tostring(L, 3);
/* Look for the statement */
pstatement = apr_hash_get(db->dbdhandle->prepared, tag,
APR_HASH_KEY_STRING);
if (pstatement == NULL) {
lua_pushnil(L);
lua_pushfstring(L,
"Could not find any prepared statement called %s!", tag);
return 2;
}
/* Push the prepared statement table */
lua_newtable(L);
st = lua_newuserdata(L, sizeof(lua_db_prepared_statement));
st->statement = pstatement;
st->variables = -1; /* we don't know :( */
st->db = db;
lua_pushliteral(L, "select");
lua_pushcfunction(L, lua_db_prepared_select);
lua_rawset(L, -4);
lua_pushliteral(L, "query");
lua_pushcfunction(L, lua_db_prepared_query);
lua_rawset(L, -4);
lua_rawseti(L, -2, 0);
return 1;
}
return 0;
}
/* lua_push_db_handle: Creates a database table object with database functions
and a userdata at index 0, which will call lua_dbgc when garbage collected.
*/
static lua_db_handle* lua_push_db_handle(lua_State *L, request_rec* r, int type,
apr_pool_t* pool)
{
lua_db_handle* db;
lua_newtable(L);
db = lua_newuserdata(L, sizeof(lua_db_handle));
db->alive = 1;
db->pool = pool;
db->type = type;
db->dbdhandle = 0;
db->server = r->server;
luaL_newmetatable(L, "lua_apr.dbacquire");
lua_pushliteral(L, "__gc");
lua_pushcfunction(L, lua_db_gc);
lua_rawset(L, -3);
lua_setmetatable(L, -2);
lua_rawseti(L, -2, 0);
lua_pushliteral(L, "escape");
lua_pushcfunction(L, lua_db_escape);
lua_rawset(L, -3);
lua_pushliteral(L, "close");
lua_pushcfunction(L, lua_db_close);
lua_rawset(L, -3);
lua_pushliteral(L, "select");
lua_pushcfunction(L, lua_db_select);
lua_rawset(L, -3);
lua_pushliteral(L, "query");
lua_pushcfunction(L, lua_db_query);
lua_rawset(L, -3);
lua_pushliteral(L, "active");
lua_pushcfunction(L, lua_db_active);
lua_rawset(L, -3);
lua_pushliteral(L, "prepare");
lua_pushcfunction(L, lua_db_prepare);
lua_rawset(L, -3);
lua_pushliteral(L, "prepared");
lua_pushcfunction(L, lua_db_prepared);
lua_rawset(L, -3);
return db;
}
/*
=============================================================================
dbacquire(dbType, dbString): Opens a new connection to a database of type
_dbType_ and with the connection parameters _dbString_. If successful,
returns a table with functions for using the database handle. If an error
occurs, returns nil as the first parameter and the error message as the
second. See the APR_DBD for a list of database types and connection strings
supported.
=============================================================================
*/
int lua_db_acquire(lua_State *L)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
const char *type;
const char *arguments;
const char *error = 0;
request_rec *r;
lua_db_handle *db = 0;
apr_status_t rc = 0;
ap_dbd_t *dbdhandle = NULL;
apr_pool_t *pool = NULL;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
r = ap_lua_check_request_rec(L, 1);
if (r) {
type = luaL_optstring(L, 2, "mod_dbd"); /* Defaults to mod_dbd */
if (!strcmp(type, "mod_dbd")) {
lua_settop(L, 0);
lua_ap_dbd_open = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_open);
if (lua_ap_dbd_open)
dbdhandle = (ap_dbd_t *) lua_ap_dbd_open(
r->server->process->pool, r->server);
if (dbdhandle) {
db = lua_push_db_handle(L, r, LUA_DBTYPE_MOD_DBD, dbdhandle->pool);
db->driver = dbdhandle->driver;
db->handle = dbdhandle->handle;
db->dbdhandle = dbdhandle;
return 1;
}
else {
lua_pushnil(L);
if ( lua_ap_dbd_open == NULL )
lua_pushliteral(L,
"mod_dbd doesn't seem to have been loaded.");
else
lua_pushliteral(
L,
"Could not acquire connection from mod_dbd. If your database is running, this may indicate a permission problem.");
return 2;
}
}
else {
rc = apr_pool_create(&pool, NULL);
if (rc != APR_SUCCESS) {
lua_pushnil(L);
lua_pushliteral(L, "Could not allocate memory for database!");
return 2;
}
apr_pool_tag(pool, "lua_dbd_pool");
apr_dbd_init(pool);
dbdhandle = apr_pcalloc(pool, sizeof(ap_dbd_t));
rc = apr_dbd_get_driver(pool, type, &dbdhandle->driver);
if (rc == APR_SUCCESS) {
luaL_checktype(L, 3, LUA_TSTRING);
arguments = lua_tostring(L, 3);
lua_settop(L, 0);
if (strlen(arguments)) {
rc = apr_dbd_open_ex(dbdhandle->driver, pool,
arguments, &dbdhandle->handle, &error);
if (rc == APR_SUCCESS) {
db = lua_push_db_handle(L, r, LUA_DBTYPE_APR_DBD, pool);
db->driver = dbdhandle->driver;
db->handle = dbdhandle->handle;
db->dbdhandle = dbdhandle;
return 1;
}
else {
lua_pushnil(L);
if (error) {
lua_pushstring(L, error);
return 2;
}
return 1;
}
}
lua_pushnil(L);
lua_pushliteral(L,
"No database connection string was specified.");
apr_pool_destroy(pool);
return (2);
}
else {
lua_pushnil(L);
if (APR_STATUS_IS_ENOTIMPL(rc)) {
lua_pushfstring(L,
"driver for %s not available", type);
}
else if (APR_STATUS_IS_EDSOOPEN(rc)) {
lua_pushfstring(L,
"can't find driver for %s", type);
}
else if (APR_STATUS_IS_ESYMNOTFOUND(rc)) {
lua_pushfstring(L,
"driver for %s is invalid or corrupted",
type);
}
else {
lua_pushliteral(L,
"mod_lua not compatible with APR in get_driver");
}
lua_pushinteger(L, rc);
apr_pool_destroy(pool);
return 3;
}
}
lua_pushnil(L);
return 1;
}
return 0;
}