1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
#include <sqlite3.h>
#include <stdio.h>
#include <stdlib.h>
#include "hdbc-sqlite3-helper.h"
int sqlite3_bind_text2(sqlite3_stmt* a, int b, const char *c, int d) {
return sqlite3_bind_text(a, b, c, d, SQLITE_TRANSIENT);
}
/* Sqlite things can't finalize more than once.
We'd like to let people call them from the app to get the error, if any.
Yet we'd also like to be able to have a ForeignPtr finalize them.
So, here's a little wrapper for things. */
int sqlite3_open2(const char *filename, finalizeonce **ppo) {
sqlite3 *ppDb;
finalizeonce *newobj;
int res;
res = sqlite3_open(filename, &ppDb);
newobj = malloc(sizeof(finalizeonce));
if (newobj == NULL) {
fprintf(stderr, "\nhdbc sqlite internal error: couldn't malloc memory for newobj\n");
return -999;
}
newobj->encapobj = (void *) ppDb;
newobj->isfinalized = 0;
newobj->refcount = 1;
newobj->parent = NULL;
*ppo = newobj;
#ifdef DEBUG_HDBC_SQLITE3
fprintf(stderr, "\nAllocated db at %p %p\n", newobj, newobj->encapobj);
#endif
return res;
}
int sqlite3_close_app(finalizeonce *ppdb) {
int res;
if (ppdb->isfinalized) {
#ifdef DEBUG_HDBC_SQLITE3
fprintf(stderr, "\nclose_app on already finalized %p\n", ppdb);
#endif
return SQLITE_OK;
}
#ifdef DEBUG_HDBC_SQLITE3
fprintf(stderr, "\nclose_app on non-finalized %p\n", ppdb);
#endif
res = sqlite3_close((sqlite3 *) (ppdb->encapobj));
ppdb->isfinalized = 1;
return res;
}
void sqlite3_close_finalizer(finalizeonce *ppdb) {
#ifdef DEBUG_HDBC_SQLITE3
fprintf(stderr, "\nclose_finalizer on %p: %d\n", ppdb, ppdb->isfinalized);
#endif
(ppdb->refcount)--;
sqlite3_conditional_finalizer(ppdb);
}
void sqlite3_conditional_finalizer(finalizeonce *ppdb) {
#ifdef DEBUG_HDBC_SQLITE3
fprintf(stderr, "\ncond finalizer on %p: refcount %d\n", ppdb, ppdb->refcount);
#endif
if (ppdb->refcount < 1) {
sqlite3_close_app(ppdb);
free(ppdb);
}
}
void sqlite3_busy_timeout2(finalizeonce *ppdb, int ms) {
sqlite3 *db;
db = (sqlite3 *) ppdb->encapobj;
sqlite3_busy_timeout(db, ms);
}
int sqlite3_prepare2(finalizeonce *fdb, const char *zSql,
int nBytes, finalizeonce **ppo,
const char **pzTail) {
sqlite3_stmt *ppst;
sqlite3 *db;
finalizeonce *newobj;
int res;
db = (sqlite3 *) fdb->encapobj;
#ifdef DEBUG_HDBC_SQLITE3
fprintf(stderr, "\nCalling prepare on %p", db);
#endif
#if SQLITE_VERSION_NUMBER > 3003011
res = sqlite3_prepare_v2(db, zSql, nBytes, &ppst,
pzTail);
#else
res = sqlite3_prepare(db, zSql, nBytes, &ppst,
pzTail);
#endif
/* We don't try to deallocate this in Haskell if there
was an error. */
if (res != SQLITE_OK) {
if (ppst != NULL) {
sqlite3_finalize(ppst);
}
return res;
}
newobj = malloc(sizeof(finalizeonce));
if (newobj == NULL) {
fprintf(stderr, "\nhdbc sqlite3 internal error: couldn't malloc memory for newobj\n");
return -999;
}
newobj->encapobj = (void *) ppst;
newobj->isfinalized = 0;
newobj->parent = fdb;
newobj->refcount = 1;
(fdb->refcount)++;
*ppo = newobj;
#ifdef DEBUG_HDBC_SQLITE3
fprintf(stderr, "\nAllocated stmt at %p %p\n", newobj, newobj->encapobj);
#endif
return res;
}
int sqlite3_finalize_app(finalizeonce *ppst) {
int res;
if (ppst->isfinalized) {
#ifdef DEBUG_HDBC_SQLITE3
fprintf(stderr, "\nfinalize_app on already finalized %p\n", ppst);
#endif
return SQLITE_OK;
}
#ifdef DEBUG_HDBC_SQLITE3
fprintf(stderr, "\nfinalize_app on non-finalized %p\n", ppst);
#endif
res = sqlite3_finalize((sqlite3_stmt *) (ppst->encapobj));
ppst->isfinalized = 1;
return res;
}
void sqlite3_finalize_finalizer(finalizeonce *ppst) {
#ifdef DEBUG_HDBC_SQLITE3
fprintf(stderr, "\nfinalize_finalizer on %p: %d\n", ppst, ppst->isfinalized);
#endif
sqlite3_finalize_app(ppst);
(ppst->refcount)--; /* Not really important since no children use
us */
/* Now decrement the refcount for the parent */
(ppst->parent->refcount)--;
sqlite3_conditional_finalizer(ppst->parent);
free(ppst);
}
|