https://issues.apache.org/bugzilla/show_bug.cgi?id=46827
This patch adds ability to the mod_dbd Apache module to execute any
SQL statements after DB connection have been established.
Patch is against httpd trunk.
Configuration example:
DBDriver mysql
DBDParams host=localhost,user=root,reconnect=0
DBDPersist On
DBDInitSQL "USE passport"
DBDInitSQL "SET NAMES utf8"
DBDMin 1
Order of the DBDInitSQL statements is preserved (statements will be
executed in same order they were in httpd.conf file).
Also this patch introduces optional post_connection hook, which
enables any other module to hook after connection were established.
--
Marko Kevac
--- modules/database/mod_dbd.h 2009-03-07 15:52:57.000000000 +0300
+++ /home/knight/micex/git/dbd_sql_init/mod_dbd.h 2009-04-12 18:57:00.000000000 +0400
@@ -55,6 +55,23 @@
#include <httpd.h>
#include <apr_optional.h>
#include <apr_hash.h>
+#include <apr_hooks.h>
+
+typedef struct {
+ server_rec *server;
+ const char *name;
+ const char *params;
+ int persist;
+#if APR_HAS_THREADS
+ int nmin;
+ int nkeep;
+ int nmax;
+ int exptime;
+ int set;
+#endif
+ apr_hash_t *queries;
+ apr_array_header_t *init_queries;
+} dbd_cfg_t;
typedef struct {
apr_dbd_t *handle;
@@ -98,6 +115,9 @@
APR_DECLARE_OPTIONAL_FN(ap_dbd_t*, ap_dbd_cacquire, (conn_rec*));
APR_DECLARE_OPTIONAL_FN(void, ap_dbd_prepare, (server_rec*, const char*, const char*));
+APR_DECLARE_EXTERNAL_HOOK(dbd, AP, apr_status_t, post_connect,
+ (apr_pool_t *, dbd_cfg_t *, ap_dbd_t *));
+
#endif
/** @} */
--- modules/database/mod_dbd.c 2009-03-07 15:52:57.000000000 +0300
+++ /home/knight/micex/git/dbd_sql_init/mod_dbd.c 2009-04-12 18:58:17.000000000 +0400
@@ -39,6 +39,11 @@
extern module AP_MODULE_DECLARE_DATA dbd_module;
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(dbd, AP, apr_status_t, post_connect,
+ (apr_pool_t *pool, dbd_cfg_t *cfg,
+ ap_dbd_t *dbd),
+ (pool, cfg, dbd), OK, DECLINED)
+
/************ svr cfg: manage db connection pool ****************/
#define NMIN_SET 0x1
@@ -46,21 +51,6 @@
#define NMAX_SET 0x4
#define EXPTIME_SET 0x8
-typedef struct {
- server_rec *server;
- const char *name;
- const char *params;
- int persist;
-#if APR_HAS_THREADS
- int nmin;
- int nkeep;
- int nmax;
- int exptime;
- int set;
-#endif
- apr_hash_t *queries;
-} dbd_cfg_t;
-
typedef struct dbd_group_t dbd_group_t;
struct dbd_group_t {
@@ -99,6 +89,8 @@
#define DEFAULT_NMAX 10
#define DEFAULT_EXPTIME 300
+#define DEFAULT_SQL_INIT_ARRAY_SIZE 5
+
static void *create_dbd_config(apr_pool_t *pool, server_rec *s)
{
svr_cfg *svr = apr_pcalloc(pool, sizeof(svr_cfg));
@@ -115,6 +107,8 @@
cfg->exptime = DEFAULT_EXPTIME;
#endif
cfg->queries = apr_hash_make(pool);
+ cfg->init_queries = apr_array_make(pool, DEFAULT_SQL_INIT_ARRAY_SIZE,
+ sizeof(const char *));
return svr;
}
@@ -137,10 +131,33 @@
new->exptime = (add->set&EXPTIME_SET) ? add->exptime : base->exptime;
#endif
new->queries = apr_hash_overlay(pool, add->queries, base->queries);
+ new->init_queries = apr_array_append(pool, add->init_queries,
+ base->init_queries);
return svr;
}
+DBD_DECLARE_NONSTD(void) ap_dbd_sql_init(server_rec *s, const char *query)
+{
+ svr_cfg *svr;
+ const char **arr_item;
+
+ svr = ap_get_module_config(s->module_config, &dbd_module);
+ if (!svr) {
+ /* some modules may call from within config directive handlers, and
+ * if these are called in a server context that contains no mod_dbd
+ * config directives, then we have to create our own server config
+ */
+ svr = create_dbd_config(config_pool, s);
+ ap_set_module_config(s->module_config, &dbd_module, svr);
+ }
+
+ if (query) {
+ arr_item = apr_array_push(svr->cfg->init_queries);
+ *arr_item = query;
+ }
+}
+
static const char *dbd_param(cmd_parms *cmd, void *dconf, const char *val)
{
const apr_dbd_driver_t *driver = NULL;
@@ -244,6 +261,17 @@
return NULL;
}
+static const char *dbd_init_sql(cmd_parms *cmd, void *dconf, const char *query)
+{
+ if (!query || *query == '\n') {
+ return "You should specify SQL statement";
+ }
+
+ ap_dbd_sql_init(cmd->server, query);
+
+ return NULL;
+}
+
static const command_rec dbd_cmds[] = {
AP_INIT_TAKE1("DBDriver", dbd_param, (void*)cmd_name, RSRC_CONF,
"SQL Driver"),
@@ -254,6 +282,8 @@
AP_INIT_TAKE12("DBDPrepareSQL", dbd_prepare, NULL, RSRC_CONF,
"SQL statement to prepare (or nothing, to override "
"statement inherited from main server) and label"),
+ AP_INIT_TAKE1("DBDInitSQL", dbd_init_sql, NULL, RSRC_CONF,
+ "SQL statement to be executed after connection is created"),
#if APR_HAS_THREADS
AP_INIT_TAKE1("DBDMin", dbd_param_int, (void*)cmd_min, RSRC_CONF,
"Minimum number of connections"),
@@ -430,6 +460,27 @@
return rv;
}
+static apr_status_t dbd_init_sql_init(apr_pool_t *pool, dbd_cfg_t *cfg,
+ ap_dbd_t *rec)
+{
+ int i;
+ apr_status_t rv = APR_SUCCESS;
+
+ for (i = 0; i < cfg->init_queries->nelts; i++) {
+ int nrows;
+ char **query_p;
+
+ query_p = (char **)cfg->init_queries->elts + i;
+
+ if (apr_dbd_query(rec->driver, rec->handle, &nrows, *query_p)) {
+ rv = APR_EGENERAL;
+ break;
+ }
+ }
+
+ return rv;
+}
+
static apr_status_t dbd_close(void *data)
{
ap_dbd_t *rec = data;
@@ -551,6 +602,8 @@
return rv;
}
+ dbd_run_post_connect(prepared_pool, cfg, rec);
+
*data_ptr = rec;
return APR_SUCCESS;
@@ -921,6 +974,9 @@
APR_REGISTER_OPTIONAL_FN(ap_dbd_acquire);
APR_REGISTER_OPTIONAL_FN(ap_dbd_cacquire);
+ APR_OPTIONAL_HOOK(dbd, post_connect, dbd_init_sql_init,
+ NULL, NULL, APR_HOOK_MIDDLE);
+
apr_dbd_init(pool);
}