| /** |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| |
| #include "mod_lua.h" |
| #include "lua_dbd.h" |
| |
| APLOG_USE_MODULE(lua); |
| static APR_OPTIONAL_FN_TYPE(ap_dbd_close) *lua_ap_dbd_close = NULL; |
| static APR_OPTIONAL_FN_TYPE(ap_dbd_open) *lua_ap_dbd_open = NULL; |
| |
| |
| |
| |
| static request_rec *ap_lua_check_request_rec(lua_State *L, int index) |
| { |
| request_rec *r; |
| luaL_checkudata(L, index, "Apache2.Request"); |
| r = lua_unboxpointer(L, index); |
| return r; |
| } |
| |
| static lua_db_handle *lua_get_db_handle(lua_State *L) |
| { |
| luaL_checktype(L, 1, LUA_TTABLE); |
| lua_rawgeti(L, 1, 0); |
| luaL_checktype(L, -1, LUA_TUSERDATA); |
| return (lua_db_handle *) lua_topointer(L, -1); |
| } |
| |
| static lua_db_result_set *lua_get_result_set(lua_State *L) |
| { |
| luaL_checktype(L, 1, LUA_TTABLE); |
| lua_rawgeti(L, 1, 0); |
| luaL_checktype(L, -1, LUA_TUSERDATA); |
| return (lua_db_result_set *) lua_topointer(L, -1); |
| } |
| |
| |
| /* |
| ============================================================================= |
| db:close(): Closes an open database connection. |
| ============================================================================= |
| */ |
| int lua_db_close(lua_State *L) |
| { |
| /*~~~~~~~~~~~~~~~~~~~~*/ |
| lua_db_handle *db; |
| apr_status_t rc = 0; |
| /*~~~~~~~~~~~~~~~~~~~~*/ |
| |
| db = lua_get_db_handle(L); |
| if (db && db->alive) { |
| if (db->type == LUA_DBTYPE_APR_DBD) { |
| rc = apr_dbd_close(db->driver, db->handle); |
| if (db->pool) apr_pool_destroy(db->pool); |
| } |
| else { |
| lua_ap_dbd_close = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_close); |
| if (lua_ap_dbd_close != NULL) |
| if (db->dbdhandle) lua_ap_dbd_close(db->server, db->dbdhandle); |
| } |
| |
| db->driver = NULL; |
| db->handle = NULL; |
| db->alive = 0; |
| db->pool = NULL; |
| } |
| |
| lua_settop(L, 0); |
| lua_pushnumber(L, rc); |
| return 1; |
| } |
| |
| /* |
| ============================================================================= |
| db:__gc(): Garbage collecting function. |
| ============================================================================= |
| */ |
| int lua_db_gc(lua_State *L) |
| { |
| /*~~~~~~~~~~~~~~~~*/ |
| lua_db_handle *db; |
| /*~~~~~~~~~~~~~~~~~~~~*/ |
| |
| db = lua_touserdata(L, 1); |
| if (db && db->alive) { |
| if (db->type == LUA_DBTYPE_APR_DBD) { |
| apr_dbd_close(db->driver, db->handle); |
| if (db->pool) apr_pool_destroy(db->pool); |
| } |
| else { |
| lua_ap_dbd_close = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_close); |
| if (lua_ap_dbd_close != NULL) |
| if (db->dbdhandle) lua_ap_dbd_close(db->server, db->dbdhandle); |
| } |
| db->driver = NULL; |
| db->handle = NULL; |
| db->alive = 0; |
| db->pool = NULL; |
| } |
| lua_settop(L, 0); |
| return 0; |
| } |
| |
| /* |
| ============================================================================= |
| db:active(): Returns true if the connection to the db is still active. |
| ============================================================================= |
| */ |
| int lua_db_active(lua_State *L) |
| { |
| /*~~~~~~~~~~~~~~~~~~~~*/ |
| lua_db_handle *db = 0; |
| apr_status_t rc = 0; |
| /*~~~~~~~~~~~~~~~~~~~~*/ |
| |
| db = lua_get_db_handle(L); |
| if (db && db->alive) { |
| rc = apr_dbd_check_conn(db->driver, db->pool, db->handle); |
| if (rc == APR_SUCCESS) { |
| lua_pushboolean(L, 1); |
| return 1; |
| } |
| } |
| |
| lua_pushboolean(L, 0); |
| return 1; |
| } |
| |
| /* |
| ============================================================================= |
| db:query(statement): Executes the given database query and returns the |
| number of rows affected. If an error is encountered, returns nil as the |
| first parameter and the error message as the second. |
| ============================================================================= |
| */ |
| int lua_db_query(lua_State *L) |
| { |
| /*~~~~~~~~~~~~~~~~~~~~~~~*/ |
| lua_db_handle *db = 0; |
| apr_status_t rc = 0; |
| int x = 0; |
| const char *statement; |
| /*~~~~~~~~~~~~~~~~~~~~~~~*/ |
| luaL_checktype(L, 3, LUA_TSTRING); |
| statement = lua_tostring(L, 3); |
| db = lua_get_db_handle(L); |
| if (db && db->alive) |
| rc = apr_dbd_query(db->driver, db->handle, &x, statement); |
| else { |
| rc = 0; |
| x = -1; |
| } |
| |
| if (rc == APR_SUCCESS) |
| lua_pushnumber(L, x); |
| else { |
| |
| /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ |
| const char *err = apr_dbd_error(db->driver, db->handle, rc); |
| /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ |
| |
| lua_pushnil(L); |
| if (err) { |
| lua_pushstring(L, err); |
| return 2; |
| } |
| } |
| |
| return 1; |
| } |
| |
| /* |
| ============================================================================= |
| db:escape(string): Escapes a string for safe use in the given database type. |
| ============================================================================= |
| */ |
| int lua_db_escape(lua_State *L) |
| { |
| /*~~~~~~~~~~~~~~~~~~~~~*/ |
| lua_db_handle *db = 0; |
| const char *statement; |
| const char *escaped = 0; |
| 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) { |
| apr_dbd_init(r->pool); |
| escaped = apr_dbd_escape(db->driver, r->pool, statement, |
| db->handle); |
| if (escaped) { |
| lua_pushstring(L, escaped); |
| return 1; |
| } |
| } |
| else { |
| lua_pushnil(L); |
| } |
| return (1); |
| } |
| |
| return 0; |
| } |
| |
| /* |
| ============================================================================= |
| resultset(N): Fetches one or more rows from a result set. |
| ============================================================================= |
| */ |
| int lua_db_get_row(lua_State *L) |
| { |
| int row_no,x,alpha = 0; |
| 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 (*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; |
| } |
| |