2
0

apr_dbd_sqlite3.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  1. /* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
  2. * applicable.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * 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. #include "apu.h"
  17. #if APU_HAVE_SQLITE3
  18. #include <ctype.h>
  19. #include <stdlib.h>
  20. #include <sqlite3.h>
  21. #include "apr_strings.h"
  22. #include "apr_time.h"
  23. #include "apr_dbd_internal.h"
  24. #define MAX_RETRY_COUNT 15
  25. #define MAX_RETRY_SLEEP 100000
  26. struct apr_dbd_transaction_t {
  27. int errnum;
  28. apr_dbd_t *handle;
  29. };
  30. struct apr_dbd_t {
  31. sqlite3 *conn;
  32. apr_dbd_transaction_t *trans;
  33. #if APR_HAS_THREADS
  34. apr_thread_mutex_t *mutex;
  35. #endif
  36. apr_pool_t *pool;
  37. apr_dbd_prepared_t *prep;
  38. };
  39. typedef struct {
  40. char *name;
  41. char *value;
  42. int size;
  43. int type;
  44. } apr_dbd_column_t;
  45. struct apr_dbd_row_t {
  46. apr_dbd_results_t *res;
  47. apr_dbd_column_t **columns;
  48. apr_dbd_row_t *next_row;
  49. int columnCount;
  50. int rownum;
  51. };
  52. struct apr_dbd_results_t {
  53. int random;
  54. sqlite3 *handle;
  55. sqlite3_stmt *stmt;
  56. apr_dbd_row_t *next_row;
  57. size_t sz;
  58. int tuples;
  59. char **col_names;
  60. };
  61. struct apr_dbd_prepared_t {
  62. sqlite3_stmt *stmt;
  63. apr_dbd_prepared_t *next;
  64. };
  65. #define dbd_sqlite3_is_success(x) (((x) == SQLITE_DONE ) \
  66. || ((x) == SQLITE_OK ))
  67. static int dbd_sqlite3_select(apr_pool_t * pool, apr_dbd_t * sql, apr_dbd_results_t ** results, const char *query, int seek)
  68. {
  69. sqlite3_stmt *stmt = NULL;
  70. const char *tail = NULL;
  71. int i, ret, retry_count = 0;
  72. size_t num_tuples = 0;
  73. int increment = 0;
  74. apr_dbd_row_t *row = NULL;
  75. apr_dbd_row_t *lastrow = NULL;
  76. apr_dbd_column_t *column;
  77. char *hold = NULL;
  78. if (sql->trans && sql->trans->errnum) {
  79. return sql->trans->errnum;
  80. }
  81. #if APR_HAS_THREADS
  82. apr_thread_mutex_lock(sql->mutex);
  83. #endif
  84. ret = sqlite3_prepare(sql->conn, query, strlen(query), &stmt, &tail);
  85. if (!dbd_sqlite3_is_success(ret)) {
  86. #if APR_HAS_THREADS
  87. apr_thread_mutex_unlock(sql->mutex);
  88. #endif
  89. return ret;
  90. } else {
  91. int column_count;
  92. column_count = sqlite3_column_count(stmt);
  93. if (!*results) {
  94. *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
  95. }
  96. (*results)->stmt = stmt;
  97. (*results)->sz = column_count;
  98. (*results)->random = seek;
  99. (*results)->next_row = 0;
  100. (*results)->tuples = 0;
  101. (*results)->col_names = apr_pcalloc(pool,
  102. column_count * sizeof(char *));
  103. do {
  104. ret = sqlite3_step(stmt);
  105. if (ret == SQLITE_BUSY) {
  106. if (retry_count++ > MAX_RETRY_COUNT) {
  107. ret = SQLITE_ERROR;
  108. } else {
  109. #if APR_HAS_THREADS
  110. apr_thread_mutex_unlock(sql->mutex);
  111. #endif
  112. apr_sleep(MAX_RETRY_SLEEP);
  113. #if APR_HAS_THREADS
  114. apr_thread_mutex_lock(sql->mutex);
  115. #endif
  116. }
  117. } else if (ret == SQLITE_ROW) {
  118. int length;
  119. apr_dbd_column_t *col;
  120. row = apr_palloc(pool, sizeof(apr_dbd_row_t));
  121. row->res = *results;
  122. increment = sizeof(apr_dbd_column_t *);
  123. length = increment * (*results)->sz;
  124. row->columns = apr_palloc(pool, length);
  125. row->columnCount = column_count;
  126. for (i = 0; i < (*results)->sz; i++) {
  127. column = apr_palloc(pool, sizeof(apr_dbd_column_t));
  128. row->columns[i] = column;
  129. /* copy column name once only */
  130. if ((*results)->col_names[i] == NULL) {
  131. (*results)->col_names[i] =
  132. apr_pstrdup(pool, sqlite3_column_name(stmt, i));
  133. }
  134. column->name = (*results)->col_names[i];
  135. column->size = sqlite3_column_bytes(stmt, i);
  136. column->type = sqlite3_column_type(stmt, i);
  137. column->value = NULL;
  138. switch (column->type) {
  139. case SQLITE_FLOAT:
  140. case SQLITE_INTEGER:
  141. case SQLITE_TEXT:
  142. hold = NULL;
  143. hold = (char *) sqlite3_column_text(stmt, i);
  144. if (hold) {
  145. column->value = apr_palloc(pool, column->size + 1);
  146. strncpy(column->value, hold, column->size + 1);
  147. }
  148. break;
  149. case SQLITE_BLOB:
  150. break;
  151. case SQLITE_NULL:
  152. break;
  153. }
  154. col = row->columns[i];
  155. }
  156. row->rownum = num_tuples++;
  157. row->next_row = 0;
  158. (*results)->tuples = num_tuples;
  159. if ((*results)->next_row == 0) {
  160. (*results)->next_row = row;
  161. }
  162. if (lastrow != 0) {
  163. lastrow->next_row = row;
  164. }
  165. lastrow = row;
  166. } else if (ret == SQLITE_DONE) {
  167. ret = SQLITE_OK;
  168. }
  169. } while (ret == SQLITE_ROW || ret == SQLITE_BUSY);
  170. }
  171. ret = sqlite3_finalize(stmt);
  172. #if APR_HAS_THREADS
  173. apr_thread_mutex_unlock(sql->mutex);
  174. #endif
  175. if (sql->trans) {
  176. sql->trans->errnum = ret;
  177. }
  178. return ret;
  179. }
  180. static int dbd_sqlite3_get_row(apr_pool_t *pool, apr_dbd_results_t *res,
  181. apr_dbd_row_t **rowp, int rownum)
  182. {
  183. int i = 0;
  184. if (rownum == -1) {
  185. *rowp = res->next_row;
  186. if (*rowp == 0)
  187. return -1;
  188. res->next_row = (*rowp)->next_row;
  189. return 0;
  190. }
  191. if (rownum > res->tuples) {
  192. return -1;
  193. }
  194. rownum--;
  195. *rowp = res->next_row;
  196. for (; *rowp != 0; i++, *rowp = (*rowp)->next_row) {
  197. if (i == rownum) {
  198. return 0;
  199. }
  200. }
  201. return -1;
  202. }
  203. static const char *dbd_sqlite3_get_entry(const apr_dbd_row_t *row, int n)
  204. {
  205. apr_dbd_column_t *column;
  206. const char *value;
  207. if ((n < 0) || (n >= row->columnCount)) {
  208. return NULL;
  209. }
  210. column = row->columns[n];
  211. value = column->value;
  212. return value;
  213. }
  214. static const char *dbd_sqlite3_error(apr_dbd_t *sql, int n)
  215. {
  216. return sqlite3_errmsg(sql->conn);
  217. }
  218. static int dbd_sqlite3_query(apr_dbd_t *sql, int *nrows, const char *query)
  219. {
  220. sqlite3_stmt *stmt = NULL;
  221. const char *tail = NULL;
  222. int ret = -1, length = 0;
  223. if (sql->trans && sql->trans->errnum) {
  224. return sql->trans->errnum;
  225. }
  226. length = strlen(query);
  227. #if APR_HAS_THREADS
  228. apr_thread_mutex_lock(sql->mutex);
  229. #endif
  230. do {
  231. int retry_count = 0;
  232. ret = sqlite3_prepare(sql->conn, query, length, &stmt, &tail);
  233. if (ret != SQLITE_OK) {
  234. sqlite3_finalize(stmt);
  235. break;
  236. }
  237. while(retry_count++ <= MAX_RETRY_COUNT) {
  238. ret = sqlite3_step(stmt);
  239. if (ret != SQLITE_BUSY)
  240. break;
  241. #if APR_HAS_THREADS
  242. apr_thread_mutex_unlock(sql->mutex);
  243. #endif
  244. apr_sleep(MAX_RETRY_SLEEP);
  245. #if APR_HAS_THREADS
  246. apr_thread_mutex_lock(sql->mutex);
  247. #endif
  248. }
  249. *nrows = sqlite3_changes(sql->conn);
  250. sqlite3_finalize(stmt);
  251. length -= (tail - query);
  252. query = tail;
  253. } while (length > 0);
  254. if (dbd_sqlite3_is_success(ret)) {
  255. ret = 0;
  256. }
  257. #if APR_HAS_THREADS
  258. apr_thread_mutex_unlock(sql->mutex);
  259. #endif
  260. if (sql->trans) {
  261. sql->trans->errnum = ret;
  262. }
  263. return ret;
  264. }
  265. static apr_status_t free_mem(void *data)
  266. {
  267. sqlite3_free(data);
  268. return APR_SUCCESS;
  269. }
  270. static const char *dbd_sqlite3_escape(apr_pool_t *pool, const char *arg,
  271. apr_dbd_t *sql)
  272. {
  273. char *ret = sqlite3_mprintf("%q", arg);
  274. apr_pool_cleanup_register(pool, ret, free_mem,
  275. apr_pool_cleanup_null);
  276. return ret;
  277. }
  278. static int dbd_sqlite3_prepare(apr_pool_t *pool, apr_dbd_t *sql,
  279. const char *query, const char *label,
  280. apr_dbd_prepared_t **statement)
  281. {
  282. sqlite3_stmt *stmt;
  283. char *p, *slquery = apr_pstrdup(pool, query);
  284. const char *tail = NULL, *q;
  285. int ret;
  286. for (p = slquery, q = query; *q; ++q) {
  287. if (q[0] == '%') {
  288. if (isalpha(q[1])) {
  289. *p++ = '?';
  290. ++q;
  291. }
  292. else if (q[1] == '%') {
  293. /* reduce %% to % */
  294. *p++ = *q++;
  295. }
  296. else {
  297. *p++ = *q;
  298. }
  299. }
  300. else {
  301. *p++ = *q;
  302. }
  303. }
  304. *p = 0;
  305. #if APR_HAS_THREADS
  306. apr_thread_mutex_lock(sql->mutex);
  307. #endif
  308. ret = sqlite3_prepare(sql->conn, slquery, strlen(query), &stmt, &tail);
  309. if (ret == SQLITE_OK) {
  310. apr_dbd_prepared_t *prep;
  311. prep = apr_pcalloc(sql->pool, sizeof(*prep));
  312. prep->stmt = stmt;
  313. prep->next = sql->prep;
  314. /* link new statement to the handle */
  315. sql->prep = prep;
  316. *statement = prep;
  317. } else {
  318. sqlite3_finalize(stmt);
  319. }
  320. #if APR_HAS_THREADS
  321. apr_thread_mutex_unlock(sql->mutex);
  322. #endif
  323. return ret;
  324. }
  325. static int dbd_sqlite3_pquery(apr_pool_t *pool, apr_dbd_t *sql,
  326. int *nrows, apr_dbd_prepared_t *statement,
  327. int nargs, const char **values)
  328. {
  329. sqlite3_stmt *stmt = statement->stmt;
  330. int ret = -1, retry_count = 0, i;
  331. if (sql->trans && sql->trans->errnum) {
  332. return sql->trans->errnum;
  333. }
  334. #if APR_HAS_THREADS
  335. apr_thread_mutex_lock(sql->mutex);
  336. #endif
  337. ret = sqlite3_reset(stmt);
  338. if (ret == SQLITE_OK) {
  339. for (i=0; i < nargs; i++) {
  340. sqlite3_bind_text(stmt, i + 1, values[i], strlen(values[i]),
  341. SQLITE_STATIC);
  342. }
  343. while(retry_count++ <= MAX_RETRY_COUNT) {
  344. ret = sqlite3_step(stmt);
  345. if (ret != SQLITE_BUSY)
  346. break;
  347. #if APR_HAS_THREADS
  348. apr_thread_mutex_unlock(sql->mutex);
  349. #endif
  350. apr_sleep(MAX_RETRY_SLEEP);
  351. #if APR_HAS_THREADS
  352. apr_thread_mutex_lock(sql->mutex);
  353. #endif
  354. }
  355. *nrows = sqlite3_changes(sql->conn);
  356. sqlite3_reset(stmt);
  357. }
  358. if (dbd_sqlite3_is_success(ret)) {
  359. ret = 0;
  360. }
  361. #if APR_HAS_THREADS
  362. apr_thread_mutex_unlock(sql->mutex);
  363. #endif
  364. if (sql->trans) {
  365. sql->trans->errnum = ret;
  366. }
  367. return ret;
  368. }
  369. static int dbd_sqlite3_pvquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows,
  370. apr_dbd_prepared_t *statement, va_list args)
  371. {
  372. const char **values;
  373. int i, nargs;
  374. if (sql->trans && sql->trans->errnum) {
  375. return sql->trans->errnum;
  376. }
  377. nargs = sqlite3_bind_parameter_count(statement->stmt);
  378. values = apr_palloc(pool, sizeof(*values) * nargs);
  379. for (i = 0; i < nargs; i++) {
  380. values[i] = apr_pstrdup(pool, va_arg(args, const char*));
  381. }
  382. return dbd_sqlite3_pquery(pool, sql, nrows, statement, nargs, values);
  383. }
  384. static int dbd_sqlite3_pselect(apr_pool_t *pool, apr_dbd_t *sql,
  385. apr_dbd_results_t **results,
  386. apr_dbd_prepared_t *statement, int seek,
  387. int nargs, const char **values)
  388. {
  389. sqlite3_stmt *stmt = statement->stmt;
  390. int i, ret, retry_count = 0;
  391. size_t num_tuples = 0;
  392. int increment = 0;
  393. apr_dbd_row_t *row = NULL;
  394. apr_dbd_row_t *lastrow = NULL;
  395. apr_dbd_column_t *column;
  396. char *hold = NULL;
  397. if (sql->trans && sql->trans->errnum) {
  398. return sql->trans->errnum;
  399. }
  400. #if APR_HAS_THREADS
  401. apr_thread_mutex_lock(sql->mutex);
  402. #endif
  403. ret = sqlite3_reset(stmt);
  404. if (ret == SQLITE_OK) {
  405. int column_count;
  406. for (i=0; i < nargs; i++) {
  407. sqlite3_bind_text(stmt, i + 1, values[i], strlen(values[i]),
  408. SQLITE_STATIC);
  409. }
  410. column_count = sqlite3_column_count(stmt);
  411. if (!*results) {
  412. *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
  413. }
  414. (*results)->stmt = stmt;
  415. (*results)->sz = column_count;
  416. (*results)->random = seek;
  417. (*results)->next_row = 0;
  418. (*results)->tuples = 0;
  419. (*results)->col_names = apr_pcalloc(pool,
  420. column_count * sizeof(char *));
  421. do {
  422. ret = sqlite3_step(stmt);
  423. if (ret == SQLITE_BUSY) {
  424. if (retry_count++ > MAX_RETRY_COUNT) {
  425. ret = SQLITE_ERROR;
  426. } else {
  427. #if APR_HAS_THREADS
  428. apr_thread_mutex_unlock(sql->mutex);
  429. #endif
  430. apr_sleep(MAX_RETRY_SLEEP);
  431. #if APR_HAS_THREADS
  432. apr_thread_mutex_lock(sql->mutex);
  433. #endif
  434. }
  435. } else if (ret == SQLITE_ROW) {
  436. int length;
  437. apr_dbd_column_t *col;
  438. row = apr_palloc(pool, sizeof(apr_dbd_row_t));
  439. row->res = *results;
  440. increment = sizeof(apr_dbd_column_t *);
  441. length = increment * (*results)->sz;
  442. row->columns = apr_palloc(pool, length);
  443. row->columnCount = column_count;
  444. for (i = 0; i < (*results)->sz; i++) {
  445. column = apr_palloc(pool, sizeof(apr_dbd_column_t));
  446. row->columns[i] = column;
  447. /* copy column name once only */
  448. if ((*results)->col_names[i] == NULL) {
  449. (*results)->col_names[i] =
  450. apr_pstrdup(pool, sqlite3_column_name(stmt, i));
  451. }
  452. column->name = (*results)->col_names[i];
  453. column->size = sqlite3_column_bytes(stmt, i);
  454. column->type = sqlite3_column_type(stmt, i);
  455. column->value = NULL;
  456. switch (column->type) {
  457. case SQLITE_FLOAT:
  458. case SQLITE_INTEGER:
  459. case SQLITE_TEXT:
  460. hold = NULL;
  461. hold = (char *) sqlite3_column_text(stmt, i);
  462. if (hold) {
  463. column->value = apr_palloc(pool, column->size + 1);
  464. strncpy(column->value, hold, column->size + 1);
  465. }
  466. break;
  467. case SQLITE_BLOB:
  468. break;
  469. case SQLITE_NULL:
  470. break;
  471. }
  472. col = row->columns[i];
  473. }
  474. row->rownum = num_tuples++;
  475. row->next_row = 0;
  476. (*results)->tuples = num_tuples;
  477. if ((*results)->next_row == 0) {
  478. (*results)->next_row = row;
  479. }
  480. if (lastrow != 0) {
  481. lastrow->next_row = row;
  482. }
  483. lastrow = row;
  484. } else if (ret == SQLITE_DONE) {
  485. ret = SQLITE_OK;
  486. }
  487. } while (ret == SQLITE_ROW || ret == SQLITE_BUSY);
  488. sqlite3_reset(stmt);
  489. }
  490. #if APR_HAS_THREADS
  491. apr_thread_mutex_unlock(sql->mutex);
  492. #endif
  493. if (sql->trans) {
  494. sql->trans->errnum = ret;
  495. }
  496. return ret;
  497. }
  498. static int dbd_sqlite3_pvselect(apr_pool_t *pool, apr_dbd_t *sql,
  499. apr_dbd_results_t **results,
  500. apr_dbd_prepared_t *statement, int seek,
  501. va_list args)
  502. {
  503. const char **values;
  504. int i, nargs;
  505. if (sql->trans && sql->trans->errnum) {
  506. return sql->trans->errnum;
  507. }
  508. nargs = sqlite3_bind_parameter_count(statement->stmt);
  509. values = apr_palloc(pool, sizeof(*values) * nargs);
  510. for (i = 0; i < nargs; i++) {
  511. values[i] = apr_pstrdup(pool, va_arg(args, const char*));
  512. }
  513. return dbd_sqlite3_pselect(pool, sql, results, statement,
  514. seek, nargs, values);
  515. }
  516. static int dbd_sqlite3_start_transaction(apr_pool_t *pool,
  517. apr_dbd_t *handle,
  518. apr_dbd_transaction_t **trans)
  519. {
  520. int ret = 0;
  521. int nrows = 0;
  522. ret = dbd_sqlite3_query(handle, &nrows, "BEGIN");
  523. if (!*trans) {
  524. *trans = apr_pcalloc(pool, sizeof(apr_dbd_transaction_t));
  525. (*trans)->handle = handle;
  526. handle->trans = *trans;
  527. }
  528. return ret;
  529. }
  530. static int dbd_sqlite3_end_transaction(apr_dbd_transaction_t *trans)
  531. {
  532. int ret = -1; /* ending transaction that was never started is an error */
  533. int nrows = 0;
  534. if (trans) {
  535. if (trans->errnum) {
  536. trans->errnum = 0;
  537. ret = dbd_sqlite3_query(trans->handle, &nrows, "ROLLBACK");
  538. } else {
  539. ret = dbd_sqlite3_query(trans->handle, &nrows, "COMMIT");
  540. }
  541. trans->handle->trans = NULL;
  542. }
  543. return ret;
  544. }
  545. static apr_dbd_t *dbd_sqlite3_open(apr_pool_t *pool, const char *params)
  546. {
  547. apr_dbd_t *sql = NULL;
  548. sqlite3 *conn = NULL;
  549. apr_status_t res;
  550. int sqlres;
  551. if (!params)
  552. return NULL;
  553. sqlres = sqlite3_open(params, &conn);
  554. if (sqlres != SQLITE_OK) {
  555. sqlite3_close(conn);
  556. return NULL;
  557. }
  558. /* should we register rand or power functions to the sqlite VM? */
  559. sql = apr_pcalloc(pool, sizeof(*sql));
  560. sql->conn = conn;
  561. sql->pool = pool;
  562. sql->trans = NULL;
  563. #if APR_HAS_THREADS
  564. /* Create a mutex */
  565. res = apr_thread_mutex_create(&sql->mutex, APR_THREAD_MUTEX_DEFAULT,
  566. pool);
  567. if (res != APR_SUCCESS) {
  568. return NULL;
  569. }
  570. #endif
  571. return sql;
  572. }
  573. static apr_status_t dbd_sqlite3_close(apr_dbd_t *handle)
  574. {
  575. apr_dbd_prepared_t *prep = handle->prep;
  576. /* finalize all prepared statements, or we'll get SQLITE_BUSY on close */
  577. while (prep) {
  578. sqlite3_finalize(prep->stmt);
  579. prep = prep->next;
  580. }
  581. sqlite3_close(handle->conn);
  582. #if APR_HAS_THREADS
  583. apr_thread_mutex_destroy(handle->mutex);
  584. #endif
  585. return APR_SUCCESS;
  586. }
  587. static apr_status_t dbd_sqlite3_check_conn(apr_pool_t *pool,
  588. apr_dbd_t *handle)
  589. {
  590. return (handle->conn != NULL) ? APR_SUCCESS : APR_EGENERAL;
  591. }
  592. static int dbd_sqlite3_select_db(apr_pool_t *pool, apr_dbd_t *handle,
  593. const char *name)
  594. {
  595. return APR_ENOTIMPL;
  596. }
  597. static void *dbd_sqlite3_native(apr_dbd_t *handle)
  598. {
  599. return handle->conn;
  600. }
  601. static int dbd_sqlite3_num_cols(apr_dbd_results_t *res)
  602. {
  603. return res->sz;
  604. }
  605. static int dbd_sqlite3_num_tuples(apr_dbd_results_t *res)
  606. {
  607. return res->tuples;
  608. }
  609. APU_DECLARE_DATA const apr_dbd_driver_t apr_dbd_sqlite3_driver = {
  610. "sqlite3",
  611. NULL,
  612. dbd_sqlite3_native,
  613. dbd_sqlite3_open,
  614. dbd_sqlite3_check_conn,
  615. dbd_sqlite3_close,
  616. dbd_sqlite3_select_db,
  617. dbd_sqlite3_start_transaction,
  618. dbd_sqlite3_end_transaction,
  619. dbd_sqlite3_query,
  620. dbd_sqlite3_select,
  621. dbd_sqlite3_num_cols,
  622. dbd_sqlite3_num_tuples,
  623. dbd_sqlite3_get_row,
  624. dbd_sqlite3_get_entry,
  625. dbd_sqlite3_error,
  626. dbd_sqlite3_escape,
  627. dbd_sqlite3_prepare,
  628. dbd_sqlite3_pvquery,
  629. dbd_sqlite3_pvselect,
  630. dbd_sqlite3_pquery,
  631. dbd_sqlite3_pselect,
  632. };
  633. #endif