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"
29 #include "apr_dbd_internal.h"
31 #include "apu_version.h"
33 static apr_hash_t
*drivers
= NULL
;
35 #define CLEANUP_CAST (apr_status_t (*)(void*))
38 static apr_thread_mutex_t
* mutex
= NULL
;
39 apr_status_t
apr_dbd_mutex_lock()
41 return apr_thread_mutex_lock(mutex
);
43 apr_status_t
apr_dbd_mutex_unlock()
45 return apr_thread_mutex_unlock(mutex
);
48 apr_status_t
apr_dbd_mutex_lock() {
51 apr_status_t
apr_dbd_mutex_unlock() {
57 #define DRIVER_LOAD(name,driver,pool) \
59 extern const apr_dbd_driver_t driver; \
60 apr_hash_set(drivers,name,APR_HASH_KEY_STRING,&driver); \
67 static apr_status_t
apr_dbd_term(void *ptr
)
69 /* set drivers to NULL so init can work again */
72 /* Everything else we need is handled by cleanups registered
73 * when we created mutexes and loaded DSOs
78 APU_DECLARE(apr_status_t
) apr_dbd_init(apr_pool_t
*pool
)
80 apr_status_t ret
= APR_SUCCESS
;
82 if (drivers
!= NULL
) {
85 drivers
= apr_hash_make(pool
);
86 apr_pool_cleanup_register(pool
, NULL
, apr_dbd_term
,
87 apr_pool_cleanup_null
);
91 ret
= apr_thread_mutex_create(&mutex
, APR_THREAD_MUTEX_DEFAULT
, pool
);
92 /* This already registers a pool cleanup */
96 /* Load statically-linked drivers: */
98 DRIVER_LOAD("mysql", apr_dbd_mysql_driver
, pool
);
101 DRIVER_LOAD("pgsql", apr_dbd_pgsql_driver
, pool
);
104 DRIVER_LOAD("sqlite3", apr_dbd_sqlite3_driver
, pool
);
107 DRIVER_LOAD("sqlite2", apr_dbd_sqlite2_driver
, pool
);
110 DRIVER_LOAD("oracle", apr_dbd_oracle_driver
, pool
);
112 #if APU_HAVE_SOME_OTHER_BACKEND
113 DRIVER_LOAD("firebird", apr_dbd_other_driver
, pool
);
115 #endif /* APU_DSO_BUILD */
120 #if defined(APU_DSO_BUILD) && APR_HAS_THREADS
121 #define dbd_drivers_lock(m) apr_thread_mutex_lock(m)
122 #define dbd_drivers_unlock(m) apr_thread_mutex_unlock(m)
124 #define dbd_drivers_lock(m) APR_SUCCESS
125 #define dbd_drivers_unlock(m)
128 APU_DECLARE(apr_status_t
) apr_dbd_get_driver(apr_pool_t
*pool
, const char *name
,
129 const apr_dbd_driver_t
**driver
)
133 apr_dso_handle_t
*dlhandle
= NULL
;
134 apr_dso_handle_sym_t symbol
;
138 rv
= dbd_drivers_lock(mutex
);
143 *driver
= apr_hash_get(drivers
, name
, APR_HASH_KEY_STRING
);
145 dbd_drivers_unlock(mutex
);
150 /* The driver DSO must have exactly the same lifetime as the
151 * drivers hash table; ignore the passed-in pool */
152 pool
= apr_hash_pool_get(drivers
);
155 apr_snprintf(path
, sizeof path
, "apr_dbd_%s.dll", name
);
156 #elif defined(NETWARE)
157 apr_snprintf(path
, sizeof path
, "dbd%s.nlm", name
);
159 apr_snprintf(path
, sizeof path
, "%s/apr_dbd_%s.so", APU_DSO_LIBDIR
, name
);
161 rv
= apr_dso_load(&dlhandle
, path
, pool
);
162 if (rv
!= APR_SUCCESS
) { /* APR_EDSOOPEN */
165 apr_snprintf(path
, sizeof path
, "apr_dbd_%s_driver", name
);
166 rv
= apr_dso_sym(&symbol
, dlhandle
, path
);
167 if (rv
!= APR_SUCCESS
) { /* APR_ESYMNOTFOUND */
168 apr_dso_unload(dlhandle
);
172 if ((*driver
)->init
) {
173 (*driver
)->init(pool
);
175 apr_hash_set(drivers
, name
, APR_HASH_KEY_STRING
, *driver
);
178 dbd_drivers_unlock(mutex
);
180 #else /* not builtin and !APR_HAS_DSO => not implemented */
186 APU_DECLARE(apr_status_t
) apr_dbd_open_ex(const apr_dbd_driver_t
*driver
,
187 apr_pool_t
*pool
, const char *params
,
192 *handle
= (driver
->open
)(pool
, params
, error
);
193 if (*handle
== NULL
) {
196 rv
= apr_dbd_check_conn(driver
, pool
, *handle
);
197 if ((rv
!= APR_SUCCESS
) && (rv
!= APR_ENOTIMPL
)) {
198 /* XXX: rv is APR error code, but apr_dbd_error() takes int! */
200 *error
= apr_dbd_error(driver
, *handle
, rv
);
202 apr_dbd_close(driver
, *handle
);
207 APU_DECLARE(apr_status_t
) apr_dbd_open(const apr_dbd_driver_t
*driver
,
208 apr_pool_t
*pool
, const char *params
,
211 return apr_dbd_open_ex(driver
,pool
,params
,handle
,NULL
);
213 APU_DECLARE(int) apr_dbd_transaction_start(const apr_dbd_driver_t
*driver
,
214 apr_pool_t
*pool
, apr_dbd_t
*handle
,
215 apr_dbd_transaction_t
**trans
)
217 int ret
= driver
->start_transaction(pool
, handle
, trans
);
219 apr_pool_cleanup_register(pool
, *trans
,
220 CLEANUP_CAST driver
->end_transaction
,
221 apr_pool_cleanup_null
);
225 APU_DECLARE(int) apr_dbd_transaction_end(const apr_dbd_driver_t
*driver
,
227 apr_dbd_transaction_t
*trans
)
229 apr_pool_cleanup_kill(pool
, trans
, CLEANUP_CAST driver
->end_transaction
);
230 return driver
->end_transaction(trans
);
233 APU_DECLARE(int) apr_dbd_transaction_mode_get(const apr_dbd_driver_t
*driver
,
234 apr_dbd_transaction_t
*trans
)
236 return driver
->transaction_mode_get(trans
);
239 APU_DECLARE(int) apr_dbd_transaction_mode_set(const apr_dbd_driver_t
*driver
,
240 apr_dbd_transaction_t
*trans
,
243 return driver
->transaction_mode_set(trans
, mode
);
246 APU_DECLARE(apr_status_t
) apr_dbd_close(const apr_dbd_driver_t
*driver
,
249 return driver
->close(handle
);
251 APU_DECLARE(const char*) apr_dbd_name(const apr_dbd_driver_t
*driver
)
255 APU_DECLARE(void*) apr_dbd_native_handle(const apr_dbd_driver_t
*driver
,
258 return driver
->native_handle(handle
);
260 APU_DECLARE(int) apr_dbd_check_conn(const apr_dbd_driver_t
*driver
, apr_pool_t
*pool
,
263 return driver
->check_conn(pool
, handle
);
265 APU_DECLARE(int) apr_dbd_set_dbname(const apr_dbd_driver_t
*driver
, apr_pool_t
*pool
,
266 apr_dbd_t
*handle
, const char *name
)
268 return driver
->set_dbname(pool
,handle
,name
);
270 APU_DECLARE(int) apr_dbd_query(const apr_dbd_driver_t
*driver
, apr_dbd_t
*handle
,
271 int *nrows
, const char *statement
)
273 return driver
->query(handle
,nrows
,statement
);
275 APU_DECLARE(int) apr_dbd_select(const apr_dbd_driver_t
*driver
, apr_pool_t
*pool
,
276 apr_dbd_t
*handle
, apr_dbd_results_t
**res
,
277 const char *statement
, int random
)
279 return driver
->select(pool
,handle
,res
,statement
,random
);
281 APU_DECLARE(int) apr_dbd_num_cols(const apr_dbd_driver_t
*driver
,
282 apr_dbd_results_t
*res
)
284 return driver
->num_cols(res
);
286 APU_DECLARE(int) apr_dbd_num_tuples(const apr_dbd_driver_t
*driver
,
287 apr_dbd_results_t
*res
)
289 return driver
->num_tuples(res
);
291 APU_DECLARE(int) apr_dbd_get_row(const apr_dbd_driver_t
*driver
, apr_pool_t
*pool
,
292 apr_dbd_results_t
*res
, apr_dbd_row_t
**row
,
295 return driver
->get_row(pool
,res
,row
,rownum
);
297 APU_DECLARE(const char*) apr_dbd_get_entry(const apr_dbd_driver_t
*driver
,
298 apr_dbd_row_t
*row
, int col
)
300 return driver
->get_entry(row
,col
);
302 APU_DECLARE(const char*) apr_dbd_get_name(const apr_dbd_driver_t
*driver
,
303 apr_dbd_results_t
*res
, int col
)
305 return driver
->get_name(res
,col
);
307 APU_DECLARE(const char*) apr_dbd_error(const apr_dbd_driver_t
*driver
,
308 apr_dbd_t
*handle
, int errnum
)
310 return driver
->error(handle
,errnum
);
312 APU_DECLARE(const char*) apr_dbd_escape(const apr_dbd_driver_t
*driver
,
313 apr_pool_t
*pool
, const char *string
,
316 return driver
->escape(pool
,string
,handle
);
318 APU_DECLARE(int) apr_dbd_prepare(const apr_dbd_driver_t
*driver
, apr_pool_t
*pool
,
319 apr_dbd_t
*handle
, const char *query
,
321 apr_dbd_prepared_t
**statement
)
324 int i
, nargs
= 0, nvals
= 0;
329 if (!driver
->pformat
) {
333 /* find the number of parameters in the query */
334 for (q
= query
; *q
; q
++) {
338 } else if (q
[1] == '%') {
345 qlen
= strlen(query
) +
346 nargs
* (strlen(driver
->pformat
) + sizeof(nargs
) * 3 + 2) + 1;
347 pq
= apr_palloc(pool
, qlen
);
348 t
= apr_pcalloc(pool
, sizeof(*t
) * nargs
);
350 for (p
= pq
, q
= query
, i
= 0; *q
; q
++) {
354 case 'd': t
[i
] = APR_DBD_TYPE_INT
; break;
355 case 'u': t
[i
] = APR_DBD_TYPE_UINT
; break;
356 case 'f': t
[i
] = APR_DBD_TYPE_FLOAT
; break;
361 case 'd': t
[i
] = APR_DBD_TYPE_TINY
; q
+= 2; break;
362 case 'u': t
[i
] = APR_DBD_TYPE_UTINY
; q
+= 2; break;
365 case 'd': t
[i
] = APR_DBD_TYPE_SHORT
; q
++; break;
366 case 'u': t
[i
] = APR_DBD_TYPE_USHORT
; q
++; break;
373 case 'd': t
[i
] = APR_DBD_TYPE_LONGLONG
; q
+= 2; break;
374 case 'u': t
[i
] = APR_DBD_TYPE_ULONGLONG
; q
+= 2; break;
377 case 'd': t
[i
] = APR_DBD_TYPE_LONG
; q
++; break;
378 case 'u': t
[i
] = APR_DBD_TYPE_ULONG
; q
++; break;
379 case 'f': t
[i
] = APR_DBD_TYPE_DOUBLE
; q
++; break;
385 case 't': t
[i
] = APR_DBD_TYPE_TEXT
; q
+= 2; break;
386 case 'i': t
[i
] = APR_DBD_TYPE_TIME
; q
+= 2; break;
387 case 'd': t
[i
] = APR_DBD_TYPE_DATE
; q
+= 2; break;
388 case 'a': t
[i
] = APR_DBD_TYPE_DATETIME
; q
+= 2; break;
389 case 's': t
[i
] = APR_DBD_TYPE_TIMESTAMP
; q
+= 2; break;
390 case 'z': t
[i
] = APR_DBD_TYPE_ZTIMESTAMP
; q
+= 2; break;
391 case 'b': t
[i
] = APR_DBD_TYPE_BLOB
; q
+= 2; break;
392 case 'c': t
[i
] = APR_DBD_TYPE_CLOB
; q
+= 2; break;
393 case 'n': t
[i
] = APR_DBD_TYPE_NULL
; q
+= 2; break;
401 case APR_DBD_TYPE_NONE
: /* by default, we expect strings */
402 t
[i
] = APR_DBD_TYPE_STRING
;
404 case APR_DBD_TYPE_BLOB
:
405 case APR_DBD_TYPE_CLOB
: /* three (3) more values passed in */
412 /* insert database specific parameter reference */
413 p
+= apr_snprintf(p
, qlen
- (p
- pq
), driver
->pformat
, ++i
);
414 } else if (q
[1] == '%') { /* reduce %% to % */
425 return driver
->prepare(pool
,handle
,pq
,label
,nargs
,nvals
,t
,statement
);
427 APU_DECLARE(int) apr_dbd_pquery(const apr_dbd_driver_t
*driver
, apr_pool_t
*pool
,
428 apr_dbd_t
*handle
, int *nrows
,
429 apr_dbd_prepared_t
*statement
,
430 int nargs
, const char **args
)
432 return driver
->pquery(pool
,handle
,nrows
,statement
,args
);
434 APU_DECLARE(int) apr_dbd_pselect(const apr_dbd_driver_t
*driver
, apr_pool_t
*pool
,
435 apr_dbd_t
*handle
, apr_dbd_results_t
**res
,
436 apr_dbd_prepared_t
*statement
, int random
,
437 int nargs
, const char **args
)
439 return driver
->pselect(pool
,handle
,res
,statement
,random
,args
);
441 APU_DECLARE(int) apr_dbd_pvquery(const apr_dbd_driver_t
*driver
, apr_pool_t
*pool
,
442 apr_dbd_t
*handle
, int *nrows
,
443 apr_dbd_prepared_t
*statement
,...)
447 va_start(args
, statement
);
448 ret
= driver
->pvquery(pool
,handle
,nrows
,statement
,args
);
452 APU_DECLARE(int) apr_dbd_pvselect(const apr_dbd_driver_t
*driver
, apr_pool_t
*pool
,
453 apr_dbd_t
*handle
, apr_dbd_results_t
**res
,
454 apr_dbd_prepared_t
*statement
, int random
,...)
458 va_start(args
, random
);
459 ret
= driver
->pvselect(pool
,handle
,res
,statement
,random
,args
);
463 APU_DECLARE(int) apr_dbd_pbquery(const apr_dbd_driver_t
*driver
,
465 apr_dbd_t
*handle
, int *nrows
,
466 apr_dbd_prepared_t
*statement
,
469 return driver
->pbquery(pool
,handle
,nrows
,statement
,args
);
471 APU_DECLARE(int) apr_dbd_pbselect(const apr_dbd_driver_t
*driver
,
473 apr_dbd_t
*handle
, apr_dbd_results_t
**res
,
474 apr_dbd_prepared_t
*statement
, int random
,
477 return driver
->pbselect(pool
,handle
,res
,statement
,random
,args
);
479 APU_DECLARE(int) apr_dbd_pvbquery(const apr_dbd_driver_t
*driver
,
481 apr_dbd_t
*handle
, int *nrows
,
482 apr_dbd_prepared_t
*statement
,...)
486 va_start(args
, statement
);
487 ret
= driver
->pvbquery(pool
,handle
,nrows
,statement
,args
);
491 APU_DECLARE(int) apr_dbd_pvbselect(const apr_dbd_driver_t
*driver
,
493 apr_dbd_t
*handle
, apr_dbd_results_t
**res
,
494 apr_dbd_prepared_t
*statement
,
499 va_start(args
, random
);
500 ret
= driver
->pvbselect(pool
,handle
,res
,statement
,random
,args
);
504 APU_DECLARE(apr_status_t
) apr_dbd_datum_get(const apr_dbd_driver_t
*driver
,
505 apr_dbd_row_t
*row
, int col
,
506 apr_dbd_type_e type
, void *data
)
508 return driver
->datum_get(row
,col
,type
,data
);