mod_dbd.c revision 6078848fce1bb946f8ef7a53bb188b9b975b56b8
71da3cca78eea6010f89b139ecadb79e6d213c4fnd/* Copyright 2003-5 The Apache Software Foundation or its licensors, as
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * applicable.
71da3cca78eea6010f89b139ecadb79e6d213c4fnd * Licensed under the Apache License, Version 2.0 (the "License");
71da3cca78eea6010f89b139ecadb79e6d213c4fnd * you may not use this file except in compliance with the License.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * You may obtain a copy of the License at
71da3cca78eea6010f89b139ecadb79e6d213c4fnd * Unless required by applicable law or agreed to in writing, software
71da3cca78eea6010f89b139ecadb79e6d213c4fnd * distributed under the License is distributed on an "AS IS" BASIS,
71da3cca78eea6010f89b139ecadb79e6d213c4fnd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
71da3cca78eea6010f89b139ecadb79e6d213c4fnd * See the License for the specific language governing permissions and
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * limitations under the License.
49f1aab8b6762ee5b4afdb3a9cc48e7c00435dd3striker/* Overview of what this is and does:
49f1aab8b6762ee5b4afdb3a9cc48e7c00435dd3striker/************ svr cfg: manage db connection pool ****************/
49f1aab8b6762ee5b4afdb3a9cc48e7c00435dd3strikertypedef struct dbd_prepared {
49f1aab8b6762ee5b4afdb3a9cc48e7c00435dd3striker const char *label;
49f1aab8b6762ee5b4afdb3a9cc48e7c00435dd3striker const char *query;
49f1aab8b6762ee5b4afdb3a9cc48e7c00435dd3strikertypedef struct svr_cfg {
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *name;
1b21d7b3d97def358b2e923655edeb16613a1c31gstein const char *params;
000397350b42c6266351bd618fa07df929fa7c79gstein for (p = val; *p; ++p) \
5ca401d5a2dd63d75464895dc2a6ea292b62fd99gstein return "Argument must be numeric!"
5ca401d5a2dd63d75464895dc2a6ea292b62fd99gsteinstatic const char *dbd_param(cmd_parms *cmd, void *cfg, const char *val)
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *p;
9f18c80269be35c0b5653e84b0db0a24044722c4gstein /* loading the driver involves once-only dlloading that is
f4c310fd2555c6faca1f980f00b161eadb089023gstein * best done at server startup. This also guarantees that
f4c310fd2555c6faca1f980f00b161eadb089023gstein * we won't return an error later.
f4c310fd2555c6faca1f980f00b161eadb089023gstein switch (apr_dbd_get_driver(cmd->pool, svr->name, &driver)) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return apr_psprintf(cmd->pool, "DBD: No driver for %s", svr->name);
b47464a901075041e800be2de098a603923fa4f9gstein "DBD: Can't load driver file apr_dbd_%s.so",
f4c310fd2555c6faca1f980f00b161eadb089023gstein "DBD: Failed to load driver apr_dbd_%s_driver",
f4c310fd2555c6faca1f980f00b161eadb089023gsteinvoid ap_dbd_prepare(server_rec *s, const char *query, const char *label)
49f1aab8b6762ee5b4afdb3a9cc48e7c00435dd3striker svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module);
f4c310fd2555c6faca1f980f00b161eadb089023gstein dbd_prepared *prepared = apr_pcalloc(s->process->pool, sizeof(dbd_prepared));
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmstatic const char *dbd_prepare(cmd_parms *cmd, void *cfg, const char *query,
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *label)
49f1aab8b6762ee5b4afdb3a9cc48e7c00435dd3striker AP_INIT_TAKE1("DBDriver", dbd_param, (void*)cmd_name, RSRC_CONF,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "SQL Driver"),
b47464a901075041e800be2de098a603923fa4f9gstein AP_INIT_TAKE1("DBDParams", dbd_param, (void*)cmd_params, RSRC_CONF,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "SQL Driver Params"),
f4c310fd2555c6faca1f980f00b161eadb089023gstein AP_INIT_TAKE1("DBDPersist", dbd_param, (void*)cmd_persist, RSRC_CONF,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Use persistent connection/pool"),
f4c310fd2555c6faca1f980f00b161eadb089023gstein AP_INIT_TAKE2("DBDPrepareSQL", dbd_prepare, NULL, RSRC_CONF,
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm "Prepared SQL statement, label"),
f4c310fd2555c6faca1f980f00b161eadb089023gstein AP_INIT_TAKE1("DBDMin", dbd_param, (void*)cmd_min, RSRC_CONF,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Minimum number of connections"),
f4c310fd2555c6faca1f980f00b161eadb089023gstein AP_INIT_TAKE1("DBDKeep", dbd_param, (void*)cmd_keep, RSRC_CONF,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Maximum number of sustained connections"),
49f1aab8b6762ee5b4afdb3a9cc48e7c00435dd3striker AP_INIT_TAKE1("DBDMax", dbd_param, (void*)cmd_max, RSRC_CONF,
de18a9e85398b9c79c422f578633ed56c2747bbbgstein "Maximum number of connections"),
de18a9e85398b9c79c422f578633ed56c2747bbbgstein AP_INIT_TAKE1("DBDExptime", dbd_param, (void*)cmd_exp, RSRC_CONF,
de18a9e85398b9c79c422f578633ed56c2747bbbgstein "Keepalive time for idle connections"),
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmstatic void *dbd_merge(apr_pool_t *pool, void *base, void *add) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein svr_cfg *cfg = apr_pmemdup(pool, add, sizeof(svr_cfg));
9f18c80269be35c0b5653e84b0db0a24044722c4gstein svr_cfg *svr = (svr_cfg*) apr_pcalloc(p, sizeof(svr_cfg));
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_status_t dbd_prepared_init(apr_pool_t *pool, svr_cfg *svr,
9f18c80269be35c0b5653e84b0db0a24044722c4gstein if (apr_dbd_prepare(dbd->driver, pool, dbd->handle, p->query,
eb2abb2d3f87f28e99bcb282b91e432822b4d9b4gstein apr_hash_set(dbd->prepared, p->label, APR_HASH_KEY_STRING, stmt);
eb2abb2d3f87f28e99bcb282b91e432822b4d9b4gstein/************ svr cfg: manage db connection pool ****************/
eb2abb2d3f87f28e99bcb282b91e432822b4d9b4gstein/* an apr_reslist_constructor for SQL connections
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Also use this for opening in non-reslist modes, since it gives
eb2abb2d3f87f28e99bcb282b91e432822b4d9b4gstein * us all the error-handling in one place.
eb2abb2d3f87f28e99bcb282b91e432822b4d9b4gsteinstatic apr_status_t dbd_construct(void **db, void *params, apr_pool_t *pool)
709df1e1c2e1710570f8cb4209497e88662829c3gstein apr_status_t rv = apr_dbd_get_driver(pool, svr->name, &rec->driver);
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* Error-checking get_driver isn't necessary now (because it's done at
f4c310fd2555c6faca1f980f00b161eadb089023gstein * config-time). But in case that changes in future ...
7281ea331999debdc337b02ce37a3169e0e033a2gstein switch (rv) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein "DBD: driver for %s is invalid or corrupted", svr->name);
f4c310fd2555c6faca1f980f00b161eadb089023gstein "DBD: mod_dbd not compatible with apr in get_driver");
9f18c80269be35c0b5653e84b0db0a24044722c4gstein rv = apr_dbd_open(rec->driver, pool, svr->params, &rec->handle);
000397350b42c6266351bd618fa07df929fa7c79gstein switch (rv) {
000397350b42c6266351bd618fa07df929fa7c79gstein "DBD: Can't connect to %s[%s]", svr->name, svr->params);
9f18c80269be35c0b5653e84b0db0a24044722c4gstein "DBD: mod_dbd not compatible with apr in open");
000397350b42c6266351bd618fa07df929fa7c79gsteinstatic apr_status_t dbd_destruct(void *sql, void *params, apr_pool_t *pool)
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_status_t dbd_setup(apr_pool_t *pool, server_rec *s)
f4c310fd2555c6faca1f980f00b161eadb089023gstein svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module);
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_status_t rv = apr_reslist_create(&svr->dbpool, svr->nmin, svr->nkeep,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "DBD Pool: failed to initialise");
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* Functions we export for modules to use:
f4c310fd2555c6faca1f980f00b161eadb089023gstein - open acquires a connection from the pool (opens one if necessary)
f4c310fd2555c6faca1f980f00b161eadb089023gstein - close releases it back in to the pool
f4c310fd2555c6faca1f980f00b161eadb089023gstein svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module);
f4c310fd2555c6faca1f980f00b161eadb089023gsteinap_dbd_t* ap_dbd_open(apr_pool_t *pool, server_rec *s)
49f1aab8b6762ee5b4afdb3a9cc48e7c00435dd3striker svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module);
49f1aab8b6762ee5b4afdb3a9cc48e7c00435dd3striker const char *errmsg;
f5d88bab65052e00ba37a1af17e5e67a437628b5wrowe /* Return a once-only connection */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (apr_reslist_acquire(svr->dbpool, &rec) != APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Failed to acquire DBD connection from pool!");
5b03ba47ff7225cacb131f14b019332af27da960gstein rv = apr_dbd_check_conn(arec->driver, pool, arec->handle);
49f1aab8b6762ee5b4afdb3a9cc48e7c00435dd3striker errmsg = apr_dbd_error(arec->driver, arec->handle, rv);
5b03ba47ff7225cacb131f14b019332af27da960gsteinap_dbd_t* ap_dbd_open(apr_pool_t *pool, server_rec *s)
5b03ba47ff7225cacb131f14b019332af27da960gstein const char *errmsg;
5b03ba47ff7225cacb131f14b019332af27da960gstein svr_cfg *svr = ap_get_module_config(s->module_config, &dbd_module);
5b03ba47ff7225cacb131f14b019332af27da960gstein /* Return a once-only connection */
5b03ba47ff7225cacb131f14b019332af27da960gstein/* since we're in nothread-land, we can mess with svr->conn with impunity */
5b03ba47ff7225cacb131f14b019332af27da960gstein/* If we have a persistent connection and it's good, we'll use it */
5b03ba47ff7225cacb131f14b019332af27da960gstein rv = apr_dbd_check_conn(svr->conn->driver, pool, svr->conn->handle);
5b03ba47ff7225cacb131f14b019332af27da960gstein errmsg = apr_dbd_error(arec->driver, arec->handle, rv);
5b03ba47ff7225cacb131f14b019332af27da960gstein/* We don't have a connection right now, so we'll open one */
5b03ba47ff7225cacb131f14b019332af27da960gstein if (dbd_construct(&rec, svr, s->process->pool) == APR_SUCCESS) {
5b03ba47ff7225cacb131f14b019332af27da960gstein apr_pool_cleanup_register(s->process->pool, svr->conn,
49f1aab8b6762ee5b4afdb3a9cc48e7c00435dd3strikertypedef struct {
f4c310fd2555c6faca1f980f00b161eadb089023gstein dbd_pool_rec *req = ap_get_module_config(r->request_config, &dbd_module);
0946f90438dcf29a5fe5d9e21559b3b9d640bc12wrowe svr = ap_get_module_config(r->server->module_config, &dbd_module);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_set_module_config(r->request_config, &dbd_module, req);
87e4c2191581abcfaba8133868a1e9c96d9643a5gstein apr_pool_cleanup_register(r->pool, req->conn, dbd_close,
87e4c2191581abcfaba8133868a1e9c96d9643a5gstein dbd_pool_rec *req = ap_get_module_config(c->conn_config, &dbd_module);
87e4c2191581abcfaba8133868a1e9c96d9643a5gstein svr = ap_get_module_config(c->base_server->module_config, &dbd_module);
87e4c2191581abcfaba8133868a1e9c96d9643a5gstein ap_set_module_config(c->conn_config, &dbd_module, req);
87e4c2191581abcfaba8133868a1e9c96d9643a5gstein apr_pool_cleanup_register(c->pool, req->conn, dbd_close,
87e4c2191581abcfaba8133868a1e9c96d9643a5gstein ap_dbd_t *ret = ap_get_module_config(r->request_config, &dbd_module);
87e4c2191581abcfaba8133868a1e9c96d9643a5gstein svr = ap_get_module_config(r->server->module_config, &dbd_module);
87e4c2191581abcfaba8133868a1e9c96d9643a5gstein ap_set_module_config(r->request_config, &dbd_module, ret);
87e4c2191581abcfaba8133868a1e9c96d9643a5gstein apr_pool_cleanup_register(r->pool, svr->conn, dbd_close,
87e4c2191581abcfaba8133868a1e9c96d9643a5gstein /* if persist then dbd_open registered cleanup on proc pool */
87e4c2191581abcfaba8133868a1e9c96d9643a5gstein ap_dbd_t *ret = ap_get_module_config(c->conn_config, &dbd_module);
87e4c2191581abcfaba8133868a1e9c96d9643a5gstein svr = ap_get_module_config(c->base_server->module_config, &dbd_module);
87e4c2191581abcfaba8133868a1e9c96d9643a5gstein ap_set_module_config(c->conn_config, &dbd_module, ret);
87e4c2191581abcfaba8133868a1e9c96d9643a5gstein apr_pool_cleanup_register(c->pool, svr->conn, dbd_close,
87e4c2191581abcfaba8133868a1e9c96d9643a5gstein /* if persist then dbd_open registered cleanup on proc pool */