On Thu, Feb 12, 2009 at 12:56 AM, Nick Kew <n...@webthing.com> wrote:
> Sounds OK in principle for trunk.  If you want to post a patch
> against trunk, I'll try and find the time to review it.

Here I am again.

The patch works well for us.

Is there something else that I can do for now?

-- 
Marko Kevac
diff -u trunk/mod_dbd.c mine/mod_dbd.c
--- trunk/mod_dbd.c	2009-03-05 15:19:18.000000000 +0300
+++ mine/mod_dbd.c	2009-03-05 15:19:44.000000000 +0300
@@ -20,6 +20,8 @@
  * http://apache.webthing.com/database/
  */
 
+#define CORE_PRIVATE
+
 #include "apr_reslist.h"
 #include "apr_strings.h"
 #include "apr_hash.h"
@@ -46,8 +48,13 @@
 #define NMAX_SET     0x4
 #define EXPTIME_SET  0x8
 
+#define DEFAULT_POOL_COUNT  2
+
+#define DBD_DEFAULT_POOL_NAME "dbd_default_pool"
+
 typedef struct {
     server_rec *server;
+    const char *pool_name;
     const char *name;
     const char *params;
     int persist;
@@ -59,6 +66,7 @@
     int set;
 #endif
     apr_hash_t *queries;
+    apr_hash_t *init_queries;
 } dbd_cfg_t;
 
 typedef struct dbd_group_t dbd_group_t;
@@ -77,8 +85,8 @@
 };
 
 typedef struct {
-    dbd_cfg_t *cfg;
-    dbd_group_t *group;
+    apr_hash_t *cfgs;
+    apr_hash_t *groups;
 } svr_cfg;
 
 typedef enum { cmd_name, cmd_params, cmd_persist,
@@ -102,79 +110,145 @@
 static void *create_dbd_config(apr_pool_t *pool, server_rec *s)
 {
     svr_cfg *svr = apr_pcalloc(pool, sizeof(svr_cfg));
-    dbd_cfg_t *cfg = svr->cfg = apr_pcalloc(pool, sizeof(dbd_cfg_t));
 
-    cfg->server = s;
-    cfg->name = no_dbdriver; /* to generate meaningful error messages */
-    cfg->params = ""; /* don't risk segfault on misconfiguration */
-    cfg->persist = -1;
-#if APR_HAS_THREADS
-    cfg->nmin = DEFAULT_NMIN;
-    cfg->nkeep = DEFAULT_NKEEP;
-    cfg->nmax = DEFAULT_NMAX;
-    cfg->exptime = DEFAULT_EXPTIME;
-#endif
-    cfg->queries = apr_hash_make(pool);
+    svr->cfgs = apr_hash_make(pool);
+    svr->groups = apr_hash_make(pool);
 
     return svr;
 }
 
-static void *merge_dbd_config(apr_pool_t *pool, void *basev, void *addv)
+DBD_DECLARE_NONSTD(void) ap_dbd_sql_init(server_rec *s, const char *pool_name,
+        const char *query, const char *label)
 {
-    dbd_cfg_t *base = ((svr_cfg*) basev)->cfg;
-    dbd_cfg_t *add = ((svr_cfg*) addv)->cfg;
-    svr_cfg *svr = apr_pcalloc(pool, sizeof(svr_cfg));
-    dbd_cfg_t *new = svr->cfg = apr_pcalloc(pool, sizeof(dbd_cfg_t));
+    svr_cfg *svr;
+    dbd_cfg_t *cfg = NULL;
 
-    new->server = add->server;
-    new->name = (add->name != no_dbdriver) ? add->name : base->name;
-    new->params = strcmp(add->params, "") ? add->params : base->params;
-    new->persist = (add->persist != -1) ? add->persist : base->persist;
-#if APR_HAS_THREADS
-    new->nmin = (add->set&NMIN_SET) ? add->nmin : base->nmin;
-    new->nkeep = (add->set&NKEEP_SET) ? add->nkeep : base->nkeep;
-    new->nmax = (add->set&NMAX_SET) ? add->nmax : base->nmax;
-    new->exptime = (add->set&EXPTIME_SET) ? add->exptime : base->exptime;
-#endif
-    new->queries = apr_hash_overlay(pool, add->queries, base->queries);
+    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);
+    }
 
-    return svr;
+    cfg = apr_hash_get(svr->cfgs, pool_name, APR_HASH_KEY_STRING);
+    if (NULL == cfg) {
+        ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
+                "could not found dbd configuration for pool %s", pool_name);
+        return;
+    }
+
+    if (apr_hash_get(cfg->init_queries, label, APR_HASH_KEY_STRING)
+        && strcmp(query, "")) {
+        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
+                "conflicting SQL statements with label %s", label);
+    }
+
+    apr_hash_set(cfg->init_queries, label, APR_HASH_KEY_STRING, query);
+}
+
+static const char *dbd_pool(cmd_parms *cmd, void *mconfig, const char *arg)
+{
+    const char *errmsg = NULL;
+    const char *endp = ap_strrchr_c(arg, '>');
+
+    dbd_cfg_t *conf;
+
+    ap_conf_vector_t *new_dir_conf = ap_create_per_dir_config(cmd->pool);
+
+    const char *err = ap_check_cmd_context(cmd,
+                                           NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
+
+    if (err != NULL) {
+        return err;
+    }
+
+    if (endp == NULL) {
+        return apr_pstrcat(cmd->pool, cmd->cmd->name,
+                           "> directive missing closing '>'", NULL);
+    }
+
+    arg = apr_pstrndup(cmd->pool, arg, endp - arg);
+
+    /* initialize our config and fetch it */
+    conf = ap_set_config_vectors(cmd->server, new_dir_conf, arg,
+                                 &dbd_module, cmd->pool);
+
+    errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_dir_conf);
+    if (errmsg != NULL)
+        return errmsg;
+
+    return NULL;
 }
 
 static const char *dbd_param(cmd_parms *cmd, void *dconf, const char *val)
 {
     const apr_dbd_driver_t *driver = NULL;
     svr_cfg *svr = ap_get_module_config(cmd->server->module_config,
-                                        &dbd_module);
-    dbd_cfg_t *cfg = svr->cfg;
+            &dbd_module);
+    dbd_cfg_t *cfg = NULL;
 
