]> granicus.if.org Git - apache/blob - modules/lua/lua_dbd.c
CodeWarrior workaround for lua_dbd
[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
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 AP_LUA_DECLARE(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_MOD_DBD) {
69             rc = apr_dbd_close(db->driver, db->handle);
70         }
71         else {
72             lua_ap_dbd_close = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_close);
73             if (lua_ap_dbd_close != NULL)
74                 if (db->dbdhandle) lua_ap_dbd_close(db->server, db->dbdhandle);
75             if (db->pool) apr_pool_destroy(db->pool);
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 AP_LUA_DECLARE(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 AP_LUA_DECLARE(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 AP_LUA_DECLARE(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 AP_LUA_DECLARE(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 static int lua_db_get_row(lua_State *L) 
231 {
232     int row_no,x;
233     const char      *entry;
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     lua_settop(L,0);
239     
240     /* Fetch all rows at once? */
241     if (row_no == 0) {
242         row_no = 1;
243         lua_newtable(L);
244         while (apr_dbd_get_row(res->driver, res->pool, res->results,
245                             &row, -1) != -1)
246          {
247             lua_pushinteger(L, row_no);
248             lua_newtable(L);
249             for (x = 0; x < res->cols; x++) {
250                 entry = apr_dbd_get_entry(res->driver, row, x);
251                 if (entry) {
252                     lua_pushinteger(L, x + 1);
253                     lua_pushstring(L, entry);
254                     lua_rawset(L, -3);
255                 }
256             }
257             lua_rawset(L, -3);
258             row_no++;
259         }
260         return 1;
261     }
262     
263     /* Just fetch a single row */
264     if (apr_dbd_get_row(res->driver, res->pool, res->results,
265                             &row, row_no) != -1)
266          {
267         
268         lua_newtable(L);
269         for (x = 0; x < res->cols; x++) {
270             entry = apr_dbd_get_entry(res->driver, row, x);
271             if (entry) {
272                 lua_pushinteger(L, x + 1);
273                 lua_pushstring(L, entry);
274                 lua_rawset(L, -3);
275             }
276         }
277         return 1;
278     }
279     return 0;
280 }
281
282
283 /*
284    =============================================================================
285     db:select(statement): Queries the database for the given statement and 
286     returns the rows/columns found as a table. If an error is encountered, 
287     returns nil as the first parameter and the error message as the second.
288    =============================================================================
289  */
290 AP_LUA_DECLARE(int) lua_db_select(lua_State *L)
291 {
292     /*~~~~~~~~~~~~~~~~~~~~~~~*/
293     lua_db_handle   *db = 0;
294     apr_status_t     rc = 0;
295     const char      *statement;
296     request_rec     *r;
297     /*~~~~~~~~~~~~~~~~~~~~~~~*/
298     r = ap_lua_check_request_rec(L, 2);
299     if (r) {
300         luaL_checktype(L, 3, LUA_TSTRING);
301         statement = lua_tostring(L, 3);
302         db = lua_get_db_handle(L);
303         if (db && db->alive) {
304
305             /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
306             int cols;
307             apr_dbd_results_t   *results = 0;
308             lua_db_result_set* resultset = NULL;
309             /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
310
311             rc = apr_dbd_select(db->driver, db->pool, db->handle,
312                                 &results, statement, 0);
313             if (rc == APR_SUCCESS) {
314                 
315                 cols = apr_dbd_num_cols(db->driver, results);
316                 
317                 if (cols > 0) {
318                     lua_newtable(L);
319                     resultset = lua_newuserdata(L, sizeof(lua_db_result_set));
320                     resultset->cols = cols;
321                     resultset->driver = db->driver;
322                     resultset->pool = db->pool;
323                     resultset->rows = apr_dbd_num_tuples(db->driver, results);
324                     resultset->results = results;
325                     luaL_newmetatable(L, "lua_apr.dbselect");
326                     lua_pushliteral(L, "__call");
327                     lua_pushcfunction(L, lua_db_get_row);
328                     lua_rawset(L, -3);
329                     lua_setmetatable(L, -3);
330                     lua_rawseti(L, -2, 0);
331                     return 1;
332                 }
333                 return 0;
334             }
335             else {
336
337                 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
338                 const char  *err = apr_dbd_error(db->driver, db->handle, rc);
339                 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
340
341                 lua_pushnil(L);
342                 if (err) {
343                     lua_pushstring(L, err);
344                     return 2;
345                 }
346             }
347         }
348
349         lua_pushboolean(L, 0);
350         return 1;
351     }
352
353     return 0;
354 }
355
356
357
358 /*
359    =============================================================================
360     statement:select(var1, var2, var3...): Injects variables into a prepared 
361     statement and returns the number of rows matching the query.
362    =============================================================================
363  */
364 static int lua_db_prepared_select(lua_State *L)
365 {
366     /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
367     lua_db_prepared_statement  *st = 0;
368     apr_status_t     rc = 0;
369     const char       **vars;
370     int              x, have;
371     /*~~~~~~~~~~~~~~~~~~~~~~~*/
372     
373     /* Fetch the prepared statement and the vars passed */
374     luaL_checktype(L, 1, LUA_TTABLE);
375     lua_rawgeti(L, 1, 0);
376     luaL_checktype(L, -1, LUA_TUSERDATA);
377     st = (lua_db_prepared_statement*) lua_topointer(L, -1);
378     
379     /* Check if we got enough variables passed on to us.
380      * This, of course, only works for prepped statements made through lua. */
381     have = lua_gettop(L) - 2;
382     if (st->variables != -1 && have < st->variables ) {
383         lua_pushboolean(L, 0);
384         lua_pushfstring(L, 
385                 "Error in executing prepared statement: Expected %d arguments, got %d.", 
386                 st->variables, have);
387         return 2;
388     }
389     vars = apr_pcalloc(st->db->pool, have*sizeof(char *));
390     for (x = 0; x < have; x++) {
391         vars[x] = lua_tostring(L, x + 2);
392     }
393
394     /* Fire off the query */
395     if (st->db && st->db->alive) {
396
397         /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
398         int cols;
399         apr_dbd_results_t   *results = 0;
400         /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
401
402         rc = apr_dbd_pselect(st->db->driver, st->db->pool, st->db->handle,
403                                 &results, st->statement, 0, have, vars);
404         if (rc == APR_SUCCESS) {
405
406             /*~~~~~~~~~~~~~~~~~~~~~*/
407             lua_db_result_set *resultset;
408             /*~~~~~~~~~~~~~~~~~~~~~*/
409
410             cols = apr_dbd_num_cols(st->db->driver, results);
411             lua_newtable(L);
412             resultset = lua_newuserdata(L, sizeof(lua_db_result_set));
413             resultset->cols = cols;
414             resultset->driver = st->db->driver;
415             resultset->pool = st->db->pool;
416             resultset->rows = apr_dbd_num_tuples(st->db->driver, results);
417             resultset->results = results;
418             luaL_newmetatable(L, "lua_apr.dbselect");
419             lua_pushliteral(L, "__call");
420             lua_pushcfunction(L, lua_db_get_row);
421             lua_rawset(L, -3);
422             lua_setmetatable(L, -3);
423             lua_rawseti(L, -2, 0);
424             return 1;
425             
426         }
427         else {
428
429             /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
430             const char  *err = apr_dbd_error(st->db->driver, st->db->handle, rc);
431             /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
432
433             lua_pushnil(L);
434             if (err) {
435                 lua_pushstring(L, err);
436                 return 2;
437             }
438             return 1;
439         }
440     }
441
442     lua_pushboolean(L, 0);
443     lua_pushliteral(L, 
444             "Database connection seems to be closed, please reacquire it.");
445     return (2);
446 }
447
448
449 /*
450    =============================================================================
451     statement:query(var1, var2, var3...): Injects variables into a prepared 
452     statement and returns the number of rows affected.
453    =============================================================================
454  */
455 static int lua_db_prepared_query(lua_State *L)
456 {
457     /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
458     lua_db_prepared_statement  *st = 0;
459     apr_status_t     rc = 0;
460     const char       **vars;
461     int              x, have;
462     /*~~~~~~~~~~~~~~~~~~~~~~~*/
463     
464     /* Fetch the prepared statement and the vars passed */
465     luaL_checktype(L, 1, LUA_TTABLE);
466     lua_rawgeti(L, 1, 0);
467     luaL_checktype(L, -1, LUA_TUSERDATA);
468     st = (lua_db_prepared_statement*) lua_topointer(L, -1);
469     
470     /* Check if we got enough variables passed on to us.
471      * This, of course, only works for prepped statements made through lua. */
472     have = lua_gettop(L) - 2;
473     if (st->variables != -1 && have < st->variables ) {
474         lua_pushboolean(L, 0);
475         lua_pushfstring(L, 
476                 "Error in executing prepared statement: Expected %d arguments, got %d.", 
477                 st->variables, have);
478         return 2;
479     }
480     vars = apr_pcalloc(st->db->pool, have*sizeof(char *));
481     for (x = 0; x < have; x++) {
482         vars[x] = lua_tostring(L, x + 2);
483     }
484
485     /* Fire off the query */
486     if (st->db && st->db->alive) {
487
488         /*~~~~~~~~~~~~~~*/
489         int affected = 0;
490         /*~~~~~~~~~~~~~~*/
491
492         rc = apr_dbd_pquery(st->db->driver, st->db->pool, st->db->handle,
493                                 &affected, st->statement, have, vars);
494         if (rc == APR_SUCCESS) {
495             lua_pushinteger(L, affected);
496             return 1;
497         }
498         else {
499
500             /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
501             const char  *err = apr_dbd_error(st->db->driver, st->db->handle, rc);
502             /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
503
504             lua_pushnil(L);
505             if (err) {
506                 lua_pushstring(L, err);
507                 return 2;
508             }
509             return 1;
510         }
511     }
512
513     lua_pushboolean(L, 0);
514     lua_pushliteral(L, 
515             "Database connection seems to be closed, please reacquire it.");
516     return (2);
517 }
518
519 /*
520    =============================================================================
521     db:prepare(statement): Prepares a statement for later query/select.
522     Returns a table with a :query and :select function, same as the db funcs.
523    =============================================================================
524  */
525 AP_LUA_DECLARE(int) lua_db_prepare(lua_State* L) 
526 {
527     /*~~~~~~~~~~~~~~~~~~~~~~~~~~*/
528     lua_db_handle   *db = 0;
529     apr_status_t     rc = 0;
530     const char      *statement, *at;
531     request_rec     *r;
532     lua_db_prepared_statement* st;
533     int need = 0;
534     /*~~~~~~~~~~~~~~~~~~~~~~~~~~*/
535     
536     r = ap_lua_check_request_rec(L, 2);
537     if (r) {
538         apr_dbd_prepared_t *pstatement = NULL;
539         luaL_checktype(L, 3, LUA_TSTRING);
540         statement = lua_tostring(L, 3);
541         
542         /* Count number of variables in statement */
543         at = ap_strchr_c(statement,'%');
544         while (at != NULL) {
545             if (at[1] == '%') {
546                 at++;
547             }
548             else {
549                 need++;
550             }
551             at = ap_strchr_c(at+1,'%');
552         }
553         
554         
555         db = lua_get_db_handle(L);
556         rc = apr_dbd_prepare(db->driver, r->pool, db->handle, statement, 
557                     NULL, &pstatement);
558         if (rc != APR_SUCCESS) {
559             /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
560             const char  *err = apr_dbd_error(db->driver, db->handle, rc);
561             /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
562
563             lua_pushnil(L);
564             if (err) {
565                 lua_pushstring(L, err);
566                 return 2;
567             }
568             return 1;
569         }
570         
571         /* Push the prepared statement table */
572         lua_newtable(L);
573         st = lua_newuserdata(L, sizeof(lua_db_prepared_statement));
574         st->statement = pstatement;
575         st->variables = need;
576         st->db = db;
577         
578         lua_pushliteral(L, "select");
579         lua_pushcfunction(L, lua_db_prepared_select);
580         lua_rawset(L, -4);
581         lua_pushliteral(L, "query");
582         lua_pushcfunction(L, lua_db_prepared_query);
583         lua_rawset(L, -4);
584         lua_rawseti(L, -2, 0);
585         return 1;
586     }
587     return 0;
588 }
589
590
591
592 /*
593    =============================================================================
594     db:prepared(statement): Fetches a prepared statement made through 
595     DBDPrepareSQL.
596    =============================================================================
597  */
598 AP_LUA_DECLARE(int) lua_db_prepared(lua_State* L) 
599 {
600     /*~~~~~~~~~~~~~~~~~~~~~~~~~~*/
601     lua_db_handle   *db = 0;
602     const char      *tag;
603     request_rec     *r;
604     lua_db_prepared_statement* st;
605     /*~~~~~~~~~~~~~~~~~~~~~~~~~~*/
606     
607     r = ap_lua_check_request_rec(L, 2);
608     if (r) {
609         apr_dbd_prepared_t *pstatement = NULL;
610         db = lua_get_db_handle(L);
611         luaL_checktype(L, 3, LUA_TSTRING);
612         tag = lua_tostring(L, 3);
613         
614         /* Look for the statement */
615         pstatement = apr_hash_get(db->dbdhandle->prepared, tag, 
616                 APR_HASH_KEY_STRING);
617         
618         if (pstatement == NULL) {
619             lua_pushnil(L);
620             lua_pushfstring(L, 
621                     "Could not find any prepared statement called %s!", tag);
622             return 2;
623         }
624         
625         
626         /* Push the prepared statement table */
627         lua_newtable(L);
628         st = lua_newuserdata(L, sizeof(lua_db_prepared_statement));
629         st->statement = pstatement;
630         st->variables = -1; /* we don't know :( */
631         st->db = db;
632         lua_pushliteral(L, "select");
633         lua_pushcfunction(L, lua_db_prepared_select);
634         lua_rawset(L, -4);
635         lua_pushliteral(L, "query");
636         lua_pushcfunction(L, lua_db_prepared_query);
637         lua_rawset(L, -4);
638         lua_rawseti(L, -2, 0);
639         return 1;
640     }
641     return 0;
642 }
643
644
645
646 /* lua_push_db_handle: Creates a database table object with database functions 
647    and a userdata at index 0, which will call lua_dbgc when garbage collected.
648  */
649 static lua_db_handle* lua_push_db_handle(lua_State *L, request_rec* r, int type,
650         apr_pool_t* pool) 
651 {
652     lua_db_handle* db;
653     lua_newtable(L);
654     db = lua_newuserdata(L, sizeof(lua_db_handle));
655     db->alive = 1;
656     db->pool = pool;
657     db->type = type;
658     db->dbdhandle = 0;
659     db->server = r->server;
660     luaL_newmetatable(L, "lua_apr.dbacquire");
661     lua_pushliteral(L, "__gc");
662     lua_pushcfunction(L, lua_db_gc);
663     lua_rawset(L, -3);
664     lua_setmetatable(L, -2);
665     lua_rawseti(L, -2, 0);
666     
667     lua_pushliteral(L, "escape");
668     lua_pushcfunction(L, lua_db_escape);
669     lua_rawset(L, -3);
670     
671     lua_pushliteral(L, "close");
672     lua_pushcfunction(L, lua_db_close);
673     lua_rawset(L, -3);
674     
675     lua_pushliteral(L, "select");
676     lua_pushcfunction(L, lua_db_select);
677     lua_rawset(L, -3);
678     
679     lua_pushliteral(L, "query");
680     lua_pushcfunction(L, lua_db_query);
681     lua_rawset(L, -3);
682     
683     lua_pushliteral(L, "active");
684     lua_pushcfunction(L, lua_db_active);
685     lua_rawset(L, -3);
686     
687     lua_pushliteral(L, "prepare");
688     lua_pushcfunction(L, lua_db_prepare);
689     lua_rawset(L, -3);
690     
691     lua_pushliteral(L, "prepared");
692     lua_pushcfunction(L, lua_db_prepared);
693     lua_rawset(L, -3);
694     return db;
695 }
696
697 /*
698    =============================================================================
699     dbacquire(dbType, dbString): Opens a new connection to a database of type 
700     _dbType_ and with the connection parameters _dbString_. If successful, 
701     returns a table with functions for using the database handle. If an error 
702     occurs, returns nil as the first parameter and the error message as the 
703     second. See the APR_DBD for a list of database types and connection strings 
704     supported.
705    =============================================================================
706  */
707 AP_LUA_DECLARE(int) lua_db_acquire(lua_State *L)
708 {
709     /*~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
710     const char      *type;
711     const char      *arguments;
712     const char      *error = 0;
713     request_rec     *r;
714     lua_db_handle   *db = 0;
715     apr_status_t     rc = 0;
716     ap_dbd_t        *dbdhandle = NULL;
717     apr_pool_t      *pool = NULL;
718     /*~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
719
720     r = ap_lua_check_request_rec(L, 1);
721     if (r) {
722         type = luaL_optstring(L, 2, "mod_dbd"); /* Defaults to mod_dbd */
723         
724         if (!strcmp(type, "mod_dbd")) {
725
726             lua_settop(L, 0);
727             lua_ap_dbd_open = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_open);
728             if (lua_ap_dbd_open)
729                 dbdhandle = (ap_dbd_t *) lua_ap_dbd_open(
730                         r->server->process->pool, r->server);
731
732             if (dbdhandle) {
733                 db = lua_push_db_handle(L, r, LUA_DBTYPE_MOD_DBD, dbdhandle->pool);
734                 db->driver = dbdhandle->driver;
735                 db->handle = dbdhandle->handle;
736                 db->dbdhandle = dbdhandle;
737                 return 1;
738             }
739             else {
740                 lua_pushnil(L);
741                 if ( lua_ap_dbd_open == NULL )
742                     lua_pushliteral(L,
743                                     "mod_dbd doesn't seem to have been loaded.");
744                 else
745                     lua_pushliteral(
746                         L,
747                         "Could not acquire connection from mod_dbd. If your database is running, this may indicate a permission problem.");
748                 return 2;
749             }
750         }
751         else {
752             rc = apr_pool_create(&pool, NULL);
753             if (rc != APR_SUCCESS) {
754                 lua_pushnil(L);
755                 lua_pushliteral(L, "Could not allocate memory for database!");
756                 return 2;
757             }
758             apr_pool_tag(pool, "lua_dbd_pool");
759             apr_dbd_init(pool);
760             
761             rc = apr_dbd_get_driver(r->server->process->pool, type, &db->driver);
762             if (rc == APR_SUCCESS) {
763                 luaL_checktype(L, 3, LUA_TSTRING);
764                 arguments = lua_tostring(L, 3);
765                 lua_settop(L, 0);
766                 if (strlen(arguments)) {
767                     rc = apr_dbd_open_ex(db->driver, r->server->process->pool, 
768                             arguments, &db->handle, &error);
769                     if (rc == APR_SUCCESS) {
770                         db = lua_push_db_handle(L, r, LUA_DBTYPE_APR_DBD, pool);
771                         db->driver = dbdhandle->driver;
772                         db->handle = dbdhandle->handle;
773                         db->dbdhandle = dbdhandle;
774                         return 1;
775                     }
776                     else {
777                         lua_pushnil(L);
778                         if (error) {
779                             lua_pushstring(L, error);
780                             return 2;
781                         }
782
783                         return 1;
784                     }
785                 }
786
787                 lua_pushnil(L);
788                 lua_pushliteral(L,
789                                 "No database connection string was specified.");
790                 return (2);
791             }
792             else {
793                 lua_pushnil(L);
794                 if (APR_STATUS_IS_ENOTIMPL(rc)) {
795                     lua_pushfstring(L, 
796                          "driver for %s not available", type);
797                 }
798                 else if (APR_STATUS_IS_EDSOOPEN(rc)) {
799                     lua_pushfstring(L, 
800                                 "can't find driver for %s", type);
801                 }
802                 else if (APR_STATUS_IS_ESYMNOTFOUND(rc)) {
803                     lua_pushfstring(L, 
804                                 "driver for %s is invalid or corrupted",
805                                 type);
806                 }
807                 else {
808                     lua_pushliteral(L, 
809                                 "mod_lua not compatible with APR in get_driver");
810                 }
811                 lua_pushinteger(L, rc);
812                 return 3;
813             }
814         }
815
816         lua_pushnil(L);
817         return 1;
818     }
819
820     return 0;
821 }
822