mirror of
https://github.com/apache/httpd.git
synced 2025-08-08 15:02:10 +03:00
Add database features for mod_lua (apr_dbd + mod_dbd).
See documentation update for API and examples. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1430225 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
@@ -90,6 +90,7 @@ trust, as it can be abused to change the internal workings of httpd.</p>
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#logging">Logging Functions</a></li>
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#apache2">apache2 Package</a></li>
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#modifying_buckets">Modifying contents with Lua filters</a></li>
|
||||
<li><img alt="" src="../images/down.gif" /> <a href="#databases">Database connectivity</a></li>
|
||||
</ul><ul class="seealso"><li><a href="#comments_section">Comments</a></li></ul></div>
|
||||
<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
||||
<div class="section">
|
||||
@@ -875,6 +876,12 @@ r:custom_response(status_code, string) -- Construct and set a custom response fo
|
||||
r:sleep(number_of_seconds) -- Puts the script to sleep for a given number of seconds.
|
||||
</pre>
|
||||
|
||||
|
||||
<pre class="prettyprint lang-lua">
|
||||
r:dbacquire(dbType[, dbParams]) -- Acquires a connection to a database and returns a database class.
|
||||
-- See '<a href="#databases">Database connectivity</a>' for details.
|
||||
</pre>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
@@ -961,6 +968,174 @@ function filter(r)
|
||||
end
|
||||
</pre>
|
||||
|
||||
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
||||
<div class="section">
|
||||
<h2><a name="databases" id="databases">Database connectivity</a></h2>
|
||||
|
||||
<p>
|
||||
Mod_lua implements a simple database feature for querying and running commands
|
||||
on the most popular database engines (mySQL, PostgreSQL, FreeTDS, ODBC, SQLite, Oracle)
|
||||
as well as mod_dbd.
|
||||
</p>
|
||||
<p>Connecting and firing off queries is as easy as:</p>
|
||||
<pre class="prettyprint lang-lua">
|
||||
function handler(r)
|
||||
local database, err = r:dbacquire("mysql", "server=localhost&user=root&database=mydb")
|
||||
if not err then
|
||||
local results, err = database:select(r, "SELECT `name`, `age` FROM `people` WHERE 1")
|
||||
if not err then
|
||||
local rows = results(0) -- fetch all rows synchronously
|
||||
for k, row in pairs(rows) do
|
||||
r:puts( string.format("Name: %s, Age: %s<br/>", row[1], row[2]) )
|
||||
end
|
||||
else
|
||||
r:puts("Database query error: " .. err)
|
||||
end
|
||||
database:close()
|
||||
else
|
||||
r:puts("Could not connect to the database: " .. err)
|
||||
end
|
||||
end
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
To utilize <code class="module"><a href="../mod/mod_dbd.html">mod_dbd</a></code>, simply specify <code>mod_dbd</code>
|
||||
as the database type, or leave the field blank:
|
||||
</p>
|
||||
<pre class="prettyprint lang-lua">
|
||||
local database = r:dbacquire("mod_dbd")
|
||||
</pre>
|
||||
|
||||
<h3><a name="database_object" id="database_object">Database object and contained functions</a></h3>
|
||||
|
||||
<p>The database object returned by <code>dbacquire</code> has the following methods:</p>
|
||||
<p><strong>Normal select and query from a database:</strong></p>
|
||||
<pre class="prettyprint lang-lua">
|
||||
-- Run a statement and return the number of rows affected:
|
||||
local affected, errmsg = database:query(r, "DELETE FROM `tbl` WHERE 1")
|
||||
|
||||
-- Run a statement and return a result set that can be used synchronously or async:
|
||||
local result, errmsg = database:select(r, "SELECT * FROM `people` WHERE 1")
|
||||
</pre>
|
||||
|
||||
<p><strong>Using prepared statements (recommended):</strong></p>
|
||||
<pre class="prettyprint lang-lua">
|
||||
-- Create and run a prepared statement:
|
||||
local statement, errmsg = database:prepare(r, "DELETE FROM `tbl` WHERE `age` > %u")
|
||||
if not errmsg then
|
||||
local result, errmsg = statement:query(20) -- run the statement with age >20
|
||||
end
|
||||
|
||||
-- Fetch a prepared statement from a DBDPrepareSQL directive:
|
||||
local statement, errmsg = database:prepared(r, "someTag")
|
||||
if not errmsg then
|
||||
local result, errmsg = statement:select("John Doe", 123) -- inject the values "John Doe" and 123 into the statement
|
||||
end
|
||||
|
||||
</pre>
|
||||
|
||||
<p><strong>Escaping values, closing databases etc:</strong></p>
|
||||
<pre class="prettyprint lang-lua">
|
||||
-- Escape a value for use in a statement:
|
||||
local escaped = database:escape(r, [["'|blabla]])
|
||||
|
||||
-- Close a database connection and free up handles:
|
||||
database:close()
|
||||
|
||||
-- Check whether a database connection is up and running:
|
||||
local connected = database:active()
|
||||
</pre>
|
||||
|
||||
|
||||
<h3><a name="result_sets" id="result_sets">Working with result sets</a></h3>
|
||||
|
||||
<p>The result set returned by <code>db:query</code> or by the prepared statement functions
|
||||
created through <code>db:prepare</code> can be used to
|
||||
fetch rows synchronously or asynchronously, depending on the row number specified:<br />
|
||||
<code>result(0)</code> fetches all rows in a synchronous manner, returning a table of rows.<br />
|
||||
<code>result(-1)</code> fetches the next available row in the set, asynchronously.<br />
|
||||
<code>result(N)</code> fetches row number <code>N</code>, asynchronously:
|
||||
</p>
|
||||
<pre class="prettyprint lang-lua">
|
||||
-- fetch a result set using a regular query:
|
||||
local result, err = db:select(r, "SELECT * FROM `tbl` WHERE 1")
|
||||
|
||||
local rows = result(0) -- Fetch ALL rows synchronously
|
||||
local row = result(-1) -- Fetch the next available row, asynchronously
|
||||
local row = result(1234) -- Fetch row number 1234, asynchronously
|
||||
</pre>
|
||||
|
||||
<p>One can construct a function that returns an iterative function to iterate over all rows
|
||||
in a synchronous or asynchronous way, depending on the async argument:
|
||||
</p>
|
||||
<pre class="prettyprint lang-lua">
|
||||
function rows(resultset, async)
|
||||
local a = 0
|
||||
local function getnext()
|
||||
a = a + 1
|
||||
local row = resultset(-1)
|
||||
return row and a or nil, row
|
||||
end
|
||||
if not async then
|
||||
return pairs(resultset(0))
|
||||
else
|
||||
return getnext, self
|
||||
end
|
||||
end
|
||||
|
||||
local statement, err = db:prepare(r, "SELECT * FROM `tbl` WHERE `age` > %u")
|
||||
if not err then
|
||||
-- fetch rows asynchronously:
|
||||
local result, err = statement:select(20)
|
||||
if not err then
|
||||
for index, row in rows(result, true) do
|
||||
....
|
||||
end
|
||||
end
|
||||
|
||||
-- fetch rows synchronously:
|
||||
local result, err = statement:select(20)
|
||||
if not err then
|
||||
for index, row in rows(result, false) do
|
||||
....
|
||||
end
|
||||
end
|
||||
end
|
||||
</pre>
|
||||
|
||||
|
||||
<h3><a name="closing_databases" id="closing_databases">Closing a database connection</a></h3>
|
||||
|
||||
|
||||
<p>Database handles should be closed using <code>database:close()</code> when they are no longer
|
||||
needed. If you do not close them manually, they will eventually be garbage collected and
|
||||
closed by mod_lua, but you may end up having too many unused connections to the database
|
||||
if you leave the closing up to mod_lua. Essentially, the following two measures are
|
||||
the same:
|
||||
</p>
|
||||
<pre class="prettyprint lang-lua">
|
||||
-- Method 1: Manually close a handle
|
||||
local database = r:dbacquire("mod_dbd")
|
||||
database:close() -- All done
|
||||
|
||||
-- Method 2: Letting the garbage collector close it
|
||||
local database = r:dbacquire("mod_dbd")
|
||||
database = nil -- throw away the reference
|
||||
collectgarbage() -- close the handle via GC
|
||||
</pre>
|
||||
|
||||
|
||||
<h3><a name="database_caveat" id="database_caveat">Precautions when working with databases</a></h3>
|
||||
|
||||
<p>Although the standard <code>query</code> and <code>run</code> functions are freely
|
||||
available, it is recommended that you use prepared statements whenever possible, to
|
||||
both optimize performance (if your db handle lives on for a long time) and to minimize
|
||||
the risk of SQL injection attacks. <code>run</code> and <code>query</code> should only
|
||||
be used when there are no variables inserted into a statement (a static statement).
|
||||
When using dynamic statements, use <code>db:prepare</code> or <code>db:prepared</code>.
|
||||
</p>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
||||
<div class="directive-section"><h2><a name="LuaAuthzProvider" id="LuaAuthzProvider">LuaAuthzProvider</a> <a name="luaauthzprovider" id="luaauthzprovider">Directive</a></h2>
|
||||
|
@@ -794,6 +794,11 @@ r:custom_response(status_code, string) -- Construct and set a custom response fo
|
||||
<highlight language="lua">
|
||||
r:sleep(number_of_seconds) -- Puts the script to sleep for a given number of seconds.
|
||||
</highlight>
|
||||
|
||||
<highlight language="lua">
|
||||
r:dbacquire(dbType[, dbParams]) -- Acquires a connection to a database and returns a database class.
|
||||
-- See '<a href="#databases">Database connectivity</a>' for details.
|
||||
</highlight>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
@@ -880,6 +885,166 @@ end
|
||||
</highlight>
|
||||
</section>
|
||||
|
||||
<section id="databases">
|
||||
<title>Database connectivity</title>
|
||||
<p>
|
||||
Mod_lua implements a simple database feature for querying and running commands
|
||||
on the most popular database engines (mySQL, PostgreSQL, FreeTDS, ODBC, SQLite, Oracle)
|
||||
as well as mod_dbd.
|
||||
</p>
|
||||
<p>Connecting and firing off queries is as easy as:</p>
|
||||
<highlight language="lua">
|
||||
function handler(r)
|
||||
local database, err = r:dbacquire("mysql", "server=localhost&user=root&database=mydb")
|
||||
if not err then
|
||||
local results, err = database:select(r, "SELECT `name`, `age` FROM `people` WHERE 1")
|
||||
if not err then
|
||||
local rows = results(0) -- fetch all rows synchronously
|
||||
for k, row in pairs(rows) do
|
||||
r:puts( string.format("Name: %s, Age: %s<br/>", row[1], row[2]) )
|
||||
end
|
||||
else
|
||||
r:puts("Database query error: " .. err)
|
||||
end
|
||||
database:close()
|
||||
else
|
||||
r:puts("Could not connect to the database: " .. err)
|
||||
end
|
||||
end
|
||||
</highlight>
|
||||
<p>
|
||||
To utilize <module name="mod_dbd">mod_dbd</module>, simply specify <code>mod_dbd</code>
|
||||
as the database type, or leave the field blank:
|
||||
</p>
|
||||
<highlight language="lua">
|
||||
local database = r:dbacquire("mod_dbd")
|
||||
</highlight>
|
||||
<section id="database_object">
|
||||
<title>Database object and contained functions</title>
|
||||
<p>The database object returned by <code>dbacquire</code> has the following methods:</p>
|
||||
<p><strong>Normal select and query from a database:</strong></p>
|
||||
<highlight language="lua">
|
||||
-- Run a statement and return the number of rows affected:
|
||||
local affected, errmsg = database:query(r, "DELETE FROM `tbl` WHERE 1")
|
||||
|
||||
-- Run a statement and return a result set that can be used synchronously or async:
|
||||
local result, errmsg = database:select(r, "SELECT * FROM `people` WHERE 1")
|
||||
</highlight>
|
||||
<p><strong>Using prepared statements (recommended):</strong></p>
|
||||
<highlight language="lua">
|
||||
-- Create and run a prepared statement:
|
||||
local statement, errmsg = database:prepare(r, "DELETE FROM `tbl` WHERE `age` > %u")
|
||||
if not errmsg then
|
||||
local result, errmsg = statement:query(20) -- run the statement with age >20
|
||||
end
|
||||
|
||||
-- Fetch a prepared statement from a DBDPrepareSQL directive:
|
||||
local statement, errmsg = database:prepared(r, "someTag")
|
||||
if not errmsg then
|
||||
local result, errmsg = statement:select("John Doe", 123) -- inject the values "John Doe" and 123 into the statement
|
||||
end
|
||||
|
||||
</highlight>
|
||||
<p><strong>Escaping values, closing databases etc:</strong></p>
|
||||
<highlight language="lua">
|
||||
-- Escape a value for use in a statement:
|
||||
local escaped = database:escape(r, [["'|blabla]])
|
||||
|
||||
-- Close a database connection and free up handles:
|
||||
database:close()
|
||||
|
||||
-- Check whether a database connection is up and running:
|
||||
local connected = database:active()
|
||||
</highlight>
|
||||
</section>
|
||||
<section id="result_sets">
|
||||
<title>Working with result sets</title>
|
||||
<p>The result set returned by <code>db:select</code> or by the prepared statement functions
|
||||
created through <code>db:prepare</code> can be used to
|
||||
fetch rows synchronously or asynchronously, depending on the row number specified:<br/>
|
||||
<code>result(0)</code> fetches all rows in a synchronous manner, returning a table of rows.<br/>
|
||||
<code>result(-1)</code> fetches the next available row in the set, asynchronously.<br/>
|
||||
<code>result(N)</code> fetches row number <code>N</code>, asynchronously:
|
||||
</p>
|
||||
<highlight language="lua">
|
||||
-- fetch a result set using a regular query:
|
||||
local result, err = db:select(r, "SELECT * FROM `tbl` WHERE 1")
|
||||
|
||||
local rows = result(0) -- Fetch ALL rows synchronously
|
||||
local row = result(-1) -- Fetch the next available row, asynchronously
|
||||
local row = result(1234) -- Fetch row number 1234, asynchronously
|
||||
</highlight>
|
||||
<p>One can construct a function that returns an iterative function to iterate over all rows
|
||||
in a synchronous or asynchronous way, depending on the async argument:
|
||||
</p>
|
||||
<highlight language="lua">
|
||||
function rows(resultset, async)
|
||||
local a = 0
|
||||
local function getnext()
|
||||
a = a + 1
|
||||
local row = resultset(-1)
|
||||
return row and a or nil, row
|
||||
end
|
||||
if not async then
|
||||
return pairs(resultset(0))
|
||||
else
|
||||
return getnext, self
|
||||
end
|
||||
end
|
||||
|
||||
local statement, err = db:prepare(r, "SELECT * FROM `tbl` WHERE `age` > %u")
|
||||
if not err then
|
||||
-- fetch rows asynchronously:
|
||||
local result, err = statement:select(20)
|
||||
if not err then
|
||||
for index, row in rows(result, true) do
|
||||
....
|
||||
end
|
||||
end
|
||||
|
||||
-- fetch rows synchronously:
|
||||
local result, err = statement:select(20)
|
||||
if not err then
|
||||
for index, row in rows(result, false) do
|
||||
....
|
||||
end
|
||||
end
|
||||
end
|
||||
</highlight>
|
||||
</section>
|
||||
<section id="closing_databases">
|
||||
<title>Closing a database connection</title>
|
||||
|
||||
<p>Database handles should be closed using <code>database:close()</code> when they are no longer
|
||||
needed. If you do not close them manually, they will eventually be garbage collected and
|
||||
closed by mod_lua, but you may end up having too many unused connections to the database
|
||||
if you leave the closing up to mod_lua. Essentially, the following two measures are
|
||||
the same:
|
||||
</p>
|
||||
<highlight language="lua">
|
||||
-- Method 1: Manually close a handle
|
||||
local database = r:dbacquire("mod_dbd")
|
||||
database:close() -- All done
|
||||
|
||||
-- Method 2: Letting the garbage collector close it
|
||||
local database = r:dbacquire("mod_dbd")
|
||||
database = nil -- throw away the reference
|
||||
collectgarbage() -- close the handle via GC
|
||||
</highlight>
|
||||
</section>
|
||||
<section id="database_caveat">
|
||||
<title>Precautions when working with databases</title>
|
||||
<p>Although the standard <code>query</code> and <code>run</code> functions are freely
|
||||
available, it is recommended that you use prepared statements whenever possible, to
|
||||
both optimize performance (if your db handle lives on for a long time) and to minimize
|
||||
the risk of SQL injection attacks. <code>run</code> and <code>query</code> should only
|
||||
be used when there are no variables inserted into a statement (a static statement).
|
||||
When using dynamic statements, use <code>db:prepare</code> or <code>db:prepared</code>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
<directivesynopsis>
|
||||
<name>LuaRoot</name>
|
||||
<description>Specify the base path for resolving relative paths for mod_lua directives</description>
|
||||
|
@@ -182,6 +182,7 @@ FILES_nlm_objs = \
|
||||
$(OBJDIR)/lua_config.o \
|
||||
$(OBJDIR)/lua_request.o \
|
||||
$(OBJDIR)/lua_vmprep.o \
|
||||
$(OBJDIR)/lua_dbd.o \
|
||||
$(EOLIST)
|
||||
|
||||
#
|
||||
|
@@ -136,7 +136,7 @@ else
|
||||
fi
|
||||
])
|
||||
|
||||
lua_objects="lua_apr.lo lua_config.lo mod_lua.lo lua_request.lo lua_vmprep.lo"
|
||||
lua_objects="lua_apr.lo lua_config.lo mod_lua.lo lua_request.lo lua_vmprep.lo lua_dbd.lo"
|
||||
|
||||
APACHE_MODULE(lua, Apache Lua Framework, $lua_objects, , , [
|
||||
CHECK_LUA()
|
||||
|
792
modules/lua/lua_dbd.c
Normal file
792
modules/lua/lua_dbd.c
Normal file
@@ -0,0 +1,792 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "mod_lua.h"
|
||||
#include "lua_apr.h"
|
||||
#include "lua_dbd.h"
|
||||
|
||||
APLOG_USE_MODULE(lua);
|
||||
static APR_OPTIONAL_FN_TYPE(ap_dbd_close) *lua_ap_dbd_close = NULL;
|
||||
static APR_OPTIONAL_FN_TYPE(ap_dbd_open) *lua_ap_dbd_open = NULL;
|
||||
|
||||
|
||||
static request_rec *ap_lua_check_request_rec(lua_State *L, int index)
|
||||
{
|
||||
request_rec *r;
|
||||
luaL_checkudata(L, index, "Apache2.Request");
|
||||
r = lua_unboxpointer(L, index);
|
||||
return r;
|
||||
}
|
||||
|
||||
static lua_db_handle *lua_get_db_handle(lua_State *L)
|
||||
{
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
lua_rawgeti(L, 1, 0);
|
||||
luaL_checktype(L, -1, LUA_TUSERDATA);
|
||||
return (lua_db_handle *) lua_topointer(L, -1);
|
||||
}
|
||||
|
||||
static lua_db_result_set *lua_get_result_set(lua_State *L)
|
||||
{
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
lua_rawgeti(L, 1, 0);
|
||||
luaL_checktype(L, -1, LUA_TUSERDATA);
|
||||
return (lua_db_result_set *) lua_topointer(L, -1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
db:close(): Closes an open database connection.
|
||||
=============================================================================
|
||||
*/
|
||||
AP_LUA_DECLARE(int) lua_db_close(lua_State *L)
|
||||
{
|
||||
/*~~~~~~~~~~~~~~~~~~~~*/
|
||||
lua_db_handle *db;
|
||||
apr_status_t rc = 0;
|
||||
/*~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
db = lua_get_db_handle(L);
|
||||
if (db && db->alive) {
|
||||
if (db->type == LUA_DBTYPE_MOD_DBD) {
|
||||
rc = apr_dbd_close(db->driver, db->handle);
|
||||
}
|
||||
else {
|
||||
lua_ap_dbd_close = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_close);
|
||||
if (lua_ap_dbd_close != NULL)
|
||||
if (db->dbdhandle) lua_ap_dbd_close(db->server, db->dbdhandle);
|
||||
if (db->pool) apr_pool_destroy(db->pool);
|
||||
}
|
||||
|
||||
db->driver = NULL;
|
||||
db->handle = NULL;
|
||||
db->alive = 0;
|
||||
db->pool = NULL;
|
||||
}
|
||||
|
||||
lua_settop(L, 0);
|
||||
lua_pushnumber(L, rc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
db:__gc(): Garbage collecing function.
|
||||
=============================================================================
|
||||
*/
|
||||
AP_LUA_DECLARE(int) lua_db_gc(lua_State *L)
|
||||
{
|
||||
/*~~~~~~~~~~~~~~~~*/
|
||||
lua_db_handle *db;
|
||||
/*~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
db = lua_touserdata(L, 1);
|
||||
if (db && db->alive) {
|
||||
if (db->type == LUA_DBTYPE_APR_DBD) {
|
||||
apr_dbd_close(db->driver, db->handle);
|
||||
if (db->pool) apr_pool_destroy(db->pool);
|
||||
}
|
||||
else {
|
||||
lua_ap_dbd_close = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_close);
|
||||
if (lua_ap_dbd_close != NULL)
|
||||
if (db->dbdhandle) lua_ap_dbd_close(db->server, db->dbdhandle);
|
||||
}
|
||||
db->driver = NULL;
|
||||
db->handle = NULL;
|
||||
db->alive = 0;
|
||||
db->pool = NULL;
|
||||
}
|
||||
lua_settop(L, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
db:active(): Returns true if the connection to the db is still active.
|
||||
=============================================================================
|
||||
*/
|
||||
AP_LUA_DECLARE(int) lua_db_active(lua_State *L)
|
||||
{
|
||||
/*~~~~~~~~~~~~~~~~~~~~*/
|
||||
lua_db_handle *db = 0;
|
||||
apr_status_t rc = 0;
|
||||
/*~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
db = lua_get_db_handle(L);
|
||||
if (db && db->alive) {
|
||||
rc = apr_dbd_check_conn(db->driver, db->pool, db->handle);
|
||||
if (rc == APR_SUCCESS) {
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
lua_pushboolean(L, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
db:query(statement): Executes the given database query and returns the
|
||||
number of rows affected. If an error is encountered, returns nil as the
|
||||
first parameter and the error message as the second.
|
||||
=============================================================================
|
||||
*/
|
||||
AP_LUA_DECLARE(int) lua_db_query(lua_State *L)
|
||||
{
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
lua_db_handle *db = 0;
|
||||
apr_status_t rc = 0;
|
||||
int x = 0;
|
||||
const char *statement;
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
luaL_checktype(L, 3, LUA_TSTRING);
|
||||
statement = lua_tostring(L, 3);
|
||||
db = lua_get_db_handle(L);
|
||||
if (db && db->alive)
|
||||
rc = apr_dbd_query(db->driver, db->handle, &x, statement);
|
||||
else {
|
||||
rc = 0;
|
||||
x = -1;
|
||||
}
|
||||
|
||||
if (rc == APR_SUCCESS)
|
||||
lua_pushnumber(L, x);
|
||||
else {
|
||||
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
const char *err = apr_dbd_error(db->driver, db->handle, rc);
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
lua_pushnil(L);
|
||||
if (err) {
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
db:escape(string): Escapes a string for safe use in the given database type.
|
||||
=============================================================================
|
||||
*/
|
||||
AP_LUA_DECLARE(int) lua_db_escape(lua_State *L)
|
||||
{
|
||||
/*~~~~~~~~~~~~~~~~~~~~~*/
|
||||
lua_db_handle *db = 0;
|
||||
const char *statement;
|
||||
const char *escaped = 0;
|
||||
request_rec *r;
|
||||
/*~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
r = ap_lua_check_request_rec(L, 2);
|
||||
if (r) {
|
||||
luaL_checktype(L, 3, LUA_TSTRING);
|
||||
statement = lua_tostring(L, 3);
|
||||
db = lua_get_db_handle(L);
|
||||
if (db && db->alive) {
|
||||
apr_dbd_init(r->pool);
|
||||
escaped = apr_dbd_escape(db->driver, r->pool, statement,
|
||||
db->handle);
|
||||
if (escaped) {
|
||||
lua_pushstring(L, escaped);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
resultset(N): Fetches one or more rows from a result set.
|
||||
=============================================================================
|
||||
*/
|
||||
static int lua_db_get_row(lua_State *L)
|
||||
{
|
||||
int row_no,x;
|
||||
const char *entry;
|
||||
apr_dbd_row_t *row = 0;
|
||||
lua_db_result_set *res = lua_get_result_set(L);
|
||||
|
||||
row_no = luaL_optinteger(L, 2, 0);
|
||||
lua_settop(L,0);
|
||||
|
||||
/* Fetch all rows at once? */
|
||||
if (row_no == 0) {
|
||||
row_no = 1;
|
||||
lua_newtable(L);
|
||||
while (apr_dbd_get_row(res->driver, res->pool, res->results,
|
||||
&row, -1) != -1)
|
||||
{
|
||||
lua_pushinteger(L, row_no);
|
||||
lua_newtable(L);
|
||||
for (x = 0; x < res->cols; x++) {
|
||||
entry = apr_dbd_get_entry(res->driver, row, x);
|
||||
if (entry) {
|
||||
lua_pushinteger(L, x + 1);
|
||||
lua_pushstring(L, entry);
|
||||
lua_rawset(L, -3);
|
||||
}
|
||||
}
|
||||
lua_rawset(L, -3);
|
||||
row_no++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Just fetch a single row */
|
||||
if (apr_dbd_get_row(res->driver, res->pool, res->results,
|
||||
&row, row_no) != -1)
|
||||
{
|
||||
|
||||
lua_newtable(L);
|
||||
for (x = 0; x < res->cols; x++) {
|
||||
entry = apr_dbd_get_entry(res->driver, row, x);
|
||||
if (entry) {
|
||||
lua_pushinteger(L, x + 1);
|
||||
lua_pushstring(L, entry);
|
||||
lua_rawset(L, -3);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
db:select(statement): Queries the database for the given statement and
|
||||
returns the rows/columns found as a table. If an error is encountered,
|
||||
returns nil as the first parameter and the error message as the second.
|
||||
=============================================================================
|
||||
*/
|
||||
AP_LUA_DECLARE(int) lua_db_select(lua_State *L)
|
||||
{
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
lua_db_handle *db = 0;
|
||||
apr_status_t rc = 0;
|
||||
const char *statement;
|
||||
request_rec *r;
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
r = ap_lua_check_request_rec(L, 2);
|
||||
if (r) {
|
||||
luaL_checktype(L, 3, LUA_TSTRING);
|
||||
statement = lua_tostring(L, 3);
|
||||
db = lua_get_db_handle(L);
|
||||
if (db && db->alive) {
|
||||
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
int cols;
|
||||
apr_dbd_results_t *results = 0;
|
||||
lua_db_result_set* resultset = NULL;
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
rc = apr_dbd_select(db->driver, db->pool, db->handle,
|
||||
&results, statement, 0);
|
||||
if (rc == APR_SUCCESS) {
|
||||
|
||||
cols = apr_dbd_num_cols(db->driver, results);
|
||||
|
||||
if (cols > 0) {
|
||||
lua_newtable(L);
|
||||
resultset = lua_newuserdata(L, sizeof(lua_db_result_set));
|
||||
resultset->cols = cols;
|
||||
resultset->driver = db->driver;
|
||||
resultset->pool = db->pool;
|
||||
resultset->rows = apr_dbd_num_tuples(db->driver, results);
|
||||
resultset->results = results;
|
||||
luaL_newmetatable(L, "lua_apr.dbselect");
|
||||
lua_pushliteral(L, "__call");
|
||||
lua_pushcfunction(L, lua_db_get_row);
|
||||
lua_rawset(L, -3);
|
||||
lua_setmetatable(L, -3);
|
||||
lua_rawseti(L, -2, 0);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
const char *err = apr_dbd_error(db->driver, db->handle, rc);
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
lua_pushnil(L);
|
||||
if (err) {
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lua_pushboolean(L, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
statement:select(var1, var2, var3...): Injects variables into a prepared
|
||||
statement and returns the number of rows matching the query.
|
||||
=============================================================================
|
||||
*/
|
||||
static int lua_db_prepared_select(lua_State *L)
|
||||
{
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
lua_db_prepared_statement *st = 0;
|
||||
apr_status_t rc = 0;
|
||||
const char **vars;
|
||||
int x, have;
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
/* Fetch the prepared statement and the vars passed */
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
lua_rawgeti(L, 1, 0);
|
||||
luaL_checktype(L, -1, LUA_TUSERDATA);
|
||||
st = (lua_db_prepared_statement*) lua_topointer(L, -1);
|
||||
|
||||
/* Check if we got enough variables passed on to us.
|
||||
* This, of course, only works for prepped statements made through lua. */
|
||||
have = lua_gettop(L) - 2;
|
||||
if (st->variables != -1 && have < st->variables ) {
|
||||
lua_pushboolean(L, 0);
|
||||
lua_pushfstring(L,
|
||||
"Error in executing prepared statement: Expected %d arguments, got %d.",
|
||||
st->variables, have);
|
||||
return 2;
|
||||
}
|
||||
vars = apr_pcalloc(st->db->pool, have*sizeof(char *));
|
||||
for (x = 0; x < have; x++) {
|
||||
vars[x] = lua_tostring(L, x + 2);
|
||||
}
|
||||
|
||||
/* Fire off the query */
|
||||
if (st->db && st->db->alive) {
|
||||
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
int cols;
|
||||
apr_dbd_results_t *results = 0;
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
rc = apr_dbd_pselect(st->db->driver, st->db->pool, st->db->handle,
|
||||
&results, st->statement, 0, have, vars);
|
||||
if (rc == APR_SUCCESS) {
|
||||
|
||||
/*~~~~~~~~~~~~~~~~~~~~~*/
|
||||
lua_db_result_set *resultset;
|
||||
/*~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
cols = apr_dbd_num_cols(st->db->driver, results);
|
||||
lua_newtable(L);
|
||||
resultset = lua_newuserdata(L, sizeof(lua_db_result_set));
|
||||
resultset->cols = cols;
|
||||
resultset->driver = st->db->driver;
|
||||
resultset->pool = st->db->pool;
|
||||
resultset->rows = apr_dbd_num_tuples(st->db->driver, results);
|
||||
resultset->results = results;
|
||||
luaL_newmetatable(L, "lua_apr.dbselect");
|
||||
lua_pushliteral(L, "__call");
|
||||
lua_pushcfunction(L, lua_db_get_row);
|
||||
lua_rawset(L, -3);
|
||||
lua_setmetatable(L, -3);
|
||||
lua_rawseti(L, -2, 0);
|
||||
return 1;
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
const char *err = apr_dbd_error(st->db->driver, st->db->handle, rc);
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
lua_pushnil(L);
|
||||
if (err) {
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
lua_pushboolean(L, 0);
|
||||
lua_pushliteral(L,
|
||||
"Database connection seems to be closed, please reacquire it.");
|
||||
return (2);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
statement:query(var1, var2, var3...): Injects variables into a prepared
|
||||
statement and returns the number of rows affected.
|
||||
=============================================================================
|
||||
*/
|
||||
static int lua_db_prepared_query(lua_State *L)
|
||||
{
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
lua_db_prepared_statement *st = 0;
|
||||
apr_status_t rc = 0;
|
||||
const char **vars;
|
||||
int x, have;
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
/* Fetch the prepared statement and the vars passed */
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
lua_rawgeti(L, 1, 0);
|
||||
luaL_checktype(L, -1, LUA_TUSERDATA);
|
||||
st = (lua_db_prepared_statement*) lua_topointer(L, -1);
|
||||
|
||||
/* Check if we got enough variables passed on to us.
|
||||
* This, of course, only works for prepped statements made through lua. */
|
||||
have = lua_gettop(L) - 2;
|
||||
if (st->variables != -1 && have < st->variables ) {
|
||||
lua_pushboolean(L, 0);
|
||||
lua_pushfstring(L,
|
||||
"Error in executing prepared statement: Expected %d arguments, got %d.",
|
||||
st->variables, have);
|
||||
return 2;
|
||||
}
|
||||
vars = apr_pcalloc(st->db->pool, have*sizeof(char *));
|
||||
for (x = 0; x < have; x++) {
|
||||
vars[x] = lua_tostring(L, x + 2);
|
||||
}
|
||||
|
||||
/* Fire off the query */
|
||||
if (st->db && st->db->alive) {
|
||||
|
||||
/*~~~~~~~~~~~~~~*/
|
||||
int affected = 0;
|
||||
/*~~~~~~~~~~~~~~*/
|
||||
|
||||
rc = apr_dbd_pquery(st->db->driver, st->db->pool, st->db->handle,
|
||||
&affected, st->statement, have, vars);
|
||||
if (rc == APR_SUCCESS) {
|
||||
lua_pushinteger(L, affected);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
const char *err = apr_dbd_error(st->db->driver, st->db->handle, rc);
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
lua_pushnil(L);
|
||||
if (err) {
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
lua_pushboolean(L, 0);
|
||||
lua_pushliteral(L,
|
||||
"Database connection seems to be closed, please reacquire it.");
|
||||
return (2);
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
db:prepare(statement): Prepares a statement for later query/select.
|
||||
Returns a table with a :query and :select function, same as the db funcs.
|
||||
=============================================================================
|
||||
*/
|
||||
AP_LUA_DECLARE(int) lua_db_prepare(lua_State* L)
|
||||
{
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
lua_db_handle *db = 0;
|
||||
apr_status_t rc = 0;
|
||||
const char *statement, *at;
|
||||
request_rec *r;
|
||||
lua_db_prepared_statement* st;
|
||||
int need = 0;
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
r = ap_lua_check_request_rec(L, 2);
|
||||
if (r) {
|
||||
apr_dbd_prepared_t *pstatement = NULL;
|
||||
luaL_checktype(L, 3, LUA_TSTRING);
|
||||
statement = lua_tostring(L, 3);
|
||||
|
||||
/* Count number of variables in statement */
|
||||
at = ap_strchr_c(statement,'%');
|
||||
while (at != NULL) {
|
||||
if (at[1] == '%') {
|
||||
at++;
|
||||
}
|
||||
else {
|
||||
need++;
|
||||
}
|
||||
at = ap_strchr_c(at+1,'%');
|
||||
}
|
||||
|
||||
|
||||
db = lua_get_db_handle(L);
|
||||
rc = apr_dbd_prepare(db->driver, r->pool, db->handle, statement,
|
||||
NULL, &pstatement);
|
||||
if (rc != APR_SUCCESS) {
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
const char *err = apr_dbd_error(db->driver, db->handle, rc);
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
lua_pushnil(L);
|
||||
if (err) {
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Push the prepared statement table */
|
||||
lua_newtable(L);
|
||||
st = lua_newuserdata(L, sizeof(lua_db_prepared_statement));
|
||||
st->statement = pstatement;
|
||||
st->variables = need;
|
||||
st->db = db;
|
||||
|
||||
lua_pushliteral(L, "select");
|
||||
lua_pushcfunction(L, lua_db_prepared_select);
|
||||
lua_rawset(L, -4);
|
||||
lua_pushliteral(L, "query");
|
||||
lua_pushcfunction(L, lua_db_prepared_query);
|
||||
lua_rawset(L, -4);
|
||||
lua_rawseti(L, -2, 0);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
db:prepared(statement): Fetches a prepared statement made through
|
||||
DBDPrepareSQL.
|
||||
=============================================================================
|
||||
*/
|
||||
AP_LUA_DECLARE(int) lua_db_prepared(lua_State* L)
|
||||
{
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
lua_db_handle *db = 0;
|
||||
const char *tag;
|
||||
request_rec *r;
|
||||
lua_db_prepared_statement* st;
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
r = ap_lua_check_request_rec(L, 2);
|
||||
if (r) {
|
||||
apr_dbd_prepared_t *pstatement = NULL;
|
||||
db = lua_get_db_handle(L);
|
||||
luaL_checktype(L, 3, LUA_TSTRING);
|
||||
tag = lua_tostring(L, 3);
|
||||
|
||||
/* Look for the statement */
|
||||
pstatement = apr_hash_get(db->dbdhandle->prepared, tag,
|
||||
APR_HASH_KEY_STRING);
|
||||
|
||||
if (pstatement == NULL) {
|
||||
lua_pushnil(L);
|
||||
lua_pushfstring(L,
|
||||
"Could not find any prepared statement called %s!", tag);
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
/* Push the prepared statement table */
|
||||
lua_newtable(L);
|
||||
st = lua_newuserdata(L, sizeof(lua_db_prepared_statement));
|
||||
st->statement = pstatement;
|
||||
st->variables = -1; /* we don't know :( */
|
||||
st->db = db;
|
||||
lua_pushliteral(L, "select");
|
||||
lua_pushcfunction(L, lua_db_prepared_select);
|
||||
lua_rawset(L, -4);
|
||||
lua_pushliteral(L, "query");
|
||||
lua_pushcfunction(L, lua_db_prepared_query);
|
||||
lua_rawset(L, -4);
|
||||
lua_rawseti(L, -2, 0);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* lua_push_db_handle: Creates a database table object with database functions
|
||||
and a userdata at index 0, which will call lua_dbgc when garbage collected.
|
||||
*/
|
||||
static lua_db_handle* lua_push_db_handle(lua_State *L, request_rec* r, int type,
|
||||
apr_pool_t* pool)
|
||||
{
|
||||
lua_db_handle* db;
|
||||
lua_newtable(L);
|
||||
luaL_register(L, NULL, lua_db_methods);
|
||||
db = lua_newuserdata(L, sizeof(lua_db_handle));
|
||||
db->alive = 1;
|
||||
db->pool = pool;
|
||||
db->type = type;
|
||||
db->dbdhandle = 0;
|
||||
db->server = r->server;
|
||||
luaL_newmetatable(L, "lua_apr.dbacquire");
|
||||
lua_pushliteral(L, "__gc");
|
||||
lua_pushcfunction(L, lua_db_gc);
|
||||
lua_rawset(L, -3);
|
||||
lua_setmetatable(L, -2);
|
||||
lua_rawseti(L, -2, 0);
|
||||
return db;
|
||||
}
|
||||
/*
|
||||
=============================================================================
|
||||
dbacquire(dbType, dbString): Opens a new connection to a database of type
|
||||
_dbType_ and with the connection parameters _dbString_. If successful,
|
||||
returns a table with functions for using the database handle. If an error
|
||||
occurs, returns nil as the first parameter and the error message as the
|
||||
second. See the APR_DBD for a list of database types and connection strings
|
||||
supported.
|
||||
=============================================================================
|
||||
*/
|
||||
AP_LUA_DECLARE(int) lua_db_acquire(lua_State *L)
|
||||
{
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
const char *type;
|
||||
const char *arguments;
|
||||
const char *error = 0;
|
||||
request_rec *r;
|
||||
lua_db_handle *db = 0;
|
||||
apr_status_t rc = 0;
|
||||
ap_dbd_t *dbdhandle = NULL;
|
||||
apr_pool_t *pool = NULL;
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
r = ap_lua_check_request_rec(L, 1);
|
||||
if (r) {
|
||||
type = luaL_optstring(L, 2, "mod_dbd"); /* Defaults to mod_dbd */
|
||||
|
||||
if (!strcmp(type, "mod_dbd")) {
|
||||
|
||||
lua_settop(L, 0);
|
||||
lua_ap_dbd_open = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_open);
|
||||
if (lua_ap_dbd_open)
|
||||
dbdhandle = (ap_dbd_t *) lua_ap_dbd_open(
|
||||
r->server->process->pool, r->server);
|
||||
|
||||
if (dbdhandle) {
|
||||
db = lua_push_db_handle(L, r, LUA_DBTYPE_MOD_DBD, dbdhandle->pool);
|
||||
db->driver = dbdhandle->driver;
|
||||
db->handle = dbdhandle->handle;
|
||||
db->dbdhandle = dbdhandle;
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
if ( lua_ap_dbd_open == NULL )
|
||||
lua_pushliteral(L,
|
||||
"mod_dbd doesn't seem to have been loaded.");
|
||||
else
|
||||
lua_pushliteral(
|
||||
L,
|
||||
"Could not acquire connection from mod_dbd. If your database is running, this may indicate a permission problem.");
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
rc = apr_pool_create(&pool, NULL);
|
||||
if (rc != APR_SUCCESS) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "Could not allocate memory for database!");
|
||||
return 2;
|
||||
}
|
||||
apr_pool_tag(pool, "lua_dbd_pool");
|
||||
apr_dbd_init(pool);
|
||||
|
||||
rc = apr_dbd_get_driver(r->server->process->pool, type, &db->driver);
|
||||
if (rc == APR_SUCCESS) {
|
||||
luaL_checktype(L, 3, LUA_TSTRING);
|
||||
arguments = lua_tostring(L, 3);
|
||||
lua_settop(L, 0);
|
||||
if (strlen(arguments)) {
|
||||
rc = apr_dbd_open_ex(db->driver, r->server->process->pool,
|
||||
arguments, &db->handle, &error);
|
||||
if (rc == APR_SUCCESS) {
|
||||
db = lua_push_db_handle(L, r, LUA_DBTYPE_APR_DBD, pool);
|
||||
db->driver = dbdhandle->driver;
|
||||
db->handle = dbdhandle->handle;
|
||||
db->dbdhandle = dbdhandle;
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
if (error) {
|
||||
lua_pushstring(L, error);
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L,
|
||||
"No database connection string was specified.");
|
||||
return (2);
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
if (APR_STATUS_IS_ENOTIMPL(rc)) {
|
||||
lua_pushfstring(L,
|
||||
"driver for %s not available", type);
|
||||
}
|
||||
else if (APR_STATUS_IS_EDSOOPEN(rc)) {
|
||||
lua_pushfstring(L,
|
||||
"can't find driver for %s", type);
|
||||
}
|
||||
else if (APR_STATUS_IS_ESYMNOTFOUND(rc)) {
|
||||
lua_pushfstring(L,
|
||||
"driver for %s is invalid or corrupted",
|
||||
type);
|
||||
}
|
||||
else {
|
||||
lua_pushliteral(L,
|
||||
"mod_lua not compatible with APR in get_driver");
|
||||
}
|
||||
lua_pushinteger(L, rc);
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
76
modules/lua/lua_dbd.h
Normal file
76
modules/lua/lua_dbd.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _LUA_DBD_H_
|
||||
#define _LUA_DBD_H_
|
||||
|
||||
#include "mod_lua.h"
|
||||
#include "apr.h"
|
||||
#include "apr_dbd.h"
|
||||
#include "mod_dbd.h"
|
||||
|
||||
#define LUA_DBTYPE_APR_DBD 0
|
||||
#define LUA_DBTYPE_MOD_DBD 1
|
||||
typedef struct
|
||||
{
|
||||
apr_dbd_t *handle;
|
||||
const apr_dbd_driver_t *driver;
|
||||
int alive;
|
||||
apr_pool_t *pool;
|
||||
char type;
|
||||
ap_dbd_t * dbdhandle;
|
||||
server_rec *server;
|
||||
} lua_db_handle;
|
||||
|
||||
typedef struct {
|
||||
const apr_dbd_driver_t *driver;
|
||||
int rows;
|
||||
int cols;
|
||||
apr_dbd_results_t *results;
|
||||
apr_pool_t *pool;
|
||||
} lua_db_result_set;
|
||||
|
||||
typedef struct {
|
||||
apr_dbd_prepared_t *statement;
|
||||
int variables;
|
||||
lua_db_handle *db;
|
||||
} lua_db_prepared_statement;
|
||||
|
||||
|
||||
AP_LUA_DECLARE(int) lua_db_close(lua_State *L);
|
||||
AP_LUA_DECLARE(int) lua_db_gc(lua_State *L);
|
||||
AP_LUA_DECLARE(int) lua_db_active(lua_State *L);
|
||||
AP_LUA_DECLARE(int) lua_db_query(lua_State *L);
|
||||
AP_LUA_DECLARE(int) lua_db_escape(lua_State *L);
|
||||
AP_LUA_DECLARE(int) lua_db_select(lua_State *L);
|
||||
AP_LUA_DECLARE(int) lua_db_prepare(lua_State* L);
|
||||
AP_LUA_DECLARE(int) lua_db_prepared(lua_State* L);
|
||||
AP_LUA_DECLARE(int) lua_db_acquire(lua_State* L);
|
||||
|
||||
static const luaL_reg lua_db_methods[] =
|
||||
{
|
||||
{ "escape", lua_db_escape },
|
||||
{ "close", lua_db_close },
|
||||
{ "select", lua_db_select },
|
||||
{ "query", lua_db_query },
|
||||
{ "active", lua_db_active },
|
||||
{ "prepare", lua_db_prepare },
|
||||
{ "prepared", lua_db_prepared },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
#endif /* !_LUA_DBD_H_ */
|
@@ -19,6 +19,7 @@
|
||||
#include "util_script.h"
|
||||
#include "lua_apr.h"
|
||||
#include "scoreboard.h"
|
||||
#include "lua_dbd.h"
|
||||
|
||||
APLOG_USE_MODULE(lua);
|
||||
#define POST_MAX_VARS 500
|
||||
@@ -964,6 +965,8 @@ AP_LUA_DECLARE(void) ap_lua_load_request_lmodule(lua_State *L, apr_pool_t *p)
|
||||
makefun(&ap_auth_name, APL_REQ_FUNTYPE_STRING, p));
|
||||
apr_hash_set(dispatch, "sendfile", APR_HASH_KEY_STRING,
|
||||
makefun(&lua_ap_sendfile, APL_REQ_FUNTYPE_LUACFUN, p));
|
||||
apr_hash_set(dispatch, "dbacquire", APR_HASH_KEY_STRING,
|
||||
makefun(&lua_db_acquire, APL_REQ_FUNTYPE_LUACFUN, p));
|
||||
|
||||
|
||||
lua_pushlightuserdata(L, dispatch);
|
||||
|
@@ -141,6 +141,14 @@ SOURCE=.\mod_lua.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\lua_dbd.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\lua_dbd.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\build\win32\httpd.rc
|
||||
# End Source File
|
||||
# End Target
|
||||
|
Reference in New Issue
Block a user