]> granicus.if.org Git - apache/blob - modules/lua/lua_dbd.c
* mod_lua: fix compilation with lua-5.3
[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
19 #include "mod_lua.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
28
29 static 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
37 static 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
45 static 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  */
59 int 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  */
94 int 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  */
125 int 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  */
152 int 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  */
193 int 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  */
230 int 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  */
308 int 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  */
382 int 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  */
473 int 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  */
543 int 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  */
616 int 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  */
667 static 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  */
725 int 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