]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/apr-util/dbd/apr_dbd.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / apr-util / dbd / apr_dbd.c
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <ctype.h>
18 #include <stdio.h>
19
20 #include "apu_config.h"
21 #include "apu.h"
22
23 #include "apr_pools.h"
24 #include "apr_dso.h"
25 #include "apr_strings.h"
26 #include "apr_hash.h"
27 #include "apr_thread_mutex.h"
28 #include "apr_lib.h"
29 #include "apr_atomic.h"
30
31 #include "apu_internal.h"
32 #include "apr_dbd_internal.h"
33 #include "apr_dbd.h"
34 #include "apu_version.h"
35
36 static apr_hash_t *drivers = NULL;
37 static apr_uint32_t initialised = 0, in_init = 1;
38
39 #define CLEANUP_CAST (apr_status_t (*)(void*))
40
41 #if APR_HAS_THREADS
42 /* deprecated, but required for existing providers.  Existing and new
43  * providers should be refactored to use a provider-specific mutex so
44  * that different providers do not block one another.
45  * In APR 1.3 this is no longer used for dso module loading, and
46  * apu_dso_mutex_[un]lock is used instead.
47  * In APR 2.0 this should become entirely local to libaprutil-2.so and
48  * no longer be exported.
49  */
50 static apr_thread_mutex_t* mutex = NULL;
51 APU_DECLARE(apr_status_t) apr_dbd_mutex_lock()
52 {
53     return apr_thread_mutex_lock(mutex);
54 }
55 APU_DECLARE(apr_status_t) apr_dbd_mutex_unlock()
56 {
57     return apr_thread_mutex_unlock(mutex);
58 }
59 #else
60 APU_DECLARE(apr_status_t) apr_dbd_mutex_lock() {
61     return APR_SUCCESS;
62 }
63 APU_DECLARE(apr_status_t) apr_dbd_mutex_unlock() {
64     return APR_SUCCESS;
65 }
66 #endif
67
68 #if !APU_DSO_BUILD
69 #define DRIVER_LOAD(name,driver,pool) \
70     {   \
71         extern const apr_dbd_driver_t driver; \
72         apr_hash_set(drivers,name,APR_HASH_KEY_STRING,&driver); \
73         if (driver.init) {     \
74             driver.init(pool); \
75         }  \
76     }
77 #endif
78
79 static apr_status_t apr_dbd_term(void *ptr)
80 {
81     /* set drivers to NULL so init can work again */
82     drivers = NULL;
83
84     /* Everything else we need is handled by cleanups registered
85      * when we created mutexes and loaded DSOs
86      */
87     return APR_SUCCESS;
88 }
89
90 APU_DECLARE(apr_status_t) apr_dbd_init(apr_pool_t *pool)
91 {
92     apr_status_t ret = APR_SUCCESS;
93     apr_pool_t *parent;
94
95     if (apr_atomic_inc32(&initialised)) {
96         apr_atomic_set32(&initialised, 1); /* prevent wrap-around */
97
98         while (apr_atomic_read32(&in_init)) /* wait until we get fully inited */
99             ;
100
101         return APR_SUCCESS;
102     }
103
104     /* Top level pool scope, need process-scope lifetime */
105     for (parent = apr_pool_parent_get(pool);
106         parent && parent != pool;
107         parent = apr_pool_parent_get(pool))
108        pool = parent;
109 #if APU_DSO_BUILD
110     /* deprecate in 2.0 - permit implicit initialization */
111     apu_dso_init(pool);
112 #endif
113
114     drivers = apr_hash_make(pool);
115
116 #if APR_HAS_THREADS
117     ret = apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_DEFAULT, pool);
118     /* This already registers a pool cleanup */
119 #endif
120
121 #if !APU_DSO_BUILD
122
123     /* Load statically-linked drivers: */
124 #if APU_HAVE_MYSQL
125     DRIVER_LOAD("mysql", apr_dbd_mysql_driver, pool);
126 #endif
127 #if APU_HAVE_PGSQL
128     DRIVER_LOAD("pgsql", apr_dbd_pgsql_driver, pool);
129 #endif
130 #if APU_HAVE_SQLITE3
131     DRIVER_LOAD("sqlite3", apr_dbd_sqlite3_driver, pool);
132 #endif
133 #if APU_HAVE_SQLITE2
134     DRIVER_LOAD("sqlite2", apr_dbd_sqlite2_driver, pool);
135 #endif
136 #if APU_HAVE_ORACLE
137     DRIVER_LOAD("oracle", apr_dbd_oracle_driver, pool);
138 #endif
139 #if APU_HAVE_FREETDS
140     DRIVER_LOAD("freetds", apr_dbd_freetds_driver, pool);
141 #endif
142 #if APU_HAVE_ODBC
143     DRIVER_LOAD("odbc", apr_dbd_odbc_driver, pool);
144 #endif
145 #if APU_HAVE_SOME_OTHER_BACKEND
146     DRIVER_LOAD("firebird", apr_dbd_other_driver, pool);
147 #endif
148 #endif /* APU_DSO_BUILD */
149
150     apr_pool_cleanup_register(pool, NULL, apr_dbd_term,
151                               apr_pool_cleanup_null);
152
153     apr_atomic_dec32(&in_init);
154
155     return ret;
156 }
157
158 APU_DECLARE(apr_status_t) apr_dbd_get_driver(apr_pool_t *pool, const char *name,
159                                              const apr_dbd_driver_t **driver)
160 {
161 #if APU_DSO_BUILD
162     char modname[32];
163     char symname[34];
164     apr_dso_handle_sym_t symbol;
165 #endif
166     apr_status_t rv;
167
168 #if APU_DSO_BUILD
169     rv = apu_dso_mutex_lock();
170     if (rv) {
171         return rv;
172     }
173 #endif
174     *driver = apr_hash_get(drivers, name, APR_HASH_KEY_STRING);
175     if (*driver) {
176 #if APU_DSO_BUILD
177         apu_dso_mutex_unlock();
178 #endif
179         return APR_SUCCESS;
180     }
181
182 #if APU_DSO_BUILD
183     /* The driver DSO must have exactly the same lifetime as the
184      * drivers hash table; ignore the passed-in pool */
185     pool = apr_hash_pool_get(drivers);
186
187 #if defined(NETWARE)
188     apr_snprintf(modname, sizeof(modname), "dbd%s.nlm", name);
189 #elif defined(WIN32) || defined(__CYGWIN__)
190     apr_snprintf(modname, sizeof(modname),
191                  "apr_dbd_%s-" APU_STRINGIFY(APU_MAJOR_VERSION) ".dll", name);
192 #else
193     apr_snprintf(modname, sizeof(modname),
194                  "apr_dbd_%s-" APU_STRINGIFY(APU_MAJOR_VERSION) ".so", name);
195 #endif
196     apr_snprintf(symname, sizeof(symname), "apr_dbd_%s_driver", name);
197     rv = apu_dso_load(NULL, &symbol, modname, symname, pool);
198     if (rv == APR_SUCCESS || rv == APR_EINIT) { /* previously loaded?!? */
199         *driver = symbol;
200         name = apr_pstrdup(pool, name);
201         apr_hash_set(drivers, name, APR_HASH_KEY_STRING, *driver);
202         rv = APR_SUCCESS;
203         if ((*driver)->init) {
204             (*driver)->init(pool);
205         }
206     }
207     apu_dso_mutex_unlock();
208
209 #else /* not builtin and !APU_DSO_BUILD => not implemented */
210     rv = APR_ENOTIMPL;
211 #endif
212
213     return rv;
214 }
215
216 APU_DECLARE(apr_status_t) apr_dbd_open_ex(const apr_dbd_driver_t *driver,
217                                           apr_pool_t *pool, const char *params,
218                                           apr_dbd_t **handle,
219                                           const char **error)
220 {
221     apr_status_t rv;
222     *handle = (driver->open)(pool, params, error);
223     if (*handle == NULL) {
224         return APR_EGENERAL;
225     }
226     rv = apr_dbd_check_conn(driver, pool, *handle);
227     if ((rv != APR_SUCCESS) && (rv != APR_ENOTIMPL)) {
228         /* XXX: rv is APR error code, but apr_dbd_error() takes int! */
229         if (error) {
230             *error = apr_dbd_error(driver, *handle, rv);
231         }
232         apr_dbd_close(driver, *handle);
233         return APR_EGENERAL;
234     }
235     return APR_SUCCESS;
236 }
237
238 APU_DECLARE(apr_status_t) apr_dbd_open(const apr_dbd_driver_t *driver,
239                                        apr_pool_t *pool, const char *params,
240                                        apr_dbd_t **handle)
241 {
242     return apr_dbd_open_ex(driver,pool,params,handle,NULL);
243 }
244
245 APU_DECLARE(int) apr_dbd_transaction_start(const apr_dbd_driver_t *driver,
246                                            apr_pool_t *pool, apr_dbd_t *handle,
247                                            apr_dbd_transaction_t **trans)
248 {
249     int ret = driver->start_transaction(pool, handle, trans);
250     if (*trans) {
251         apr_pool_cleanup_register(pool, *trans,
252                                   CLEANUP_CAST driver->end_transaction,
253                                   apr_pool_cleanup_null);
254     }
255     return ret;
256 }
257
258 APU_DECLARE(int) apr_dbd_transaction_end(const apr_dbd_driver_t *driver,
259                                          apr_pool_t *pool,
260                                          apr_dbd_transaction_t *trans)
261 {
262     apr_pool_cleanup_kill(pool, trans, CLEANUP_CAST driver->end_transaction);
263     return driver->end_transaction(trans);
264 }
265
266 APU_DECLARE(int) apr_dbd_transaction_mode_get(const apr_dbd_driver_t *driver,
267                                               apr_dbd_transaction_t *trans)
268 {
269     return driver->transaction_mode_get(trans);
270 }
271
272 APU_DECLARE(int) apr_dbd_transaction_mode_set(const apr_dbd_driver_t *driver,
273                                               apr_dbd_transaction_t *trans,
274                                               int mode)
275 {
276     return driver->transaction_mode_set(trans, mode);
277 }
278
279 APU_DECLARE(apr_status_t) apr_dbd_close(const apr_dbd_driver_t *driver,
280                                         apr_dbd_t *handle)
281 {
282     return driver->close(handle);
283 }
284
285 APU_DECLARE(const char*) apr_dbd_name(const apr_dbd_driver_t *driver)
286 {
287     return driver->name;
288 }
289
290 APU_DECLARE(void*) apr_dbd_native_handle(const apr_dbd_driver_t *driver,
291                                          apr_dbd_t *handle)
292 {
293     return driver->native_handle(handle);
294 }
295
296 APU_DECLARE(int) apr_dbd_check_conn(const apr_dbd_driver_t *driver,
297                                     apr_pool_t *pool,
298                                     apr_dbd_t *handle)
299 {
300     return driver->check_conn(pool, handle);
301 }
302
303 APU_DECLARE(int) apr_dbd_set_dbname(const apr_dbd_driver_t *driver,
304                                     apr_pool_t *pool,
305                                     apr_dbd_t *handle, const char *name)
306 {
307     return driver->set_dbname(pool,handle,name);
308 }
309
310 APU_DECLARE(int) apr_dbd_query(const apr_dbd_driver_t *driver,
311                                apr_dbd_t *handle,
312                                int *nrows, const char *statement)
313 {
314     return driver->query(handle,nrows,statement);
315 }
316
317 APU_DECLARE(int) apr_dbd_select(const apr_dbd_driver_t *driver,
318                                 apr_pool_t *pool,
319                                 apr_dbd_t *handle, apr_dbd_results_t **res,
320                                 const char *statement, int random)
321 {
322     return driver->select(pool,handle,res,statement,random);
323 }
324
325 APU_DECLARE(int) apr_dbd_num_cols(const apr_dbd_driver_t *driver,
326                                   apr_dbd_results_t *res)
327 {
328     return driver->num_cols(res);
329 }
330
331 APU_DECLARE(int) apr_dbd_num_tuples(const apr_dbd_driver_t *driver,
332                                     apr_dbd_results_t *res)
333 {
334     return driver->num_tuples(res);
335 }
336
337 APU_DECLARE(int) apr_dbd_get_row(const apr_dbd_driver_t *driver,
338                                  apr_pool_t *pool,
339                                  apr_dbd_results_t *res, apr_dbd_row_t **row,
340                                  int rownum)
341 {
342     return driver->get_row(pool,res,row,rownum);
343 }
344
345 APU_DECLARE(const char*) apr_dbd_get_entry(const apr_dbd_driver_t *driver,
346                                            apr_dbd_row_t *row, int col)
347 {
348     return driver->get_entry(row,col);
349 }
350
351 APU_DECLARE(const char*) apr_dbd_get_name(const apr_dbd_driver_t *driver,
352                                           apr_dbd_results_t *res, int col)
353 {
354     return driver->get_name(res,col);
355 }
356
357 APU_DECLARE(const char*) apr_dbd_error(const apr_dbd_driver_t *driver,
358                                        apr_dbd_t *handle, int errnum)
359 {
360     return driver->error(handle,errnum);
361 }
362
363 APU_DECLARE(const char*) apr_dbd_escape(const apr_dbd_driver_t *driver,
364                                         apr_pool_t *pool, const char *string,
365                                         apr_dbd_t *handle)
366 {
367     return driver->escape(pool,string,handle);
368 }
369
370 APU_DECLARE(int) apr_dbd_prepare(const apr_dbd_driver_t *driver,
371                                  apr_pool_t *pool,
372                                  apr_dbd_t *handle, const char *query,
373                                  const char *label,
374                                  apr_dbd_prepared_t **statement)
375 {
376     size_t qlen;
377     int i, nargs = 0, nvals = 0;
378     char *p, *pq;
379     const char *q;
380     apr_dbd_type_e *t;
381
382     if (!driver->pformat) {
383         return APR_ENOTIMPL;
384     }
385
386     /* find the number of parameters in the query */
387     for (q = query; *q; q++) {
388         if (q[0] == '%') {
389             if (apr_isalpha(q[1])) {
390                 nargs++;
391             } else if (q[1] == '%') {
392                 q++;
393             }
394         }
395     }
396     nvals = nargs;
397
398     qlen = strlen(query) +
399            nargs * (strlen(driver->pformat) + sizeof(nargs) * 3 + 2) + 1;
400     pq = apr_palloc(pool, qlen);
401     t = apr_pcalloc(pool, sizeof(*t) * nargs);
402
403     for (p = pq, q = query, i = 0; *q; q++) {
404         if (q[0] == '%') {
405             if (apr_isalpha(q[1])) {
406                 switch (q[1]) {
407                 case 'd': t[i] = APR_DBD_TYPE_INT;   break;
408                 case 'u': t[i] = APR_DBD_TYPE_UINT;  break;
409                 case 'f': t[i] = APR_DBD_TYPE_FLOAT; break;
410                 case 'h':
411                     switch (q[2]) {
412                     case 'h':
413                         switch (q[3]){
414                         case 'd': t[i] = APR_DBD_TYPE_TINY;  q += 2; break;
415                         case 'u': t[i] = APR_DBD_TYPE_UTINY; q += 2; break;
416                         }
417                         break;
418                     case 'd': t[i] = APR_DBD_TYPE_SHORT;  q++; break;
419                     case 'u': t[i] = APR_DBD_TYPE_USHORT; q++; break;
420                     }
421                     break;
422                 case 'l':
423                     switch (q[2]) {
424                     case 'l':
425                         switch (q[3]){
426                         case 'd': t[i] = APR_DBD_TYPE_LONGLONG;  q += 2; break;
427                         case 'u': t[i] = APR_DBD_TYPE_ULONGLONG; q += 2; break;
428                         }
429                         break;
430                     case 'd': t[i] = APR_DBD_TYPE_LONG;   q++; break;
431                     case 'u': t[i] = APR_DBD_TYPE_ULONG;  q++; break;
432                     case 'f': t[i] = APR_DBD_TYPE_DOUBLE; q++; break;
433                     }
434                     break;
435                 case 'p':
436                     if (q[2] == 'D') {
437                         switch (q[3]) {
438                         case 't': t[i] = APR_DBD_TYPE_TEXT;       q += 2; break;
439                         case 'i': t[i] = APR_DBD_TYPE_TIME;       q += 2; break;
440                         case 'd': t[i] = APR_DBD_TYPE_DATE;       q += 2; break;
441                         case 'a': t[i] = APR_DBD_TYPE_DATETIME;   q += 2; break;
442                         case 's': t[i] = APR_DBD_TYPE_TIMESTAMP;  q += 2; break;
443                         case 'z': t[i] = APR_DBD_TYPE_ZTIMESTAMP; q += 2; break;
444                         case 'b': t[i] = APR_DBD_TYPE_BLOB;       q += 2; break;
445                         case 'c': t[i] = APR_DBD_TYPE_CLOB;       q += 2; break;
446                         case 'n': t[i] = APR_DBD_TYPE_NULL;       q += 2; break;
447                         }
448                     }
449                     break;
450                 }
451                 q++;
452
453                 switch (t[i]) {
454                 case APR_DBD_TYPE_NONE: /* by default, we expect strings */
455                     t[i] = APR_DBD_TYPE_STRING;
456                     break;
457                 case APR_DBD_TYPE_BLOB:
458                 case APR_DBD_TYPE_CLOB: /* three (3) more values passed in */
459                     nvals += 3;
460                     break;
461                 default:
462                     break;
463                 }
464
465                 /* insert database specific parameter reference */
466                 p += apr_snprintf(p, qlen - (p - pq), driver->pformat, ++i);
467             } else if (q[1] == '%') { /* reduce %% to % */
468                 *p++ = *q++;
469             } else {
470                 *p++ = *q;
471             }
472         } else {
473             *p++ = *q;
474         }
475     }
476     *p = '\0';
477
478     return driver->prepare(pool,handle,pq,label,nargs,nvals,t,statement);
479 }
480
481 APU_DECLARE(int) apr_dbd_pquery(const apr_dbd_driver_t *driver,
482                                 apr_pool_t *pool,
483                                 apr_dbd_t *handle, int *nrows,
484                                 apr_dbd_prepared_t *statement,
485                                 int nargs, const char **args)
486 {
487     return driver->pquery(pool,handle,nrows,statement,args);
488 }
489
490 APU_DECLARE(int) apr_dbd_pselect(const apr_dbd_driver_t *driver,
491                                  apr_pool_t *pool,
492                                  apr_dbd_t *handle, apr_dbd_results_t **res,
493                                  apr_dbd_prepared_t *statement, int random,
494                                  int nargs, const char **args)
495 {
496     return driver->pselect(pool,handle,res,statement,random,args);
497 }
498
499 APU_DECLARE_NONSTD(int) apr_dbd_pvquery(const apr_dbd_driver_t *driver,
500                                         apr_pool_t *pool,
501                                         apr_dbd_t *handle, int *nrows,
502                                         apr_dbd_prepared_t *statement, ...)
503 {
504     int ret;
505     va_list args;
506     va_start(args, statement);
507     ret = driver->pvquery(pool,handle,nrows,statement,args);
508     va_end(args);
509     return ret;
510 }
511
512 APU_DECLARE_NONSTD(int) apr_dbd_pvselect(const apr_dbd_driver_t *driver,
513                                          apr_pool_t *pool, apr_dbd_t *handle,
514                                          apr_dbd_results_t **res,
515                                          apr_dbd_prepared_t *statement,
516                                          int random, ...)
517 {
518     int ret;
519     va_list args;
520     va_start(args, random);
521     ret = driver->pvselect(pool,handle,res,statement,random,args);
522     va_end(args);
523     return ret;
524 }
525
526 APU_DECLARE(int) apr_dbd_pbquery(const apr_dbd_driver_t *driver,
527                                  apr_pool_t *pool,
528                                  apr_dbd_t *handle, int *nrows,
529                                  apr_dbd_prepared_t *statement,
530                                  const void **args)
531 {
532     return driver->pbquery(pool,handle,nrows,statement,args);
533 }
534
535 APU_DECLARE(int) apr_dbd_pbselect(const apr_dbd_driver_t *driver,
536                                   apr_pool_t *pool,
537                                   apr_dbd_t *handle, apr_dbd_results_t **res,
538                                   apr_dbd_prepared_t *statement, int random,
539                                   const void **args)
540 {
541     return driver->pbselect(pool,handle,res,statement,random,args);
542 }
543
544 APU_DECLARE_NONSTD(int) apr_dbd_pvbquery(const apr_dbd_driver_t *driver,
545                                          apr_pool_t *pool,
546                                          apr_dbd_t *handle, int *nrows,
547                                          apr_dbd_prepared_t *statement, ...)
548 {
549     int ret;
550     va_list args;
551     va_start(args, statement);
552     ret = driver->pvbquery(pool,handle,nrows,statement,args);
553     va_end(args);
554     return ret;
555 }
556
557 APU_DECLARE_NONSTD(int) apr_dbd_pvbselect(const apr_dbd_driver_t *driver,
558                                           apr_pool_t *pool, apr_dbd_t *handle,
559                                           apr_dbd_results_t **res,
560                                           apr_dbd_prepared_t *statement,
561                                           int random, ...)
562 {
563     int ret;
564     va_list args;
565     va_start(args, random);
566     ret = driver->pvbselect(pool,handle,res,statement,random,args);
567     va_end(args);
568     return ret;
569 }
570
571 APU_DECLARE(apr_status_t) apr_dbd_datum_get(const apr_dbd_driver_t *driver,
572                                             apr_dbd_row_t *row, int col,
573                                             apr_dbd_type_e type, void *data)
574 {
575     return driver->datum_get(row,col,type,data);
576 }