]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/apr-util/dbd/apr_dbd_sqlite2.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_sqlite2.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 "apu.h"
18
19 #if APU_HAVE_SQLITE2
20
21 #include <ctype.h>
22 #include <stdlib.h>
23
24 #include <sqlite.h>
25
26 #include "apr_strings.h"
27 #include "apr_time.h"
28 #include "apr_buckets.h"
29
30 #include "apr_dbd_internal.h"
31
32 struct apr_dbd_transaction_t {
33     int mode;
34     int errnum;
35     apr_dbd_t *handle;
36 };
37
38 struct apr_dbd_t {
39     sqlite *conn;
40     char *errmsg;
41     apr_dbd_transaction_t *trans;
42 };
43
44 struct apr_dbd_results_t {
45     int random;
46     sqlite *handle;
47     char **res;
48     size_t ntuples;
49     size_t sz;
50     size_t index;
51     apr_pool_t *pool;
52 };
53
54 struct apr_dbd_row_t {
55     int n;
56     char **data;
57     apr_dbd_results_t *res;
58 };
59
60 struct apr_dbd_prepared_t {
61     const char *name;
62     int prepared;
63 };
64
65 #define FREE_ERROR_MSG(dbd) \
66         do { \
67                 if(dbd && dbd->errmsg) { \
68                         free(dbd->errmsg); \
69                         dbd->errmsg = NULL; \
70                 } \
71         } while(0);
72
73 static apr_status_t free_table(void *data)
74 {
75     sqlite_free_table(data); 
76     return APR_SUCCESS;
77 }
78
79 static int dbd_sqlite_select(apr_pool_t * pool, apr_dbd_t * sql,
80                              apr_dbd_results_t ** results, const char *query,
81                              int seek)
82 {
83     char **result;
84     int ret = 0;
85     int tuples = 0;
86     int fields = 0;
87
88     if (sql->trans && sql->trans->errnum) {
89         return sql->trans->errnum;
90     }
91
92     FREE_ERROR_MSG(sql);
93
94     ret = sqlite_get_table(sql->conn, query, &result, &tuples, &fields,
95                           &sql->errmsg);
96
97     if (ret == SQLITE_OK) {
98         if (!*results) {
99             *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
100         }
101
102         (*results)->res = result;
103         (*results)->ntuples = tuples;
104         (*results)->sz = fields;
105         (*results)->random = seek;
106         (*results)->pool = pool;
107
108         if (tuples > 0)
109             apr_pool_cleanup_register(pool, result, free_table,
110                                       apr_pool_cleanup_null);
111
112         ret = 0;
113     }
114     else {
115         if (TXN_NOTICE_ERRORS(sql->trans)) {
116             sql->trans->errnum = ret;
117         }
118     }
119
120     return ret;
121 }
122
123 static const char *dbd_sqlite_get_name(const apr_dbd_results_t *res, int n)
124 {
125     if ((n < 0) || (n >= res->sz)) {
126         return NULL;
127     }
128
129     return res->res[n];
130 }
131
132 static int dbd_sqlite_get_row(apr_pool_t * pool, apr_dbd_results_t * res,
133                               apr_dbd_row_t ** rowp, int rownum)
134 {
135     apr_dbd_row_t *row = *rowp;
136     int sequential = ((rownum >= 0) && res->random) ? 0 : 1;
137
138     if (row == NULL) {
139         row = apr_palloc(pool, sizeof(apr_dbd_row_t));
140         *rowp = row;
141         row->res = res;
142         row->n = sequential ? 0 : rownum - 1;
143     }
144     else {
145         if (sequential) {
146             ++row->n;
147         }
148         else {
149             row->n = rownum - 1;
150         }
151     }
152
153     if (row->n >= res->ntuples) {
154         *rowp = NULL;
155         apr_pool_cleanup_run(res->pool, res->res, free_table);
156         res->res = NULL;
157         return -1;
158     }
159
160     /* Pointer magic explanation:
161      *      The sqlite result is an array such that the first res->sz elements are 
162      *      the column names and each tuple follows afterwards 
163      *      ex: (from the sqlite2 documentation)
164      SELECT employee_name, login, host FROM users WHERE login LIKE *        'd%';
165
166      nrow = 2
167      ncolumn = 3
168      result[0] = "employee_name"
169      result[1] = "login"
170      result[2] = "host"
171      result[3] = "dummy"
172      result[4] = "No such user"
173      result[5] = 0
174      result[6] = "D. Richard Hipp"
175      result[7] = "drh"
176      result[8] = "zadok"
177      */
178
179     row->data = res->res + res->sz + (res->sz * row->n);
180
181     return 0;
182 }
183
184 static const char *dbd_sqlite_get_entry(const apr_dbd_row_t * row, int n)
185 {
186     if ((n < 0) || (n >= row->res->sz)) {
187       return NULL;
188     }
189
190     return row->data[n];
191 }
192
193 static apr_status_t dbd_sqlite_datum_get(const apr_dbd_row_t *row, int n,
194                                          apr_dbd_type_e type, void *data)
195 {
196     if ((n < 0) || (n >= row->res->sz)) {
197       return APR_EGENERAL;
198     }
199
200     if (row->data[n] == NULL) {
201         return APR_ENOENT;
202     }
203
204     switch (type) {
205     case APR_DBD_TYPE_TINY:
206         *(char*)data = atoi(row->data[n]);
207         break;
208     case APR_DBD_TYPE_UTINY:
209         *(unsigned char*)data = atoi(row->data[n]);
210         break;
211     case APR_DBD_TYPE_SHORT:
212         *(short*)data = atoi(row->data[n]);
213         break;
214     case APR_DBD_TYPE_USHORT:
215         *(unsigned short*)data = atoi(row->data[n]);
216         break;
217     case APR_DBD_TYPE_INT:
218         *(int*)data = atoi(row->data[n]);
219         break;
220     case APR_DBD_TYPE_UINT:
221         *(unsigned int*)data = atoi(row->data[n]);
222         break;
223     case APR_DBD_TYPE_LONG:
224         *(long*)data = atol(row->data[n]);
225         break;
226     case APR_DBD_TYPE_ULONG:
227         *(unsigned long*)data = atol(row->data[n]);
228         break;
229     case APR_DBD_TYPE_LONGLONG:
230         *(apr_int64_t*)data = apr_atoi64(row->data[n]);
231         break;
232     case APR_DBD_TYPE_ULONGLONG:
233         *(apr_uint64_t*)data = apr_atoi64(row->data[n]);
234         break;
235     case APR_DBD_TYPE_FLOAT:
236         *(float*)data = atof(row->data[n]);
237         break;
238     case APR_DBD_TYPE_DOUBLE:
239         *(double*)data = atof(row->data[n]);
240         break;
241     case APR_DBD_TYPE_STRING:
242     case APR_DBD_TYPE_TEXT:
243     case APR_DBD_TYPE_TIME:
244     case APR_DBD_TYPE_DATE:
245     case APR_DBD_TYPE_DATETIME:
246     case APR_DBD_TYPE_TIMESTAMP:
247     case APR_DBD_TYPE_ZTIMESTAMP:
248         *(char**)data = row->data[n];
249         break;
250     case APR_DBD_TYPE_BLOB:
251     case APR_DBD_TYPE_CLOB:
252         {
253         apr_bucket *e;
254         apr_bucket_brigade *b = (apr_bucket_brigade*)data;
255
256         e = apr_bucket_pool_create(row->data[n],strlen(row->data[n]),
257                                    row->res->pool, b->bucket_alloc);
258         APR_BRIGADE_INSERT_TAIL(b, e);
259         }
260         break;
261     case APR_DBD_TYPE_NULL:
262         *(void**)data = NULL;
263         break;
264     default:
265         return APR_EGENERAL;
266     }
267
268     return APR_SUCCESS;
269 }
270
271 static const char *dbd_sqlite_error(apr_dbd_t * sql, int n)
272 {
273     return sql->errmsg;
274 }
275
276 static int dbd_sqlite_query(apr_dbd_t * sql, int *nrows, const char *query)
277 {
278     char **result;
279     int ret;
280     int tuples = 0;
281     int fields = 0;
282
283     if (sql->trans && sql->trans->errnum) {
284         return sql->trans->errnum;
285     }
286
287     FREE_ERROR_MSG(sql);
288
289     ret =
290         sqlite_get_table(sql->conn, query, &result, &tuples, &fields,
291                          &sql->errmsg);
292     if (ret == SQLITE_OK) {
293         *nrows = sqlite_changes(sql->conn);
294
295         if (tuples > 0)
296             free(result);
297
298         ret = 0;
299     }
300
301     if (TXN_NOTICE_ERRORS(sql->trans)) {
302         sql->trans->errnum = ret;
303     }
304
305     return ret;
306 }
307
308 static apr_status_t free_mem(void *data)
309 {
310     sqlite_freemem(data);
311     return APR_SUCCESS;
312 }
313
314 static const char *dbd_sqlite_escape(apr_pool_t * pool, const char *arg,
315                                      apr_dbd_t * sql)
316 {
317     char *ret = sqlite_mprintf("%q", arg);
318     apr_pool_cleanup_register(pool, ret, free_mem, apr_pool_cleanup_null);
319     return ret;
320 }
321
322 static int dbd_sqlite_prepare(apr_pool_t * pool, apr_dbd_t * sql,
323                               const char *query, const char *label,
324                               int nargs, int nvals, apr_dbd_type_e *types,
325                               apr_dbd_prepared_t ** statement)
326 {
327     return APR_ENOTIMPL;
328 }
329
330 static int dbd_sqlite_pquery(apr_pool_t * pool, apr_dbd_t * sql,
331                              int *nrows, apr_dbd_prepared_t * statement,
332                              const char **values)
333 {
334     return APR_ENOTIMPL;
335 }
336
337 static int dbd_sqlite_pvquery(apr_pool_t * pool, apr_dbd_t * sql,
338                               int *nrows, apr_dbd_prepared_t * statement,
339                               va_list args)
340 {
341     return APR_ENOTIMPL;
342 }
343
344 static int dbd_sqlite_pselect(apr_pool_t * pool, apr_dbd_t * sql,
345                               apr_dbd_results_t ** results,
346                               apr_dbd_prepared_t * statement,
347                               int seek, const char **values)
348 {
349     return APR_ENOTIMPL;
350 }
351
352 static int dbd_sqlite_pvselect(apr_pool_t * pool, apr_dbd_t * sql,
353                                apr_dbd_results_t ** results,
354                                apr_dbd_prepared_t * statement, int seek,
355                                va_list args)
356 {
357     return APR_ENOTIMPL;
358 }
359
360 static int dbd_sqlite_pbquery(apr_pool_t * pool, apr_dbd_t * sql,
361                               int *nrows, apr_dbd_prepared_t * statement,
362                               const void **values)
363 {
364     return APR_ENOTIMPL;
365 }
366
367 static int dbd_sqlite_pvbquery(apr_pool_t * pool, apr_dbd_t * sql,
368                                int *nrows, apr_dbd_prepared_t * statement,
369                                va_list args)
370 {
371     return APR_ENOTIMPL;
372 }
373
374 static int dbd_sqlite_pbselect(apr_pool_t * pool, apr_dbd_t * sql,
375                                apr_dbd_results_t ** results,
376                                apr_dbd_prepared_t * statement,
377                                int seek, const void **values)
378 {
379     return APR_ENOTIMPL;
380 }
381
382 static int dbd_sqlite_pvbselect(apr_pool_t * pool, apr_dbd_t * sql,
383                                 apr_dbd_results_t ** results,
384                                 apr_dbd_prepared_t * statement, int seek,
385                                 va_list args)
386 {
387     return APR_ENOTIMPL;
388 }
389
390 static int dbd_sqlite_start_transaction(apr_pool_t * pool, apr_dbd_t * handle,
391                                         apr_dbd_transaction_t ** trans)
392 {
393     int ret, rows;
394
395     ret = dbd_sqlite_query(handle, &rows, "BEGIN TRANSACTION");
396     if (ret == 0) {
397         if (!*trans) {
398             *trans = apr_pcalloc(pool, sizeof(apr_dbd_transaction_t));
399         }
400         (*trans)->handle = handle;
401         handle->trans = *trans;
402     }
403     else {
404         ret = -1;
405     }
406     return ret;
407 }
408
409 static int dbd_sqlite_end_transaction(apr_dbd_transaction_t * trans)
410 {
411     int rows;
412     int ret = -1;               /* no transaction is an error cond */
413
414     if (trans) {
415         /* rollback on error or explicit rollback request */
416         if (trans->errnum || TXN_DO_ROLLBACK(trans)) {
417             trans->errnum = 0;
418             ret =
419                 dbd_sqlite_query(trans->handle, &rows,
420                                  "ROLLBACK TRANSACTION");
421         }
422         else {
423             ret =
424                 dbd_sqlite_query(trans->handle, &rows, "COMMIT TRANSACTION");
425         }
426         trans->handle->trans = NULL;
427     }
428
429     return ret;
430 }
431
432 static int dbd_sqlite_transaction_mode_get(apr_dbd_transaction_t *trans)
433 {
434     if (!trans)
435         return APR_DBD_TRANSACTION_COMMIT;
436
437     return trans->mode;
438 }
439
440 static int dbd_sqlite_transaction_mode_set(apr_dbd_transaction_t *trans,
441                                            int mode)
442 {
443     if (!trans)
444         return APR_DBD_TRANSACTION_COMMIT;
445
446     return trans->mode = (mode & TXN_MODE_BITS);
447 }
448
449 static apr_status_t error_free(void *data)
450 {
451     free(data);
452     return APR_SUCCESS;
453 }
454
455 static apr_dbd_t *dbd_sqlite_open(apr_pool_t * pool, const char *params_,
456                                   const char **error)
457 {
458     apr_dbd_t *sql;
459     sqlite *conn = NULL;
460     char *perm;
461     int iperms = 600;
462     char* params = apr_pstrdup(pool, params_);
463     /* params = "[filename]:[permissions]"
464      *    example: "shopping.db:600"
465      */
466
467     perm = strstr(params, ":");
468     if (perm) {
469         *(perm++) = '\x00';     /* split the filename and permissions */
470
471         if (strlen(perm) > 0)
472             iperms = atoi(perm);
473     }
474
475     if (error) {
476         *error = NULL;
477
478         conn = sqlite_open(params, iperms, (char **)error);
479
480         if (*error) {
481             apr_pool_cleanup_register(pool, *error, error_free,
482                                       apr_pool_cleanup_null);
483         }
484     }
485     else {
486         conn = sqlite_open(params, iperms, NULL);
487     }
488
489     sql = apr_pcalloc(pool, sizeof(*sql));
490     sql->conn = conn;
491
492     return sql;
493 }
494
495 static apr_status_t dbd_sqlite_close(apr_dbd_t * handle)
496 {
497     if (handle->conn) {
498         sqlite_close(handle->conn);
499         handle->conn = NULL;
500     }
501     return APR_SUCCESS;
502 }
503
504 static apr_status_t dbd_sqlite_check_conn(apr_pool_t * pool,
505                                           apr_dbd_t * handle)
506 {
507     if (handle->conn == NULL)
508         return -1;
509     return APR_SUCCESS;
510 }
511
512 static int dbd_sqlite_select_db(apr_pool_t * pool, apr_dbd_t * handle,
513                                 const char *name)
514 {
515     return APR_ENOTIMPL;
516 }
517
518 static void *dbd_sqlite_native(apr_dbd_t * handle)
519 {
520     return handle->conn;
521 }
522
523 static int dbd_sqlite_num_cols(apr_dbd_results_t * res)
524 {
525     return res->sz;
526 }
527
528 static int dbd_sqlite_num_tuples(apr_dbd_results_t * res)
529 {
530     return res->ntuples;
531 }
532
533 APU_MODULE_DECLARE_DATA const apr_dbd_driver_t apr_dbd_sqlite2_driver = {
534     "sqlite2",
535     NULL,
536     dbd_sqlite_native,
537     dbd_sqlite_open,
538     dbd_sqlite_check_conn,
539     dbd_sqlite_close,
540     dbd_sqlite_select_db,
541     dbd_sqlite_start_transaction,
542     dbd_sqlite_end_transaction,
543     dbd_sqlite_query,
544     dbd_sqlite_select,
545     dbd_sqlite_num_cols,
546     dbd_sqlite_num_tuples,
547     dbd_sqlite_get_row,
548     dbd_sqlite_get_entry,
549     dbd_sqlite_error,
550     dbd_sqlite_escape,
551     dbd_sqlite_prepare,
552     dbd_sqlite_pvquery,
553     dbd_sqlite_pvselect,
554     dbd_sqlite_pquery,
555     dbd_sqlite_pselect,
556     dbd_sqlite_get_name,
557     dbd_sqlite_transaction_mode_get,
558     dbd_sqlite_transaction_mode_set,
559     NULL,
560     dbd_sqlite_pvbquery,
561     dbd_sqlite_pvbselect,
562     dbd_sqlite_pbquery,
563     dbd_sqlite_pbselect,
564     dbd_sqlite_datum_get
565 };
566 #endif