-    switch ((long) cmd->info) {
-    case cmd_name:
-        cfg->name = val;
-        /* loading the driver involves once-only dlloading that is
-         * best done at server startup.  This also guarantees that
-         * we won't return an error later.
+    char *name = NULL;
+    char *word = NULL;
+
+    if (cmd->directive->parent &&
+            strncasecmp(cmd->directive->parent->directive,
+                "<DBDPool", 8) == 0) {
+        const char *pargs = cmd->directive->parent->args;
+        /* Directive inside <DBDPool section
+         * Parent directive arg is the dbd pool name.
          */
-        switch (apr_dbd_get_driver(cmd->pool, cfg->name, &driver)) {
-        case APR_ENOTIMPL:
-            return apr_psprintf(cmd->pool, "DBD: No driver for %s", cfg->name);
-        case APR_EDSOOPEN:
-            return apr_psprintf(cmd->pool,
+        name = ap_getword_conf(cmd->pool, &pargs);
+        if ((word = ap_strchr(name, '>')))
+            *word = '\0';
+    } else {
+        name = DBD_DEFAULT_POOL_NAME;
+    }
+
+    cfg = apr_hash_get(svr->cfgs, name, APR_HASH_KEY_STRING);
+    if (NULL == cfg) {
+        cfg = apr_palloc(cmd->pool, sizeof(*cfg));
+        apr_hash_set(svr->cfgs, name, APR_HASH_KEY_STRING, cfg);
+        cfg->pool_name = name;
+        cfg->nmax = DEFAULT_NMAX;
+        cfg->nmin = DEFAULT_NMIN;
+        cfg->nkeep = DEFAULT_NKEEP;
+        cfg->exptime = DEFAULT_EXPTIME;
+        cfg->server = cmd->server;
+        cfg->queries = apr_hash_make(cmd->pool);
+        cfg->init_queries = apr_hash_make(cmd->pool);
+    }
+
+    switch ((long) cmd->info) {
+        case cmd_name:
+            cfg->name = val;
+            /* loading the driver involves once-only dlloading that is
+             * best done at server startup.  This also guarantees that
+             * we won't return an error later.
+             */
+            switch (apr_dbd_get_driver(cmd->pool, cfg->name, &driver)) {
+                case APR_ENOTIMPL:
+                    return apr_psprintf(cmd->pool, "DBD: No driver for %s",
+                            cfg->name);
+                case APR_EDSOOPEN:
+                    return apr_psprintf(cmd->pool,
 #ifdef NETWARE
-                                "DBD: Can't load driver file dbd%s.nlm",
+                            "DBD: Can't load driver file dbd%s.nlm",
 #else
-                                "DBD: Can't load driver file apr_dbd_%s.so",
+                            "DBD: Can't load driver file apr_dbd_%s.so",
 #endif
-                                cfg->name);
-        case APR_ESYMNOTFOUND:
-            return apr_psprintf(cmd->pool,
-                                "DBD: Failed to load driver apr_dbd_%s_driver",
-                                cfg->name);
-        }
-        break;
-    case cmd_params:
-        cfg->params = val;
-        break;
+                            cfg->name);
+                case APR_ESYMNOTFOUND:
+                    return apr_psprintf(cmd->pool,
+                            "DBD: Failed to load driver apr_dbd_%s_driver",
+                            cfg->name);
+            }
+            break;
+        case cmd_params:
+            cfg->params = val;
+            break;
     }
 
     return NULL;
