diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 06:33:50 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 06:33:50 +0000 |
commit | fe39ffb8b90ae4e002ed73fe98617cd590abb467 (patch) | |
tree | b80e5956907d8aeaaffe4e4f0c068c0e6157ce8b /modules/lua/lua_dbd.c | |
parent | Initial commit. (diff) | |
download | apache2-upstream.tar.xz apache2-upstream.zip |
Adding upstream version 2.4.56.upstream/2.4.56upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'modules/lua/lua_dbd.c')
-rw-r--r-- | modules/lua/lua_dbd.c | 843 |
1 files changed, 843 insertions, 0 deletions
diff --git a/modules/lua/lua_dbd.c b/modules/lua/lua_dbd.c new file mode 100644 index 0000000..1b8d5b7 --- /dev/null +++ b/modules/lua/lua_dbd.c @@ -0,0 +1,843 @@ +/** + * 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; +} + |