1/**
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18
19#include "mod_lua.h"
20#include "lua_dbd.h"
21
22APLOG_USE_MODULE(lua);
23static APR_OPTIONAL_FN_TYPE(ap_dbd_close) *lua_ap_dbd_close = NULL;
24static APR_OPTIONAL_FN_TYPE(ap_dbd_open) *lua_ap_dbd_open = NULL;
25
26
27
28
29static request_rec *ap_lua_check_request_rec(lua_State *L, int index)
30{
31    request_rec *r;
32    luaL_checkudata(L, index, "Apache2.Request");
33    r = lua_unboxpointer(L, index);
34    return r;
35}
36
37static lua_db_handle *lua_get_db_handle(lua_State *L)
38{
39    luaL_checktype(L, 1, LUA_TTABLE);
40    lua_rawgeti(L, 1, 0);
41    luaL_checktype(L, -1, LUA_TUSERDATA);
42    return (lua_db_handle *) lua_topointer(L, -1);
43}
44
45static lua_db_result_set *lua_get_result_set(lua_State *L)
46{
47    luaL_checktype(L, 1, LUA_TTABLE);
48    lua_rawgeti(L, 1, 0);
49    luaL_checktype(L, -1, LUA_TUSERDATA);
50    return (lua_db_result_set *) lua_topointer(L, -1);
51}
52
53
54/*
55   =============================================================================
56    db:close(): Closes an open database connection.
57   =============================================================================
58 */
59int lua_db_close(lua_State *L)
60{
61    /*~~~~~~~~~~~~~~~~~~~~*/
62    lua_db_handle   *db;
63    apr_status_t     rc = 0;
64    /*~~~~~~~~~~~~~~~~~~~~*/
65
66    db = lua_get_db_handle(L);
67    if (db && db->alive) {
68        if (db->type == LUA_DBTYPE_APR_DBD) {
69            rc = apr_dbd_close(db->driver, db->handle);
70            if (db->pool) apr_pool_destroy(db->pool);
71        }
72        else {
73            lua_ap_dbd_close = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_close);
74            if (lua_ap_dbd_close != NULL)
75                if (db->dbdhandle) lua_ap_dbd_close(db->server, db->dbdhandle);
76        }
77
78        db->driver = NULL;
79        db->handle = NULL;
80        db->alive = 0;
81        db->pool = NULL;
82    }
83
84    lua_settop(L, 0);
85    lua_pushnumber(L, rc);
86    return 1;
87}
88
89/*
90   =============================================================================
91     db:__gc(): Garbage collecting function.
92   =============================================================================
93 */
94int lua_db_gc(lua_State *L)
95{
96    /*~~~~~~~~~~~~~~~~*/
97    lua_db_handle    *db;
98    /*~~~~~~~~~~~~~~~~~~~~*/
99
100    db = lua_touserdata(L, 1);
101    if (db && db->alive) {
102        if (db->type == LUA_DBTYPE_APR_DBD) {
103            apr_dbd_close(db->driver, db->handle);
104            if (db->pool) apr_pool_destroy(db->pool);
105        }
106        else {
107            lua_ap_dbd_close = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_close);
108            if (lua_ap_dbd_close != NULL)
109                if (db->dbdhandle) lua_ap_dbd_close(db->server, db->dbdhandle);
110        }
111        db->driver = NULL;
112        db->handle = NULL;
113        db->alive = 0;
114        db->pool = NULL;
115    }
116    lua_settop(L, 0);
117    return 0;
118}
119
120/*
121   =============================================================================
122    db:active(): Returns true if the connection to the db is still active.
123   =============================================================================
124 */
125int lua_db_active(lua_State *L)
126{
127    /*~~~~~~~~~~~~~~~~~~~~*/
128    lua_db_handle   *db = 0;
129    apr_status_t     rc = 0;
130    /*~~~~~~~~~~~~~~~~~~~~*/
131
132    db = lua_get_db_handle(L);
133    if (db && db->alive) {
134        rc = apr_dbd_check_conn(db->driver, db->pool, db->handle);
135        if (rc == APR_SUCCESS) {
136            lua_pushboolean(L, 1);
137            return 1;
138        }
139    }
140
141    lua_pushboolean(L, 0);
142    return 1;
143}
144
145/*
146   =============================================================================
147    db:query(statement): Executes the given database query and returns the
148    number of rows affected. If an error is encountered, returns nil as the
149    first parameter and the error message as the second.
150   =============================================================================
151 */
152int lua_db_query(lua_State *L)
153{
154    /*~~~~~~~~~~~~~~~~~~~~~~~*/
155    lua_db_handle   *db = 0;
156    apr_status_t     rc = 0;
157    int              x = 0;
158    const char      *statement;
159    /*~~~~~~~~~~~~~~~~~~~~~~~*/
160    luaL_checktype(L, 3, LUA_TSTRING);
161    statement = lua_tostring(L, 3);
162    db = lua_get_db_handle(L);
163    if (db && db->alive)
164        rc = apr_dbd_query(db->driver, db->handle, &x, statement);
165    else {
166        rc = 0;
167        x = -1;
168    }
169
170    if (rc == APR_SUCCESS)
171        lua_pushnumber(L, x);
172    else {
173
174        /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
175        const char  *err = apr_dbd_error(db->driver, db->handle, rc);
176        /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
177
178        lua_pushnil(L);
179        if (err) {
180            lua_pushstring(L, err);
181            return 2;
182        }
183    }
184
185    return 1;
186}
187
188/*
189   =============================================================================
190    db:escape(string): Escapes a string for safe use in the given database type.
191   =============================================================================
192 */
193int lua_db_escape(lua_State *L)
194{
195    /*~~~~~~~~~~~~~~~~~~~~~*/
196    lua_db_handle    *db = 0;
197    const char       *statement;
198    const char       *escaped = 0;
199    request_rec      *r;
200    /*~~~~~~~~~~~~~~~~~~~~~*/
201
202    r = ap_lua_check_request_rec(L, 2);
203    if (r) {
204        luaL_checktype(L, 3, LUA_TSTRING);
205        statement = lua_tostring(L, 3);
206        db = lua_get_db_handle(L);
207        if (db && db->alive) {
208            apr_dbd_init(r->pool);
209            escaped = apr_dbd_escape(db->driver, r->pool, statement,
210                                     db->handle);
211            if (escaped) {
212                lua_pushstring(L, escaped);
213                return 1;
214            }
215        }
216        else {
217            lua_pushnil(L);
218        }
219        return (1);
220    }
221
222    return 0;
223}
224
225/*
226   =============================================================================
227     resultset(N): Fetches one or more rows from a result set.
228   =============================================================================
229 */
230int lua_db_get_row(lua_State *L)
231{
232    int row_no,x,alpha = 0;
233    const char      *entry, *rowname;
234    apr_dbd_row_t   *row = 0;
235    lua_db_result_set *res = lua_get_result_set(L);
236
237    row_no = luaL_optinteger(L, 2, 0);
238    if (lua_isboolean(L, 3)) {
239        alpha = lua_toboolean(L, 3);
240    }
241    lua_settop(L,0);
242
243    /* Fetch all rows at once? */
244
245    if (row_no == 0) {
246        row_no = 1;
247        lua_newtable(L);
248        while (apr_dbd_get_row(res->driver, res->pool, res->results,
249                            &row, -1) != -1)
250         {
251            lua_pushinteger(L, row_no);
252            lua_newtable(L);
253            for (x = 0; x < res->cols; x++) {
254                entry = apr_dbd_get_entry(res->driver, row, x);
255                if (entry) {
256                    if (alpha == 1) {
257                        rowname = apr_dbd_get_name(res->driver,
258                                res->results, x);
259                        lua_pushstring(L, rowname ? rowname : "(oob)");
260                    }
261                    else {
262                        lua_pushinteger(L, x + 1);
263                    }
264                    lua_pushstring(L, entry);
265                    lua_rawset(L, -3);
266                }
267            }
268            lua_rawset(L, -3);
269            row_no++;
270        }
271        return 1;
272    }
273
274    /* Just fetch a single row */
275    if (apr_dbd_get_row(res->driver, res->pool, res->results,
276                            &row, row_no) != -1)
277         {
278
279        lua_newtable(L);
280        for (x = 0; x < res->cols; x++) {
281            entry = apr_dbd_get_entry(res->driver, row, x);
282            if (entry) {
283                if (alpha == 1) {
284                    rowname = apr_dbd_get_name(res->driver,
285                            res->results, x);
286                    lua_pushstring(L, rowname ? rowname : "(oob)");
287                }
288                else {
289                    lua_pushinteger(L, x + 1);
290                }
291                lua_pushstring(L, entry);
292                lua_rawset(L, -3);
293            }
294        }
295        return 1;
296    }
297    return 0;
298}
299
300
301/*
302   =============================================================================
303    db:select(statement): Queries the database for the given statement and
304    returns the rows/columns found as a table. If an error is encountered,
305    returns nil as the first parameter and the error message as the second.
306   =============================================================================
307 */
308int lua_db_select(lua_State *L)
309{
310    /*~~~~~~~~~~~~~~~~~~~~~~~*/
311    lua_db_handle   *db = 0;
312    apr_status_t     rc = 0;
313    const char      *statement;
314    request_rec     *r;
315    /*~~~~~~~~~~~~~~~~~~~~~~~*/
316    r = ap_lua_check_request_rec(L, 2);
317    if (r) {
318        luaL_checktype(L, 3, LUA_TSTRING);
319        statement = lua_tostring(L, 3);
320        db = lua_get_db_handle(L);
321        if (db && db->alive) {
322
323            /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
324            int cols;
325            apr_dbd_results_t   *results = 0;
326            lua_db_result_set* resultset = NULL;
327            /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
328
329            rc = apr_dbd_select(db->driver, db->pool, db->handle,
330                                &results, statement, 0);
331            if (rc == APR_SUCCESS) {
332
333                cols = apr_dbd_num_cols(db->driver, results);
334
335                if (cols > 0) {
336                    lua_newtable(L);
337                    resultset = lua_newuserdata(L, sizeof(lua_db_result_set));
338                    resultset->cols = cols;
339                    resultset->driver = db->driver;
340                    resultset->pool = db->pool;
341                    resultset->rows = apr_dbd_num_tuples(db->driver, results);
342                    resultset->results = results;
343                    luaL_newmetatable(L, "lua_apr.dbselect");
344                    lua_pushliteral(L, "__call");
345                    lua_pushcfunction(L, lua_db_get_row);
346                    lua_rawset(L, -3);
347                    lua_setmetatable(L, -3);
348                    lua_rawseti(L, -2, 0);
349                    return 1;
350                }
351                return 0;
352            }
353            else {
354
355                /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
356                const char  *err = apr_dbd_error(db->driver, db->handle, rc);
357                /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
358
359                lua_pushnil(L);
360                if (err) {
361                    lua_pushstring(L, err);
362                    return 2;
363                }
364            }
365        }
366
367        lua_pushboolean(L, 0);
368        return 1;
369    }
370
371    return 0;
372}
373
374
375
376/*
377   =============================================================================
378    statement:select(var1, var2, var3...): Injects variables into a prepared
379    statement and returns the number of rows matching the query.
380   =============================================================================
381 */
382int lua_db_prepared_select(lua_State *L)
383{
384    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
385    lua_db_prepared_statement  *st = 0;
386    apr_status_t     rc = 0;
387    const char       **vars;
388    int              x, have;
389    /*~~~~~~~~~~~~~~~~~~~~~~~*/
390
391    /* Fetch the prepared statement and the vars passed */
392    luaL_checktype(L, 1, LUA_TTABLE);
393    lua_rawgeti(L, 1, 0);
394    luaL_checktype(L, -1, LUA_TUSERDATA);
395    st = (lua_db_prepared_statement*) lua_topointer(L, -1);
396
397    /* Check if we got enough variables passed on to us.
398     * This, of course, only works for prepared statements made through lua. */
399    have = lua_gettop(L) - 2;
400    if (st->variables != -1 && have < st->variables ) {
401        lua_pushboolean(L, 0);
402        lua_pushfstring(L,
403                "Error in executing prepared statement: Expected %d arguments, got %d.",
404                st->variables, have);
405        return 2;
406    }
407    vars = apr_pcalloc(st->db->pool, have*sizeof(char *));
408    for (x = 0; x < have; x++) {
409        vars[x] = lua_tostring(L, x + 2);
410    }
411
412    /* Fire off the query */
413    if (st->db && st->db->alive) {
414
415        /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
416        int cols;
417        apr_dbd_results_t   *results = 0;
418        /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
419
420        rc = apr_dbd_pselect(st->db->driver, st->db->pool, st->db->handle,
421                                &results, st->statement, 0, have, vars);
422        if (rc == APR_SUCCESS) {
423
424            /*~~~~~~~~~~~~~~~~~~~~~*/
425            lua_db_result_set *resultset;
426            /*~~~~~~~~~~~~~~~~~~~~~*/
427
428            cols = apr_dbd_num_cols(st->db->driver, results);
429            lua_newtable(L);
430            resultset = lua_newuserdata(L, sizeof(lua_db_result_set));
431            resultset->cols = cols;
432            resultset->driver = st->db->driver;
433            resultset->pool = st->db->pool;
434            resultset->rows = apr_dbd_num_tuples(st->db->driver, results);
435            resultset->results = results;
436            luaL_newmetatable(L, "lua_apr.dbselect");
437            lua_pushliteral(L, "__call");
438            lua_pushcfunction(L, lua_db_get_row);
439            lua_rawset(L, -3);
440            lua_setmetatable(L, -3);
441            lua_rawseti(L, -2, 0);
442            return 1;
443
444        }
445        else {
446
447            /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
448            const char  *err = apr_dbd_error(st->db->driver, st->db->handle, rc);
449            /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
450
451            lua_pushnil(L);
452            if (err) {
453                lua_pushstring(L, err);
454                return 2;
455            }
456            return 1;
457        }
458    }
459
460    lua_pushboolean(L, 0);
461    lua_pushliteral(L,
462            "Database connection seems to be closed, please reacquire it.");
463    return (2);
464}
465
466
467/*
468   =============================================================================
469    statement:query(var1, var2, var3...): Injects variables into a prepared
470    statement and returns the number of rows affected.
471   =============================================================================
472 */
473int lua_db_prepared_query(lua_State *L)
474{
475    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
476    lua_db_prepared_statement  *st = 0;
477    apr_status_t     rc = 0;
478    const char       **vars;
479    int              x, have;
480    /*~~~~~~~~~~~~~~~~~~~~~~~*/
481
482    /* Fetch the prepared statement and the vars passed */
483    luaL_checktype(L, 1, LUA_TTABLE);
484    lua_rawgeti(L, 1, 0);
485    luaL_checktype(L, -1, LUA_TUSERDATA);
486    st = (lua_db_prepared_statement*) lua_topointer(L, -1);
487
488    /* Check if we got enough variables passed on to us.
489     * This, of course, only works for prepared statements made through lua. */
490    have = lua_gettop(L) - 2;
491    if (st->variables != -1 && have < st->variables ) {
492        lua_pushboolean(L, 0);
493        lua_pushfstring(L,
494                "Error in executing prepared statement: Expected %d arguments, got %d.",
495                st->variables, have);
496        return 2;
497    }
498    vars = apr_pcalloc(st->db->pool, have*sizeof(char *));
499    for (x = 0; x < have; x++) {
500        vars[x] = lua_tostring(L, x + 2);
501    }
502
503    /* Fire off the query */
504    if (st->db && st->db->alive) {
505
506        /*~~~~~~~~~~~~~~*/
507        int affected = 0;
508        /*~~~~~~~~~~~~~~*/
509
510        rc = apr_dbd_pquery(st->db->driver, st->db->pool, st->db->handle,
511                                &affected, st->statement, have, vars);
512        if (rc == APR_SUCCESS) {
513            lua_pushinteger(L, affected);
514            return 1;
515        }
516        else {
517
518            /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
519            const char  *err = apr_dbd_error(st->db->driver, st->db->handle, rc);
520            /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
521
522            lua_pushnil(L);
523            if (err) {
524                lua_pushstring(L, err);
525                return 2;
526            }
527            return 1;
528        }
529    }
530
531    lua_pushboolean(L, 0);
532    lua_pushliteral(L,
533            "Database connection seems to be closed, please reacquire it.");
534    return (2);
535}
536
537/*
538   =============================================================================
539    db:prepare(statement): Prepares a statement for later query/select.
540    Returns a table with a :query and :select function, same as the db funcs.
541   =============================================================================
542 */
543int lua_db_prepare(lua_State* L)
544{
545    /*~~~~~~~~~~~~~~~~~~~~~~~~~~*/
546    lua_db_handle   *db = 0;
547    apr_status_t     rc = 0;
548    const char      *statement, *at;
549    request_rec     *r;
550    lua_db_prepared_statement* st;
551    int need = 0;
552    /*~~~~~~~~~~~~~~~~~~~~~~~~~~*/
553
554    r = ap_lua_check_request_rec(L, 2);
555    if (r) {
556        apr_dbd_prepared_t *pstatement = NULL;
557        luaL_checktype(L, 3, LUA_TSTRING);
558        statement = lua_tostring(L, 3);
559
560        /* Count number of variables in statement */
561        at = ap_strchr_c(statement,'%');
562        while (at != NULL) {
563            if (at[1] == '%') {
564                at++;
565            }
566            else {
567                need++;
568            }
569            at = ap_strchr_c(at+1,'%');
570        }
571
572
573        db = lua_get_db_handle(L);
574        rc = apr_dbd_prepare(db->driver, r->pool, db->handle, statement,
575                    NULL, &pstatement);
576        if (rc != APR_SUCCESS) {
577            /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
578            const char  *err = apr_dbd_error(db->driver, db->handle, rc);
579            /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
580
581            lua_pushnil(L);
582            if (err) {
583                lua_pushstring(L, err);
584                return 2;
585            }
586            return 1;
587        }
588
589        /* Push the prepared statement table */
590        lua_newtable(L);
591        st = lua_newuserdata(L, sizeof(lua_db_prepared_statement));
592        st->statement = pstatement;
593        st->variables = need;
594        st->db = db;
595
596        lua_pushliteral(L, "select");
597        lua_pushcfunction(L, lua_db_prepared_select);
598        lua_rawset(L, -4);
599        lua_pushliteral(L, "query");
600        lua_pushcfunction(L, lua_db_prepared_query);
601        lua_rawset(L, -4);
602        lua_rawseti(L, -2, 0);
603        return 1;
604    }
605    return 0;
606}
607
608
609
610/*
611   =============================================================================
612    db:prepared(statement): Fetches a prepared statement made through
613    DBDPrepareSQL.
614   =============================================================================
615 */
616int lua_db_prepared(lua_State* L)
617{
618    /*~~~~~~~~~~~~~~~~~~~~~~~~~~*/
619    lua_db_handle   *db = 0;
620    const char      *tag;
621    request_rec     *r;
622    lua_db_prepared_statement* st;
623    /*~~~~~~~~~~~~~~~~~~~~~~~~~~*/
624
625    r = ap_lua_check_request_rec(L, 2);
626    if (r) {
627        apr_dbd_prepared_t *pstatement = NULL;
628        db = lua_get_db_handle(L);
629        luaL_checktype(L, 3, LUA_TSTRING);
630        tag = lua_tostring(L, 3);
631
632        /* Look for the statement */
633        pstatement = apr_hash_get(db->dbdhandle->prepared, tag,
634                APR_HASH_KEY_STRING);
635
636        if (pstatement == NULL) {
637            lua_pushnil(L);
638            lua_pushfstring(L,
639                    "Could not find any prepared statement called %s!", tag);
640            return 2;
641        }
642
643
644        /* Push the prepared statement table */
645        lua_newtable(L);
646        st = lua_newuserdata(L, sizeof(lua_db_prepared_statement));
647        st->statement = pstatement;
648        st->variables = -1; /* we don't know :( */
649        st->db = db;
650        lua_pushliteral(L, "select");
651        lua_pushcfunction(L, lua_db_prepared_select);
652        lua_rawset(L, -4);
653        lua_pushliteral(L, "query");
654        lua_pushcfunction(L, lua_db_prepared_query);
655        lua_rawset(L, -4);
656        lua_rawseti(L, -2, 0);
657        return 1;
658    }
659    return 0;
660}
661
662
663
664/* lua_push_db_handle: Creates a database table object with database functions
665   and a userdata at index 0, which will call lua_dbgc when garbage collected.
666 */
667static lua_db_handle* lua_push_db_handle(lua_State *L, request_rec* r, int type,
668        apr_pool_t* pool)
669{
670    lua_db_handle* db;
671    lua_newtable(L);
672    db = lua_newuserdata(L, sizeof(lua_db_handle));
673    db->alive = 1;
674    db->pool = pool;
675    db->type = type;
676    db->dbdhandle = 0;
677    db->server = r->server;
678    luaL_newmetatable(L, "lua_apr.dbacquire");
679    lua_pushliteral(L, "__gc");
680    lua_pushcfunction(L, lua_db_gc);
681    lua_rawset(L, -3);
682    lua_setmetatable(L, -2);
683    lua_rawseti(L, -2, 0);
684
685    lua_pushliteral(L, "escape");
686    lua_pushcfunction(L, lua_db_escape);
687    lua_rawset(L, -3);
688
689    lua_pushliteral(L, "close");
690    lua_pushcfunction(L, lua_db_close);
691    lua_rawset(L, -3);
692
693    lua_pushliteral(L, "select");
694    lua_pushcfunction(L, lua_db_select);
695    lua_rawset(L, -3);
696
697    lua_pushliteral(L, "query");
698    lua_pushcfunction(L, lua_db_query);
699    lua_rawset(L, -3);
700
701    lua_pushliteral(L, "active");
702    lua_pushcfunction(L, lua_db_active);
703    lua_rawset(L, -3);
704
705    lua_pushliteral(L, "prepare");
706    lua_pushcfunction(L, lua_db_prepare);
707    lua_rawset(L, -3);
708
709    lua_pushliteral(L, "prepared");
710    lua_pushcfunction(L, lua_db_prepared);
711    lua_rawset(L, -3);
712    return db;
713}
714
715/*
716   =============================================================================
717    dbacquire(dbType, dbString): Opens a new connection to a database of type
718    _dbType_ and with the connection parameters _dbString_. If successful,
719    returns a table with functions for using the database handle. If an error
720    occurs, returns nil as the first parameter and the error message as the
721    second. See the APR_DBD for a list of database types and connection strings
722    supported.
723   =============================================================================
724 */
725int lua_db_acquire(lua_State *L)
726{
727    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
728    const char      *type;
729    const char      *arguments;
730    const char      *error = 0;
731    request_rec     *r;
732    lua_db_handle   *db = 0;
733    apr_status_t     rc = 0;
734    ap_dbd_t        *dbdhandle = NULL;
735    apr_pool_t      *pool = NULL;
736    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
737
738    r = ap_lua_check_request_rec(L, 1);
739    if (r) {
740        type = luaL_optstring(L, 2, "mod_dbd"); /* Defaults to mod_dbd */
741
742        if (!strcmp(type, "mod_dbd")) {
743
744            lua_settop(L, 0);
745            lua_ap_dbd_open = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_open);
746            if (lua_ap_dbd_open)
747                dbdhandle = (ap_dbd_t *) lua_ap_dbd_open(
748                        r->server->process->pool, r->server);
749
750            if (dbdhandle) {
751                db = lua_push_db_handle(L, r, LUA_DBTYPE_MOD_DBD, dbdhandle->pool);
752                db->driver = dbdhandle->driver;
753                db->handle = dbdhandle->handle;
754                db->dbdhandle = dbdhandle;
755                return 1;
756            }
757            else {
758                lua_pushnil(L);
759                if ( lua_ap_dbd_open == NULL )
760                    lua_pushliteral(L,
761                                    "mod_dbd doesn't seem to have been loaded.");
762                else
763                    lua_pushliteral(
764                        L,
765                        "Could not acquire connection from mod_dbd. If your database is running, this may indicate a permission problem.");
766                return 2;
767            }
768        }
769        else {
770            rc = apr_pool_create(&pool, NULL);
771            if (rc != APR_SUCCESS) {
772                lua_pushnil(L);
773                lua_pushliteral(L, "Could not allocate memory for database!");
774                return 2;
775            }
776            apr_pool_tag(pool, "lua_dbd_pool");
777            apr_dbd_init(pool);
778            dbdhandle = apr_pcalloc(pool, sizeof(ap_dbd_t));
779            rc = apr_dbd_get_driver(pool, type, &dbdhandle->driver);
780            if (rc == APR_SUCCESS) {
781                luaL_checktype(L, 3, LUA_TSTRING);
782                arguments = lua_tostring(L, 3);
783                lua_settop(L, 0);
784
785                if (strlen(arguments)) {
786                    rc = apr_dbd_open_ex(dbdhandle->driver, pool,
787                            arguments, &dbdhandle->handle, &error);
788                    if (rc == APR_SUCCESS) {
789                        db = lua_push_db_handle(L, r, LUA_DBTYPE_APR_DBD, pool);
790                        db->driver = dbdhandle->driver;
791                        db->handle = dbdhandle->handle;
792                        db->dbdhandle = dbdhandle;
793                        return 1;
794                    }
795                    else {
796                        lua_pushnil(L);
797                        if (error) {
798                            lua_pushstring(L, error);
799                            return 2;
800                        }
801
802                        return 1;
803                    }
804                }
805
806                lua_pushnil(L);
807                lua_pushliteral(L,
808                                "No database connection string was specified.");
809                apr_pool_destroy(pool);
810                return (2);
811            }
812            else {
813                lua_pushnil(L);
814                if (APR_STATUS_IS_ENOTIMPL(rc)) {
815                    lua_pushfstring(L,
816                         "driver for %s not available", type);
817                }
818                else if (APR_STATUS_IS_EDSOOPEN(rc)) {
819                    lua_pushfstring(L,
820                                "can't find driver for %s", type);
821                }
822                else if (APR_STATUS_IS_ESYMNOTFOUND(rc)) {
823                    lua_pushfstring(L,
824                                "driver for %s is invalid or corrupted",
825                                type);
826                }
827                else {
828                    lua_pushliteral(L,
829                                "mod_lua not compatible with APR in get_driver");
830                }
831                lua_pushinteger(L, rc);
832                apr_pool_destroy(pool);
833                return 3;
834            }
835        }
836
837        lua_pushnil(L);
838        return 1;
839    }
840
841    return 0;
842}
843
844