@@ -185,9 +259,41 @@
 {
     svr_cfg *svr = ap_get_module_config(cmd->server->module_config,
                                         &dbd_module);
-    dbd_cfg_t *cfg = svr->cfg;
+    dbd_cfg_t *cfg;
+
+    char *name = NULL;
+    char *word = NULL;
+
     const char *p;
 
+    if (cmd->directive->parent &&
+            strncasecmp(cmd->directive->parent->directive,
+                "<DBDPool", 8) == 0) {
+        const char *pargs = cmd->directive->parent->args;
+        /* Directive inside <DBDPool section
+         * Parent directive arg is the dbd pool name.
+         */
+        name = ap_getword_conf(cmd->pool, &pargs);
+        if ((word = ap_strchr(name, '>')))
+            *word = '\0';
+    } else {
+        name = DBD_DEFAULT_POOL_NAME;
+    }
+
+    cfg = apr_hash_get(svr->cfgs, name, APR_HASH_KEY_STRING);
+    if (NULL == cfg) {
+        cfg = apr_palloc(cmd->pool, sizeof(*cfg));
+        apr_hash_set(svr->cfgs, name, APR_HASH_KEY_STRING, cfg);
+        cfg->pool_name = name;
+        cfg->nmax = DEFAULT_NMAX;
+        cfg->nmin = DEFAULT_NMIN;
+        cfg->nkeep = DEFAULT_NKEEP;
+        cfg->exptime = DEFAULT_EXPTIME;
+        cfg->server = cmd->server;
+        cfg->queries = apr_hash_make(cmd->pool);
+        cfg->init_queries = apr_hash_make(cmd->pool);
+    }
+
     for (p = val; *p; ++p) {
         if (!apr_isdigit(*p)) {
             return "Argument must be numeric!";
@@ -195,22 +301,22 @@
     }
 
     switch ((long) cmd->info) {
-    case cmd_min:
-        cfg->nmin = atoi(val);
-        cfg->set |= NMIN_SET;
-        break;
-    case cmd_keep:
-        cfg->nkeep = atoi(val);
-        cfg->set |= NKEEP_SET;
-        break;
-    case cmd_max:
-        cfg->nmax = atoi(val);
-        cfg->set |= NMAX_SET;
-        break;
-    case cmd_exp:
-        cfg->exptime = atoi(val);
-        cfg->set |= EXPTIME_SET;
-        break;
+        case cmd_min:
+            cfg->nmin = atoi(val);
+            cfg->set |= NMIN_SET;
+            break;
+        case cmd_keep:
+            cfg->nkeep = atoi(val);
+            cfg->set |= NKEEP_SET;
+            break;
+        case cmd_max:
+            cfg->nmax = atoi(val);
+            cfg->set |= NMAX_SET;
+            break;
+        case cmd_exp:
+            cfg->exptime = atoi(val);
+            cfg->set |= EXPTIME_SET;
+            break;
     }
 
     return NULL;
@@ -220,12 +326,37 @@
 static const char *dbd_param_flag(cmd_parms *cmd, void *dconf, int flag)
 {
     svr_cfg *svr = ap_get_module_config(cmd->server->module_config,
-                                        &dbd_module);
+            &dbd_module);
+    dbd_cfg_t *cfg = NULL;
+
+    char *word = NULL;
+    char *name = NULL;
+
+    if (cmd->directive->parent &&
+            strncasecmp(cmd->directive->parent->directive,
+                "<DBDPool", 8) == 0) {
+        const char *pargs = cmd->directive->parent->args;
+        /* Directive inside <DBDPool section
+         * Parent directive arg is the dbd pool name.
+         */
+        name = ap_getword_conf(cmd->temp_pool, &pargs);
+        if ((word = ap_strchr(name, '>')))
+            *word = '\0';
+    } else {
+        return apr_psprintf(cmd->pool,
+                "DBD: %s should be inside <DBDPool >", cmd->cmd->name);
+    }
+
+    cfg = apr_hash_get(svr->cfgs, name, APR_HASH_KEY_STRING);
+    if (NULL == cfg) {
+        cfg = apr_palloc(cmd->pool, sizeof(*cfg));
+        apr_hash_set(svr->cfgs, name, APR_HASH_KEY_STRING, cfg);
+    }
 
     switch ((long) cmd->info) {
-    case cmd_persist:
-        svr->cfg->persist = flag;
-        break;
+        case cmd_persist:
+            cfg->persist = flag;
+            break;
     }
 
     return NULL;
@@ -234,17 +365,68 @@
 static const char *dbd_prepare(cmd_parms *cmd, void *dconf, const char *query,
                                const char *label)
 {
+    char *word = NULL;
+    char *name = NULL;
+
+    if (cmd->directive->parent &&
+            strncasecmp(cmd->directive->parent->directive,
+                "<DBDPool", 8) == 0) {
+        const char *pargs = cmd->directive->parent->args;
+        /* Directive inside <DBDPool section
+         * Parent directive arg is the dbd pool name.
+         */
+        name = ap_getword_conf(cmd->temp_pool, &pargs);
+        if ((word = ap_strchr(name, '>')))
+            *word = '\0';
+    } else {
+        return apr_psprintf(cmd->pool,
+                "DBD: %s should be inside <DBDPool >", cmd->cmd->name);
+    }
+
     if (!label) {
         label = query;
         query = "";
     }
 
-    ap_dbd_prepare(cmd->server, query, label);
+    ap_dbd_prepare_pool(cmd->server, name, query, label);
+
+    return NULL;
+}
+
+static const char *dbd_init_sql(cmd_parms *cmd, void *dconf, const char *query,
+        const char *label)
+{
+    char *word = NULL;
+    char *name = NULL;
+
+    if (cmd->directive->parent &&
+            strncasecmp(cmd->directive->parent->directive,
+                "<DBDPool", 8) == 0) {
+        const char *pargs = cmd->directive->parent->args;
+        /* Directive inside <DBDPool section
+         * Parent directive arg is the dbd pool name.
+         */
+        name = ap_getword_conf(cmd->temp_pool, &pargs);
+        if ((word = ap_strchr(name, '>')))
+            *word = '\0';
+    } else {
+        return apr_psprintf(cmd->pool,
+                "DBD: %s should be inside <DBDPool >", cmd->cmd->name);
+    }
+
+    if (!label) {
+        label = query;
+        query = "";
+    }
+
+    ap_dbd_sql_init(cmd->server, name, query, label);
 
     return NULL;
 }
 
 static const command_rec dbd_cmds[] = {
+    AP_INIT_RAW_ARGS("<DBDPool", dbd_pool, NULL, RSRC_CONF,
+            "Container for pool configuration"),
     AP_INIT_TAKE1("DBDriver", dbd_param, (void*)cmd_name, RSRC_CONF,
                   "SQL Driver"),
     AP_INIT_TAKE1("DBDParams", dbd_param, (void*)cmd_params, RSRC_CONF,
@@ -254,6 +436,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_TAKE12("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"),
@@ -277,10 +461,11 @@
    return OK;
 }
 
-DBD_DECLARE_NONSTD(void) ap_dbd_prepare(server_rec *s, const char *query,
-                                        const char *label)
+DBD_DECLARE_NONSTD(void) ap_dbd_prepare_pool(server_rec *s, const char *pool_name,
+        const char *query, const char *label)
 {
     svr_cfg *svr;
+    dbd_cfg_t *cfg = NULL;
 
     svr = ap_get_module_config(s->module_config, &dbd_module);
     if (!svr) {
@@ -292,13 +477,25 @@
          ap_set_module_config(s->module_config, &dbd_module, svr);
     }
 
-    if (apr_hash_get(svr->cfg->queries, label, APR_HASH_KEY_STRING)
+    cfg = apr_hash_get(svr->cfgs, pool_name, APR_HASH_KEY_STRING);
+    if (NULL == cfg) {
+        ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
+                "could not found dbd configuration for pool %s", pool_name);
+        return;
+    }
+
+    if (apr_hash_get(cfg->queries, label, APR_HASH_KEY_STRING)
         && strcmp(query, "")) {
         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
-                     "conflicting SQL statements with label %s", label);
+                "conflicting SQL statements with label %s", label);
     }
 
-    apr_hash_set(svr->cfg->queries, label, APR_HASH_KEY_STRING, query);
+    apr_hash_set(cfg->queries, label, APR_HASH_KEY_STRING, query);
+}
+
+DBD_DECLARE_NONSTD(void) ap_dbd_prepare(server_rec *s, const char *query, const char *label)
+{
+    ap_dbd_prepare_pool(s, DBD_DEFAULT_POOL_NAME, query, label);
 }
 
 typedef struct {
@@ -309,89 +506,46 @@
                            apr_pool_t *ptemp, server_rec *s)
 {
     server_rec *sp;
-    apr_array_header_t *add_queries = apr_array_make(ptemp, 10,
-                                                     sizeof(dbd_query_t));
 
     for (sp = s; sp; sp = sp->next) {
         svr_cfg *svr = ap_get_module_config(sp->module_config, &dbd_module);
-        dbd_cfg_t *cfg = svr->cfg;
-        apr_hash_index_t *hi_first = apr_hash_first(ptemp, cfg->queries);
-        dbd_group_t *group;
-
-        /* dbd_setup in 2.2.3 and under was causing spurious error messages
-         * when dbd isn't configured.  We can stop that with a quick check here
-         * together with a similar check in ap_dbd_open (where being
-         * unconfigured is a genuine error that must be reported).
-         */
-        if (cfg->name == no_dbdriver || !cfg->persist) {
-            continue;
-        }
+        apr_hash_index_t *hi;
 
-        for (group = group_list; group; group = group->next) {
-            dbd_cfg_t *group_cfg = group->cfg;
-            apr_hash_index_t *hi;
-            int group_ok = 1;
+        for (hi = apr_hash_first(ptemp, svr->cfgs);
+                hi; hi = apr_hash_next(hi)) {
+            dbd_cfg_t *cfg;
+            dbd_group_t *group;
 
-            if (strcmp(cfg->name, group_cfg->name)
-                || strcmp(cfg->params, group_cfg->params)) {
-                continue;
-            }
+            apr_hash_this(hi, NULL, NULL, (void*)&cfg);
 
-#if APR_HAS_THREADS
-            if (cfg->nmin != group_cfg->nmin
-                || cfg->nkeep != group_cfg->nkeep
-                || cfg->nmax != group_cfg->nmax
-                || cfg->exptime != group_cfg->exptime) {
+            if (!cfg->persist) {
                 continue;
             }
-#endif
-
-            add_queries->nelts = 0;
-
-            for (hi = hi_first; hi; hi = apr_hash_next(hi)) {
-                const char *label, *query;
-                const char *group_query;
-
-                apr_hash_this(hi, (void*) &label, NULL, (void*) &query);
 
-                group_query = apr_hash_get(group_cfg->queries, label,
-                                           APR_HASH_KEY_STRING);
+            for (group = group_list; group; group = group->next) {
+                dbd_cfg_t *group_cfg = group->cfg;
 
-                if (!group_query) {
-                    dbd_query_t *add_query = apr_array_push(add_queries);
-
-                    add_query->label = label;
-                    add_query->query = query;
-                }
-                else if (strcmp(query, group_query)) {
-                    group_ok = 0;
-                    break;
-                }
-            }
-
-            if (group_ok) {
-                int i;
-
-                for (i = 0; i < add_queries->nelts; ++i) {
-                    dbd_query_t *add_query = ((dbd_query_t*) add_queries->elts)
-                                             + i;
-
-                    apr_hash_set(group_cfg->queries, add_query->label,
-                                 APR_HASH_KEY_STRING, add_query->query);
+                if (strcmp(cfg->pool_name, group_cfg->pool_name)) {
+                    continue;
                 }
 
-                svr->group = group;
+                apr_hash_set(svr->groups, cfg->pool_name,
+                        APR_HASH_KEY_STRING, group);
                 break;
             }
-        }
 
-        if (!svr->group) {
-            svr->group = group = apr_pcalloc(pconf, sizeof(dbd_group_t));
+            if (NULL == apr_hash_get(svr->groups, cfg->pool_name,
+                        APR_HASH_KEY_STRING)) {
+                group = apr_pcalloc(pconf, sizeof(dbd_group_t));
+
+                group->cfg = cfg;
 
-            group->cfg = cfg;
+                group->next = group_list;
+                group_list = group;
 
-            group->next = group_list;
-            group_list = group;
+                apr_hash_set(svr->groups, cfg->pool_name,
+                        APR_HASH_KEY_STRING, group);
+            }
         }
     }
 
@@ -430,6 +584,33 @@
     return rv;
 }
 
+static apr_status_t dbd_init_sql_init(apr_pool_t *pool, dbd_cfg_t *cfg,
+                                      ap_dbd_t *rec)
+{
+    apr_hash_index_t *hi;
+    apr_status_t rv = APR_SUCCESS;
+
+    for (hi = apr_hash_first(pool, cfg->init_queries); hi;
+         hi = apr_hash_next(hi)) {
+        int nrows;
+        const char *label, *query;
+        apr_dbd_prepared_t *stmt;
+
+        apr_hash_this(hi, (void*) &label, NULL, (void*) &query);
+
+        if (!strcmp(query, "")) {
+            continue;
+        }
+
+        stmt = NULL;
+        if (apr_dbd_query(rec->driver, rec->handle, &nrows, query)) {
+            rv = APR_EGENERAL;
+        }
+    }
+
+    return rv;
+}
+
 static apr_status_t dbd_close(void *data)
 {
     ap_dbd_t *rec = data;
@@ -464,7 +645,6 @@
     apr_pool_t *rec_pool, *prepared_pool;
     ap_dbd_t *rec;
     apr_status_t rv;
-    const char *err = "";
 
     rv = apr_pool_create(&rec_pool, pool);
     if (rv != APR_SUCCESS) {
@@ -508,12 +688,12 @@
         return rv;
     }
 
-    rv = apr_dbd_open_ex(rec->driver, rec->pool, cfg->params, &rec->handle, &err);
+    rv = apr_dbd_open(rec->driver, rec->pool, cfg->params, &rec->handle);
     if (rv != APR_SUCCESS) {
         switch (rv) {
         case APR_EGENERAL:
             ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
-                         "DBD: Can't connect to %s: %s", cfg->name, err);
+                         "DBD: Can't connect to %s", cfg->name);
             break;
         default:
             ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
@@ -551,6 +731,17 @@
         return rv;
     }
 
+    rv = dbd_init_sql_init(prepared_pool, cfg, rec);
+    if (rv != APR_SUCCESS) {
+        const char *errmsg = apr_dbd_error(rec->driver, rec->handle, rv);
+        ap_log_error(APLOG_MARK, APLOG_ERR, rv, cfg->server,
+                     "DBD: failed to execute init SQL statements: %s",
+                     (errmsg ? errmsg : "[???]"));
+
+        apr_pool_destroy(rec->pool);
+        return rv;
+    }
+
     *data_ptr = rec;
 
     return APR_SUCCESS;
@@ -649,11 +840,11 @@
 
 static void dbd_child_init(apr_pool_t *p, server_rec *s)
 {
-  apr_status_t rv = dbd_setup_init(p, s);
-  if (rv) {
-    ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
-                 "DBD: child init failed!");
-  }
+    apr_status_t rv = dbd_setup_init(p, s);
+    if (rv) {
+        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
+                "DBD: child init failed!");
+    }
 }
 
 #if APR_HAS_THREADS
@@ -697,23 +888,34 @@
         - open acquires a connection from the pool (opens one if necessary)
         - close releases it back in to the pool
 */
-DBD_DECLARE_NONSTD(void) ap_dbd_close(server_rec *s, ap_dbd_t *rec)
+DBD_DECLARE_NONSTD(void) ap_dbd_close_pool(server_rec *s, ap_dbd_t *rec,
+        const char *pool_name)
 {
+    dbd_group_t *group = NULL;
     svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module);
 
-    if (!svr->cfg->persist) {
+    group = apr_hash_get(svr->groups, pool_name, APR_HASH_KEY_STRING);
+
+    if (!group->cfg->persist) {
         apr_pool_destroy(rec->pool);
     }
 #if APR_HAS_THREADS
     else {
-        apr_reslist_release(svr->group->reslist, rec);
+        apr_reslist_release(group->reslist, rec);
     }
 #endif
 }
 
-static apr_status_t dbd_check(apr_pool_t *pool, server_rec *s, ap_dbd_t *rec)
+DBD_DECLARE_NONSTD(void) ap_dbd_close(server_rec *s, ap_dbd_t *rec)
 {
-    svr_cfg *svr;
+    return ap_dbd_close_pool(s, rec, DBD_DEFAULT_POOL_NAME);
+}
+
+static apr_status_t dbd_check(apr_pool_t *pool, server_rec *s, ap_dbd_t *rec,
+        const char *pool_name)
+{
+    svr_cfg *svr = NULL;
+    dbd_group_t *group = NULL;
     apr_status_t rv = apr_dbd_check_conn(rec->driver, pool, rec->handle);
     const char *errmsg;
 
@@ -730,26 +932,32 @@
     }
 
     svr = ap_get_module_config(s->module_config, &dbd_module);
+    if (!svr)
+        return -1;
+    group = apr_hash_get(svr->groups, pool_name, APR_HASH_KEY_STRING);
     ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
-                 "DBD [%s] Error: %s", svr->cfg->name, errmsg);
+                 "DBD [%s] Error: %s", group->cfg->name, errmsg);
     return rv;
 }
 
-DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_open(apr_pool_t *pool, server_rec *s)
+DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_open_pool(apr_pool_t *pool, server_rec *s,
+        const char *pool_name)
 {
     svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module);
-    dbd_group_t *group = svr->group;
-    dbd_cfg_t *cfg = svr->cfg;
+    dbd_group_t *group = NULL;
+    dbd_cfg_t *cfg = NULL;
     ap_dbd_t *rec = NULL;
 #if APR_HAS_THREADS
     apr_status_t rv;
 #endif
 
-    /* If nothing is configured, we shouldn't be here */
-    if (cfg->name == no_dbdriver) {
-        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "DBD: not configured");
+    group = apr_hash_get(svr->groups, pool_name, APR_HASH_KEY_STRING);
+    if (NULL == group) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                "DBD: %s pool is not configured", pool_name);
         return NULL;
     }
+    cfg = group->cfg;
 
     if (!cfg->persist) {
         /* Return a once-only connection */
@@ -775,9 +983,18 @@
         return NULL;
     }
 
-    if (dbd_check(pool, s, rec) != APR_SUCCESS) {
+    if (dbd_check(pool, s, rec, pool_name) != APR_SUCCESS) {
         apr_reslist_invalidate(group->reslist, rec);
-        return NULL;
+
+        /* Problem is often connected with server timeout.
+         * So create new connection
+         */
+        rv = apr_reslist_acquire(group->reslist, (void*) &rec);
+        if (rv != APR_SUCCESS) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
+                    "Failed to acquire DBD connection from pool!");
+            return NULL;
+        }
     }
 #else
     /* If we have a persistent connection and it's good, we'll use it;
@@ -785,7 +1002,7 @@
      */
     rec = group->rec;
     if (rec) {
-        if (dbd_check(pool, s, rec) != APR_SUCCESS) {
+        if (dbd_check(pool, s, rec, pool_name) != APR_SUCCESS) {
             apr_pool_destroy(rec->pool);
             rec = NULL;
         }
@@ -801,12 +1018,21 @@
     return rec;
 }
 
+DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_open(apr_pool_t *pool, server_rec *s)
+{
+    return ap_dbd_open_pool(pool, s, DBD_DEFAULT_POOL_NAME);
+}
+
 #if APR_HAS_THREADS
 typedef struct {
     ap_dbd_t *rec;
     apr_reslist_t *reslist;
 } dbd_acquire_t;
 
+typedef struct {
+    apr_hash_t *list;
+} dbd_acquire_list_t;
+
 static apr_status_t dbd_release(void *data)
 {
     dbd_acquire_t *acq = data;
@@ -814,9 +1040,11 @@
     return APR_SUCCESS;
 }
 
-DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire(request_rec *r)
+DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire_pool(request_rec *r,
+        const char *pool_name)
 {
-    dbd_acquire_t *acq;
+    dbd_acquire_list_t *acq_list;
+    dbd_acquire_t *acq = NULL;
 
     while (!ap_is_initial_req(r)) {
         if (r->prev) {
@@ -827,52 +1055,88 @@
         }
     }
 
-    acq = ap_get_module_config(r->request_config, &dbd_module);
+    acq_list = ap_get_module_config(r->request_config, &dbd_module);
+    if (!acq_list) {
+        acq_list = apr_palloc(r->pool, sizeof(dbd_acquire_list_t));
+        acq_list->list = apr_hash_make(r->pool);
+        ap_set_module_config(r->request_config, &dbd_module, acq_list);
+    }
+
+    acq = apr_hash_get(acq_list->list, pool_name,
+            APR_HASH_KEY_STRING);
     if (!acq) {
+        dbd_group_t *group = NULL;
+        svr_cfg *svr = ap_get_module_config(r->server->module_config,
+                &dbd_module);
+
         acq = apr_palloc(r->pool, sizeof(dbd_acquire_t));
-        acq->rec = ap_dbd_open(r->pool, r->server);
-        if (acq->rec) {
-            svr_cfg *svr = ap_get_module_config(r->server->module_config,
-                                                &dbd_module);
 
-            ap_set_module_config(r->request_config, &dbd_module, acq);
-            if (svr->cfg->persist) {
-                acq->reslist = svr->group->reslist;
-                apr_pool_cleanup_register(r->pool, acq, dbd_release,
-                                          apr_pool_cleanup_null);
-            }
+        acq->rec = ap_dbd_open_pool(r->pool, r->server, pool_name);
+        if (!acq->rec) {
+            return NULL;
+        }
+
+        apr_hash_set(acq_list->list, pool_name, APR_HASH_KEY_STRING, acq);
+
+        group = apr_hash_get(svr->groups, pool_name,
+                APR_HASH_KEY_STRING);
+        if (group->cfg->persist) {
+            acq->reslist = group->reslist;
+            apr_pool_cleanup_register(r->pool, acq, dbd_release,
+                    apr_pool_cleanup_null);
         }
     }
 
     return acq->rec;
 }
 
-DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire(conn_rec *c)
+DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire_pool(conn_rec *c,
+        const char *pool_name)
 {
-    dbd_acquire_t *acq = ap_get_module_config(c->conn_config, &dbd_module);
+    dbd_acquire_list_t *acq_list =
+        ap_get_module_config(c->conn_config, &dbd_module);
+    dbd_acquire_t *acq = NULL;
 
-    if (!acq) {
+    if (!acq_list) {
+        acq_list = apr_palloc(c->pool, sizeof(dbd_acquire_list_t));
         acq = apr_palloc(c->pool, sizeof(dbd_acquire_t));
-        acq->rec = ap_dbd_open(c->pool, c->base_server);
+
+        apr_hash_set(acq_list->list, pool_name, APR_HASH_KEY_STRING, acq);
+
+        acq->rec = ap_dbd_open_pool(c->pool, c->base_server, pool_name);
         if (acq->rec) {
+            dbd_group_t *group = NULL;
             svr_cfg *svr = ap_get_module_config(c->base_server->module_config,
                                                 &dbd_module);
 
             ap_set_module_config(c->conn_config, &dbd_module, acq);
-            if (svr->cfg->persist) {
-                acq->reslist = svr->group->reslist;
+            group = apr_hash_get(svr->groups, pool_name,
+                    APR_HASH_KEY_STRING);
+            if (group->cfg->persist) {
+                acq->reslist = group->reslist;
                 apr_pool_cleanup_register(c->pool, acq, dbd_release,
                                           apr_pool_cleanup_null);
             }
         }
     }
 
+    if (NULL == acq) {
+        acq = apr_hash_get(acq_list->list, pool_name,
+                APR_HASH_KEY_STRING);
+    }
+
     return acq->rec;
 }
 #else
-DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire(request_rec *r)
+typedef struct {
+    apr_hash_t *list;
+} dbd_acquire_list_t;
+
+DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire_pool(request_rec *r,
+        const char *pool_name)
 {
-    ap_dbd_t *rec;
+    dbd_acquire_list_t *rec_list;
+    ap_dbd_t *rec = NULL;
 
     while (!ap_is_initial_req(r)) {
         if (r->prev) {
@@ -883,32 +1147,58 @@
         }
     }
 
-    rec = ap_get_module_config(r->request_config, &dbd_module);
-    if (!rec) {
-        rec = ap_dbd_open(r->pool, r->server);
+    rec_list = ap_get_module_config(r->request_config, &dbd_module);
+    if (!rec_list) {
+        rec_list = apr_palloc(r->pool, sizeof(dbd_acquire_list_t));
+        rec = ap_dbd_open_pool(r->pool, r->server, pool_name);
         if (rec) {
-            ap_set_module_config(r->request_config, &dbd_module, rec);
+            apr_hash_set(rec_list, pool_name, APR_HASH_KEY_STRING,
+                    rec);
+            ap_set_module_config(r->request_config, &dbd_module, rec_list);
         }
     }
 
+    if (NULL == rec) {
+        rec = apr_hash_get(rec_list, pool_name, APR_HASH_KEY_STRING);
+    }
+
     return rec;
 }
 
-DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire(conn_rec *c)
+DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire_pool(conn_rec *c,
+        const char *pool_name)
 {
-    ap_dbd_t *rec = ap_get_module_config(c->conn_config, &dbd_module);
+    dbd_acquire_list_t *rec_list =
+        ap_get_module_config(c->conn_config, &dbd_module);
+    ap_dbd_t *rec = NULL;
 
-    if (!rec) {
-        rec = ap_dbd_open(c->pool, c->base_server);
+    if (!rec_list) {
+        rec_list = apr_palloc(c->pool, sizeof(dbd_acquire_list_t));
+        rec = ap_dbd_open_pool(c->pool, c->base_server, pool_name);
         if (rec) {
             ap_set_module_config(c->conn_config, &dbd_module, rec);
+            apr_hash_set(rec_list, pool_name, APR_HASH_KEY_STRING, rec);
         }
     }
 
+    if (NULL == rec) {
+        rec = apr_hash_get(rec_list, pool_name, APR_HASH_KEY_STRING);
+    }
+
     return rec;
 }
 #endif
 
+DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_acquire(request_rec *r)
+{
+    return ap_dbd_acquire_pool(r, DBD_DEFAULT_POOL_NAME);
+}
+
+DBD_DECLARE_NONSTD(ap_dbd_t *) ap_dbd_cacquire(conn_rec *c)
+{
+    return ap_dbd_cacquire_pool(c, DBD_DEFAULT_POOL_NAME);
+}
+
 static void dbd_hooks(apr_pool_t *pool)
 {
     ap_hook_pre_config(dbd_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
@@ -916,10 +1206,15 @@
     ap_hook_child_init(dbd_child_init, NULL, NULL, APR_HOOK_MIDDLE);
 
     APR_REGISTER_OPTIONAL_FN(ap_dbd_prepare);
+    APR_REGISTER_OPTIONAL_FN(ap_dbd_prepare_pool);
     APR_REGISTER_OPTIONAL_FN(ap_dbd_open);
+    APR_REGISTER_OPTIONAL_FN(ap_dbd_open_pool);
     APR_REGISTER_OPTIONAL_FN(ap_dbd_close);
+    APR_REGISTER_OPTIONAL_FN(ap_dbd_close_pool);
     APR_REGISTER_OPTIONAL_FN(ap_dbd_acquire);
+    APR_REGISTER_OPTIONAL_FN(ap_dbd_acquire_pool);
     APR_REGISTER_OPTIONAL_FN(ap_dbd_cacquire);
+    APR_REGISTER_OPTIONAL_FN(ap_dbd_cacquire_pool);
 
     apr_dbd_init(pool);
 }
@@ -929,7 +1224,7 @@
     NULL,
     NULL,
     create_dbd_config,
-    merge_dbd_config,
+    NULL,
     dbd_cmds,
     dbd_hooks
 };
diff -u trunk/mod_dbd.h mine/mod_dbd.h
--- trunk/mod_dbd.h	2009-03-05 15:19:21.000000000 +0300
+++ mine/mod_dbd.h	2009-03-05 15:19:48.000000000 +0300
@@ -1,5 +1,4 @@
-/* Copyright 2003-5 WebThing Ltd
- * Licensed to the Apache Software Foundation (ASF) under one or more
+/* 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
@@ -69,34 +68,53 @@
 /* acquire a connection that MUST be explicitly closed.
  * Returns NULL on error
  */
-DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_open(apr_pool_t*, server_rec*);
+DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_open_pool(apr_pool_t *pool, server_rec *s,
+        const char *pool_name);
+DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_open(apr_pool_t *pool, server_rec *s);
 
 /* release a connection acquired with ap_dbd_open */
-DBD_DECLARE_NONSTD(void) ap_dbd_close(server_rec*, ap_dbd_t*);
+DBD_DECLARE_NONSTD(void) ap_dbd_close_pool(server_rec *s, ap_dbd_t *dbd,
+        const char *pool_name);
+DBD_DECLARE_NONSTD(void) ap_dbd_close(server_rec *s, ap_dbd_t *dbd);
 
 /* acquire a connection that will have the lifetime of a request
  * and MUST NOT be explicitly closed.  Return NULL on error.
  * This is the preferred function for most applications.
  */
-DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_acquire(request_rec*);
+DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_acquire_pool(request_rec *r,
+        const char *pool_name);
+DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_acquire(request_rec *r);
 
 /* acquire a connection that will have the lifetime of a connection
  * and MUST NOT be explicitly closed.  Return NULL on error.
  * This is the preferred function for most applications.
  */
-DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_cacquire(conn_rec*);
+DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_cacquire_pool(conn_rec *c,
+        const char *pool_name);
+DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_cacquire(conn_rec *c);
 
 /* Prepare a statement for use by a client module during
  * the server startup/configuration phase.  Can't be called
  * after the server has created its children (use apr_dbd_*).
  */
-DBD_DECLARE_NONSTD(void) ap_dbd_prepare(server_rec*, const char*, const char*);
+DBD_DECLARE_NONSTD(void) ap_dbd_prepare_pool(server_rec *s, const char *pool_name,
+        const char *query, const char *label);
+DBD_DECLARE_NONSTD(void) ap_dbd_prepare(server_rec *s, const char *query, const char *label);
 
 /* Also export them as optional functions for modules that prefer it */
+APR_DECLARE_OPTIONAL_FN(ap_dbd_t*, ap_dbd_open_pool, (apr_pool_t*, server_rec*, const char*));
 APR_DECLARE_OPTIONAL_FN(ap_dbd_t*, ap_dbd_open, (apr_pool_t*, server_rec*));
+
+APR_DECLARE_OPTIONAL_FN(void, ap_dbd_close_pool, (server_rec*, ap_dbd_t*, const char*));
 APR_DECLARE_OPTIONAL_FN(void, ap_dbd_close, (server_rec*, ap_dbd_t*));
+
+APR_DECLARE_OPTIONAL_FN(ap_dbd_t*, ap_dbd_acquire_pool, (request_rec*, const char*));
 APR_DECLARE_OPTIONAL_FN(ap_dbd_t*, ap_dbd_acquire, (request_rec*));
+
+APR_DECLARE_OPTIONAL_FN(ap_dbd_t*, ap_dbd_cacquire_pool, (conn_rec*, const char*));
 APR_DECLARE_OPTIONAL_FN(ap_dbd_t*, ap_dbd_cacquire, (conn_rec*));
+
+APR_DECLARE_OPTIONAL_FN(void, ap_dbd_prepare_pool, (server_rec*, const char*, const char*, const char*));
 APR_DECLARE_OPTIONAL_FN(void, ap_dbd_prepare, (server_rec*, const char*, const char*));
 
 #endif

Reply via email to