-
Notifications
You must be signed in to change notification settings - Fork 6
/
hdbc-sqlite3-helper.c
156 lines (136 loc) · 4.06 KB
/
hdbc-sqlite3-helper.c
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);
}