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