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 32struct apr_dbd_transaction_t { 33 int mode; 34 int errnum; 35 apr_dbd_t *handle; 36}; 37 38struct apr_dbd_t { 39 sqlite *conn; 40 char *errmsg; 41 apr_dbd_transaction_t *trans; 42}; 43 44struct 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 54struct apr_dbd_row_t { 55 int n; 56 char **data; 57 apr_dbd_results_t *res; 58}; 59 60struct 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 73static apr_status_t free_table(void *data) 74{ 75 sqlite_free_table(data); 76 return APR_SUCCESS; 77} 78 79static 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 123static 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 132static 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 184static 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 193static 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 271static const char *dbd_sqlite_error(apr_dbd_t * sql, int n) 272{ 273 return sql->errmsg; 274} 275 276static 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 308static apr_status_t free_mem(void *data) 309{ 310 sqlite_freemem(data); 311 return APR_SUCCESS; 312} 313 314static 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 322static 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 330static 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 337static 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 344static 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 352static 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 360static 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 367static 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 374static 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 382static 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 390static 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 409static 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 432static 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 440static 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 449static apr_status_t error_free(void *data) 450{ 451 free(data); 452 return APR_SUCCESS; 453} 454 455static 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 495static 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 504static 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 512static int dbd_sqlite_select_db(apr_pool_t * pool, apr_dbd_t * handle, 513 const char *name) 514{ 515 return APR_ENOTIMPL; 516} 517 518static void *dbd_sqlite_native(apr_dbd_t * handle) 519{ 520 return handle->conn; 521} 522 523static int dbd_sqlite_num_cols(apr_dbd_results_t * res) 524{ 525 return res->sz; 526} 527 528static int dbd_sqlite_num_tuples(apr_dbd_results_t * res) 529{ 530 return res->ntuples; 531} 532 533APU_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 567