Blame modules/lua/lua_dbd.c

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