1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 #include "apu_config.h"
23 #include "apr_pools.h"
25 #include "apr_strings.h"
27 #include "apr_thread_mutex.h"
30 #include "apu_internal.h"
31 #include "apr_dbd_internal.h"
33 #include "apu_version.h"
35 static apr_hash_t
*drivers
= NULL
;
37 #define CLEANUP_CAST (apr_status_t (*)(void*))
40 /* deprecated, but required for existing providers. Existing and new
41 * providers should be refactored to use a provider-specific mutex so
42 * that different providers do not block one another.
43 * In APR 1.3 this is no longer used for dso module loading, and
44 * apu_dso_mutex_[un]lock is used instead.
45 * In APR 2.0 this should become entirely local to libaprutil-2.so and
46 * no longer be exported.
48 static apr_thread_mutex_t
* mutex
= NULL
;
49 APU_DECLARE(apr_status_t
) apr_dbd_mutex_lock()
51 return apr_thread_mutex_lock(mutex
);
53 APU_DECLARE(apr_status_t
) apr_dbd_mutex_unlock()
55 return apr_thread_mutex_unlock(mutex
);
58 APU_DECLARE(apr_status_t
) apr_dbd_mutex_lock() {
61 APU_DECLARE(apr_status_t
) apr_dbd_mutex_unlock() {
67 #define DRIVER_LOAD(name,driver,pool) \
69 extern const apr_dbd_driver_t driver; \
70 apr_hash_set(drivers,name,APR_HASH_KEY_STRING,&driver); \
77 static apr_status_t
apr_dbd_term(void *ptr
)
79 /* set drivers to NULL so init can work again */
82 /* Everything else we need is handled by cleanups registered
83 * when we created mutexes and loaded DSOs
88 APU_DECLARE(apr_status_t
) apr_dbd_init(apr_pool_t
*pool
)
90 apr_status_t ret
= APR_SUCCESS
;
93 if (drivers
!= NULL
) {
97 /* Top level pool scope, need process-scope lifetime */
98 for (parent
= pool
; parent
; parent
= apr_pool_parent_get(pool
))
101 /* deprecate in 2.0 - permit implicit initialization */
104 drivers
= apr_hash_make(pool
);
107 ret
= apr_thread_mutex_create(&mutex
, APR_THREAD_MUTEX_DEFAULT
, pool
);
108 /* This already registers a pool cleanup */
112 /* Load statically-linked drivers: */
114 DRIVER_LOAD("mysql", apr_dbd_mysql_driver
, pool
);
117 DRIVER_LOAD("pgsql", apr_dbd_pgsql_driver
, pool
);
120 DRIVER_LOAD("sqlite3", apr_dbd_sqlite3_driver
, pool
);
123 DRIVER_LOAD("sqlite2", apr_dbd_sqlite2_driver
, pool
);
126 DRIVER_LOAD("oracle", apr_dbd_oracle_driver
, pool
);
129 DRIVER_LOAD("freetds", apr_dbd_freetds_driver
, pool
);
132 DRIVER_LOAD("odbc", apr_dbd_odbc_driver
, pool
);
134 #if APU_HAVE_SOME_OTHER_BACKEND
135 DRIVER_LOAD("firebird", apr_dbd_other_driver
, pool
);
137 #endif /* APU_DSO_BUILD */
139 apr_pool_cleanup_register(pool
, NULL
, apr_dbd_term
,
140 apr_pool_cleanup_null
);
145 APU_DECLARE(apr_status_t
) apr_dbd_get_driver(apr_pool_t
*pool
, const char *name
,
146 const apr_dbd_driver_t
**driver
)
151 apr_dso_handle_sym_t symbol
;
156 rv
= apu_dso_mutex_lock();
161 *driver
= apr_hash_get(drivers
, name
, APR_HASH_KEY_STRING
);
164 apu_dso_mutex_unlock();
170 /* The driver DSO must have exactly the same lifetime as the
171 * drivers hash table; ignore the passed-in pool */
172 pool
= apr_hash_pool_get(drivers
);
175 apr_snprintf(modname
, sizeof(modname
), "dbd%s.nlm", name
);
177 apr_snprintf(modname
, sizeof(modname
),
178 "apr_dbd_%s-" APU_STRINGIFY(APU_MAJOR_VERSION
) ".dll", name
);
180 apr_snprintf(modname
, sizeof(modname
),
181 "apr_dbd_%s-" APU_STRINGIFY(APU_MAJOR_VERSION
) ".so", name
);
183 apr_snprintf(symname
, sizeof(symname
), "apr_dbd_%s_driver", name
);
184 rv
= apu_dso_load(&symbol
, modname
, symname
, pool
);
185 if (rv
!= APR_SUCCESS
) { /* APR_EDSOOPEN or APR_ESYMNOTFOUND? */
186 if (rv
== APR_EINIT
) { /* previously loaded?!? */
187 name
= apr_pstrdup(pool
, name
);
188 apr_hash_set(drivers
, name
, APR_HASH_KEY_STRING
, *driver
);
194 if ((*driver
)->init
) {
195 (*driver
)->init(pool
);
197 name
= apr_pstrdup(pool
, name
);
198 apr_hash_set(drivers
, name
, APR_HASH_KEY_STRING
, *driver
);
201 apu_dso_mutex_unlock();
203 #else /* not builtin and !APR_HAS_DSO => not implemented */
210 APU_DECLARE(apr_status_t
) apr_dbd_open_ex(const apr_dbd_driver_t
*driver
,
211 apr_pool_t
*pool
, const char *params
,
216 *handle
= (driver
->open
)(pool
, params
, error
);
217 if (*handle
== NULL
) {
220 rv
= apr_dbd_check_conn(driver
, pool
, *handle
);
221 if ((rv
!= APR_SUCCESS
) && (rv
!= APR_ENOTIMPL
)) {
222 /* XXX: rv is APR error code, but apr_dbd_error() takes int! */
224 *error
= apr_dbd_error(driver
, *handle
, rv
);
226 apr_dbd_close(driver
, *handle
);
232 APU_DECLARE(apr_status_t
) apr_dbd_open(const apr_dbd_driver_t
*driver
,
233 apr_pool_t
*pool
, const char *params
,
236 return apr_dbd_open_ex(driver
,pool
,params
,handle
,NULL
);
239 APU_DECLARE(int) apr_dbd_transaction_start(const apr_dbd_driver_t
*driver
,
240 apr_pool_t
*pool
, apr_dbd_t
*handle
,
241 apr_dbd_transaction_t
**trans
)
243 int ret
= driver
->start_transaction(pool
, handle
, trans
);
245 apr_pool_cleanup_register(pool
, *trans
,
246 CLEANUP_CAST driver
->end_transaction
,
247 apr_pool_cleanup_null
);
252 APU_DECLARE(int) apr_dbd_transaction_end(const apr_dbd_driver_t
*driver
,
254 apr_dbd_transaction_t
*trans
)
256 apr_pool_cleanup_kill(pool
, trans
, CLEANUP_CAST driver
->end_transaction
);
257 return driver
->end_transaction(trans
);
260 APU_DECLARE(int) apr_dbd_transaction_mode_get(const apr_dbd_driver_t
*driver
,
261 apr_dbd_transaction_t
*trans
)
263 return driver
->transaction_mode_get(trans
);
266 APU_DECLARE(int) apr_dbd_transaction_mode_set(const apr_dbd_driver_t
*driver
,
267 apr_dbd_transaction_t
*trans
,
270 return driver
->transaction_mode_set(trans
, mode
);
273 APU_DECLARE(apr_status_t
) apr_dbd_close(const apr_dbd_driver_t
*driver
,
276 return driver
->close(handle
);
279 APU_DECLARE(const char*) apr_dbd_name(const apr_dbd_driver_t
*driver
)
284 APU_DECLARE(void*) apr_dbd_native_handle(const apr_dbd_driver_t
*driver
,
287 return driver
->native_handle(handle
);
290 APU_DECLARE(int) apr_dbd_check_conn(const apr_dbd_driver_t
*driver
,
294 return driver
->check_conn(pool
, handle
);
297 APU_DECLARE(int) apr_dbd_set_dbname(const apr_dbd_driver_t
*driver
,
299 apr_dbd_t
*handle
, const char *name
)
301 return driver
->set_dbname(pool
,handle
,name
);
304 APU_DECLARE(int) apr_dbd_query(const apr_dbd_driver_t
*driver
,
306 int *nrows
, const char *statement
)
308 return driver
->query(handle
,nrows
,statement
);
311 APU_DECLARE(int) apr_dbd_select(const apr_dbd_driver_t
*driver
,
313 apr_dbd_t
*handle
, apr_dbd_results_t
**res
,
314 const char *statement
, int random
)
316 return driver
->select(pool
,handle
,res
,statement
,random
);
319 APU_DECLARE(int) apr_dbd_num_cols(const apr_dbd_driver_t
*driver
,
320 apr_dbd_results_t
*res
)
322 return driver
->num_cols(res
);
325 APU_DECLARE(int) apr_dbd_num_tuples(const apr_dbd_driver_t
*driver
,
326 apr_dbd_results_t
*res
)
328 return driver
->num_tuples(res
);
331 APU_DECLARE(int) apr_dbd_get_row(const apr_dbd_driver_t
*driver
,
333 apr_dbd_results_t
*res
, apr_dbd_row_t
**row
,
336 return driver
->get_row(pool
,res
,row
,rownum
);
339 APU_DECLARE(const char*) apr_dbd_get_entry(const apr_dbd_driver_t
*driver
,
340 apr_dbd_row_t
*row
, int col
)
342 return driver
->get_entry(row
,col
);
345 APU_DECLARE(const char*) apr_dbd_get_name(const apr_dbd_driver_t
*driver
,
346 apr_dbd_results_t
*res
, int col
)
348 return driver
->get_name(res
,col
);
351 APU_DECLARE(const char*) apr_dbd_error(const apr_dbd_driver_t
*driver
,
352 apr_dbd_t
*handle
, int errnum
)
354 return driver
->error(handle
,errnum
);
357 APU_DECLARE(const char*) apr_dbd_escape(const apr_dbd_driver_t
*driver
,
358 apr_pool_t
*pool
, const char *string
,
361 return driver
->escape(pool
,string
,handle
);
364 APU_DECLARE(int) apr_dbd_prepare(const apr_dbd_driver_t
*driver
,
366 apr_dbd_t
*handle
, const char *query
,
368 apr_dbd_prepared_t
**statement
)
371 int i
, nargs
= 0, nvals
= 0;
376 if (!driver
->pformat
) {
380 /* find the number of parameters in the query */
381 for (q
= query
; *q
; q
++) {
383 if (apr_isalpha(q
[1])) {
385 } else if (q
[1] == '%') {
392 qlen
= strlen(query
) +
393 nargs
* (strlen(driver
->pformat
) + sizeof(nargs
) * 3 + 2) + 1;
394 pq
= apr_palloc(pool
, qlen
);
395 t
= apr_pcalloc(pool
, sizeof(*t
) * nargs
);
397 for (p
= pq
, q
= query
, i
= 0; *q
; q
++) {
399 if (apr_isalpha(q
[1])) {
401 case 'd': t
[i
] = APR_DBD_TYPE_INT
; break;
402 case 'u': t
[i
] = APR_DBD_TYPE_UINT
; break;
403 case 'f': t
[i
] = APR_DBD_TYPE_FLOAT
; break;
408 case 'd': t
[i
] = APR_DBD_TYPE_TINY
; q
+= 2; break;
409 case 'u': t
[i
] = APR_DBD_TYPE_UTINY
; q
+= 2; break;
412 case 'd': t
[i
] = APR_DBD_TYPE_SHORT
; q
++; break;
413 case 'u': t
[i
] = APR_DBD_TYPE_USHORT
; q
++; break;
420 case 'd': t
[i
] = APR_DBD_TYPE_LONGLONG
; q
+= 2; break;
421 case 'u': t
[i
] = APR_DBD_TYPE_ULONGLONG
; q
+= 2; break;
424 case 'd': t
[i
] = APR_DBD_TYPE_LONG
; q
++; break;
425 case 'u': t
[i
] = APR_DBD_TYPE_ULONG
; q
++; break;
426 case 'f': t
[i
] = APR_DBD_TYPE_DOUBLE
; q
++; break;
432 case 't': t
[i
] = APR_DBD_TYPE_TEXT
; q
+= 2; break;
433 case 'i': t
[i
] = APR_DBD_TYPE_TIME
; q
+= 2; break;
434 case 'd': t
[i
] = APR_DBD_TYPE_DATE
; q
+= 2; break;
435 case 'a': t
[i
] = APR_DBD_TYPE_DATETIME
; q
+= 2; break;
436 case 's': t
[i
] = APR_DBD_TYPE_TIMESTAMP
; q
+= 2; break;
437 case 'z': t
[i
] = APR_DBD_TYPE_ZTIMESTAMP
; q
+= 2; break;
438 case 'b': t
[i
] = APR_DBD_TYPE_BLOB
; q
+= 2; break;
439 case 'c': t
[i
] = APR_DBD_TYPE_CLOB
; q
+= 2; break;
440 case 'n': t
[i
] = APR_DBD_TYPE_NULL
; q
+= 2; break;
448 case APR_DBD_TYPE_NONE
: /* by default, we expect strings */
449 t
[i
] = APR_DBD_TYPE_STRING
;
451 case APR_DBD_TYPE_BLOB
:
452 case APR_DBD_TYPE_CLOB
: /* three (3) more values passed in */
459 /* insert database specific parameter reference */
460 p
+= apr_snprintf(p
, qlen
- (p
- pq
), driver
->pformat
, ++i
);
461 } else if (q
[1] == '%') { /* reduce %% to % */
472 return driver
->prepare(pool
,handle
,pq
,label
,nargs
,nvals
,t
,statement
);
475 APU_DECLARE(int) apr_dbd_pquery(const apr_dbd_driver_t
*driver
,
477 apr_dbd_t
*handle
, int *nrows
,
478 apr_dbd_prepared_t
*statement
,
479 int nargs
, const char **args
)
481 return driver
->pquery(pool
,handle
,nrows
,statement
,args
);
484 APU_DECLARE(int) apr_dbd_pselect(const apr_dbd_driver_t
*driver
,
486 apr_dbd_t
*handle
, apr_dbd_results_t
**res
,
487 apr_dbd_prepared_t
*statement
, int random
,
488 int nargs
, const char **args
)
490 return driver
->pselect(pool
,handle
,res
,statement
,random
,args
);
493 APU_DECLARE_NONSTD(int) apr_dbd_pvquery(const apr_dbd_driver_t
*driver
,
495 apr_dbd_t
*handle
, int *nrows
,
496 apr_dbd_prepared_t
*statement
, ...)
500 va_start(args
, statement
);
501 ret
= driver
->pvquery(pool
,handle
,nrows
,statement
,args
);
506 APU_DECLARE_NONSTD(int) apr_dbd_pvselect(const apr_dbd_driver_t
*driver
,
507 apr_pool_t
*pool
, apr_dbd_t
*handle
,
508 apr_dbd_results_t
**res
,
509 apr_dbd_prepared_t
*statement
,
514 va_start(args
, random
);
515 ret
= driver
->pvselect(pool
,handle
,res
,statement
,random
,args
);
520 APU_DECLARE(int) apr_dbd_pbquery(const apr_dbd_driver_t
*driver
,
522 apr_dbd_t
*handle
, int *nrows
,
523 apr_dbd_prepared_t
*statement
,
526 return driver
->pbquery(pool
,handle
,nrows
,statement
,args
);
529 APU_DECLARE(int) apr_dbd_pbselect(const apr_dbd_driver_t
*driver
,
531 apr_dbd_t
*handle
, apr_dbd_results_t
**res
,
532 apr_dbd_prepared_t
*statement
, int random
,
535 return driver
->pbselect(pool
,handle
,res
,statement
,random
,args
);
538 APU_DECLARE_NONSTD(int) apr_dbd_pvbquery(const apr_dbd_driver_t
*driver
,
540 apr_dbd_t
*handle
, int *nrows
,
541 apr_dbd_prepared_t
*statement
, ...)
545 va_start(args
, statement
);
546 ret
= driver
->pvbquery(pool
,handle
,nrows
,statement
,args
);
551 APU_DECLARE_NONSTD(int) apr_dbd_pvbselect(const apr_dbd_driver_t
*driver
,
552 apr_pool_t
*pool
, apr_dbd_t
*handle
,
553 apr_dbd_results_t
**res
,
554 apr_dbd_prepared_t
*statement
,
559 va_start(args
, random
);
560 ret
= driver
->pvbselect(pool
,handle
,res
,statement
,random
,args
);
565 APU_DECLARE(apr_status_t
) apr_dbd_datum_get(const apr_dbd_driver_t
*driver
,
566 apr_dbd_row_t
*row
, int col
,
567 apr_dbd_type_e type
, void *data
)
569 return driver
->datum_get(row
,col
,type
,data
);