@cutils/sqlite 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,321 @@
1
+ /*
2
+ * sqlite_shim.c — FFI shim adapting the SQLite C API to scriptc's fixed-width
3
+ * FFI ABI. One entry point per manifest function; every handle is an opaque
4
+ * pointer, every out string/blob is written into a caller-owned buffer.
5
+ *
6
+ * Span ABI (scriptc ffi_format 7): `string`/`bytes` params arrive as
7
+ * (const uint8_t *data, size_t len) pairs — length-delimited, NOT
8
+ * NUL-terminated — and `mutable-bytes` out params as (uint8_t *buf,
9
+ * size_t len). Callers (declares/koffi adapters) pass no separate length.
10
+ *
11
+ * Buffer-out convention (column name/text/blob/meta, errmsg, expanded_sql):
12
+ * return value >= 0 — required byte count. If it exceeds the caller's
13
+ * buffer length nothing was written; grow and retry.
14
+ * return value -1 — the underlying value is NULL (wrapper maps to null).
15
+ *
16
+ * Step convention: 0 = SQLITE_ROW, 101 = SQLITE_DONE, otherwise the raw
17
+ * sqlite3_step() result code.
18
+ *
19
+ * The amalgamation is built with SQLITE_THREADSAFE=0: no locking anywhere in
20
+ * this file. All state lives in the caller's handles.
21
+ */
22
+
23
+ #include <stdint.h>
24
+ #include <stdlib.h>
25
+ #include <string.h>
26
+ #include <stdio.h>
27
+ #include "../sqlite-amalgamation/sqlite3.h"
28
+
29
+ /* Copy a span into a fresh NUL-terminated heap string (SQLite APIs that take
30
+ * filenames, full SQL text, or parameter names require cstrings). Returns
31
+ * NULL on allocation failure. */
32
+ static char *dup_cstr(const uint8_t *s, size_t n) {
33
+ char *p = (char *)malloc(n + 1);
34
+ if (p == NULL) return NULL;
35
+ if (n > 0) memcpy(p, s, n);
36
+ p[n] = '\0';
37
+ return p;
38
+ }
39
+
40
+ /* ------------------------------------------------------------------ */
41
+ /* open / close / errors */
42
+ /* ------------------------------------------------------------------ */
43
+
44
+ void *shim_open(const uint8_t *path, size_t plen, int32_t flags) {
45
+ sqlite3 *db = NULL;
46
+ char *zpath;
47
+ int rc;
48
+ zpath = dup_cstr(path, plen);
49
+ if (zpath == NULL) return NULL;
50
+ rc = sqlite3_open_v2(zpath, &db, (int)flags, NULL);
51
+ free(zpath);
52
+ if (rc != SQLITE_OK && db == NULL) {
53
+ return NULL; /* SQLITE_NOMEM: no handle to report through */
54
+ }
55
+ /* On error sqlite3_open_v2 still hands back a usable handle for
56
+ * errmsg/errcode; the wrapper checks shim_errcode next and closes. */
57
+ return (void *)db;
58
+ }
59
+
60
+ int32_t shim_close(void *db) {
61
+ if (db == NULL) return SQLITE_OK;
62
+ return (int32_t)sqlite3_close((sqlite3 *)db);
63
+ }
64
+
65
+ int32_t shim_errcode(void *db) {
66
+ /* Extended errcode so SQLITE_CONSTRAINT_* sub-codes (UNIQUE, NOTNULL,
67
+ * FOREIGNKEY, ...) reach SqliteError.code un-mangled. */
68
+ return (int32_t)sqlite3_extended_errcode((sqlite3 *)db);
69
+ }
70
+
71
+ /* Copy a NUL-terminated source into the caller buffer; -1 when NULL. */
72
+ static int32_t copy_cstr(const char *src, uint8_t *buf, size_t len) {
73
+ size_t n;
74
+ if (src == NULL) return -1;
75
+ n = strlen(src);
76
+ if (n > len) return (int32_t)n;
77
+ memcpy(buf, src, n);
78
+ return (int32_t)n;
79
+ }
80
+
81
+ /* Copy `n` raw bytes into the caller buffer; -1 when NULL. */
82
+ static int32_t copy_bytes(const void *src, int32_t n, uint8_t *buf,
83
+ size_t len) {
84
+ if (src == NULL) return -1;
85
+ if (n < 0) n = 0;
86
+ if ((size_t)n > len) return n;
87
+ memcpy(buf, src, (size_t)n);
88
+ return n;
89
+ }
90
+
91
+ int32_t shim_errmsg(void *db, uint8_t *buf, size_t len) {
92
+ return copy_cstr(sqlite3_errmsg((sqlite3 *)db), buf, len);
93
+ }
94
+
95
+ int32_t shim_in_transaction(void *db) {
96
+ return sqlite3_get_autocommit((sqlite3 *)db) == 0 ? 1 : 0;
97
+ }
98
+
99
+ /* ------------------------------------------------------------------ */
100
+ /* exec / transactions / savepoints */
101
+ /* ------------------------------------------------------------------ */
102
+
103
+ int32_t shim_exec(void *db, const uint8_t *sql, size_t slen) {
104
+ char *z = dup_cstr(sql, slen);
105
+ int rc;
106
+ if (z == NULL) return SQLITE_NOMEM;
107
+ rc = sqlite3_exec((sqlite3 *)db, z, NULL, NULL, NULL);
108
+ free(z);
109
+ return (int32_t)rc;
110
+ }
111
+
112
+ int32_t shim_begin(void *db) {
113
+ return (int32_t)sqlite3_exec((sqlite3 *)db, "BEGIN", NULL, NULL, NULL);
114
+ }
115
+
116
+ int32_t shim_commit(void *db) {
117
+ return (int32_t)sqlite3_exec((sqlite3 *)db, "COMMIT", NULL, NULL, NULL);
118
+ }
119
+
120
+ int32_t shim_rollback(void *db) {
121
+ return (int32_t)sqlite3_exec((sqlite3 *)db, "ROLLBACK", NULL, NULL, NULL);
122
+ }
123
+
124
+ /* op: 0 = SAVEPOINT <name>, 1 = RELEASE <name>, 2 = ROLLBACK TO + RELEASE.
125
+ * Names are generated wrapper-side (sp_N) or user-provided; restrict to
126
+ * identifier chars so the name can be spliced into SQL without quoting. */
127
+ static int name_ok(const uint8_t *name, size_t n) {
128
+ size_t i;
129
+ if (n == 0 || n > 64) return 0;
130
+ for (i = 0; i < n; i++) {
131
+ uint8_t c = name[i];
132
+ if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
133
+ (c >= '0' && c <= '9') || c == '_'))
134
+ return 0;
135
+ }
136
+ return 1;
137
+ }
138
+
139
+ int32_t shim_savepoint(void *db, const uint8_t *name, size_t nlen, int32_t op) {
140
+ char sql[96];
141
+ char zname[65];
142
+ int rc;
143
+ if (!name_ok(name, nlen)) return SQLITE_MISUSE;
144
+ memcpy(zname, name, nlen);
145
+ zname[nlen] = '\0';
146
+ if (op == 0) {
147
+ snprintf(sql, sizeof(sql), "SAVEPOINT %s", zname);
148
+ return (int32_t)sqlite3_exec((sqlite3 *)db, sql, NULL, NULL, NULL);
149
+ }
150
+ if (op == 1) {
151
+ snprintf(sql, sizeof(sql), "RELEASE %s", zname);
152
+ return (int32_t)sqlite3_exec((sqlite3 *)db, sql, NULL, NULL, NULL);
153
+ }
154
+ if (op == 2) {
155
+ snprintf(sql, sizeof(sql), "ROLLBACK TO %s", zname);
156
+ rc = sqlite3_exec((sqlite3 *)db, sql, NULL, NULL, NULL);
157
+ if (rc != SQLITE_OK) return (int32_t)rc;
158
+ snprintf(sql, sizeof(sql), "RELEASE %s", zname);
159
+ return (int32_t)sqlite3_exec((sqlite3 *)db, sql, NULL, NULL, NULL);
160
+ }
161
+ return SQLITE_MISUSE;
162
+ }
163
+
164
+ /* ------------------------------------------------------------------ */
165
+ /* statements */
166
+ /* ------------------------------------------------------------------ */
167
+
168
+ void *shim_prepare(void *db, const uint8_t *sql, size_t slen) {
169
+ sqlite3_stmt *stmt = NULL;
170
+ int rc = sqlite3_prepare_v2((sqlite3 *)db, (const char *)sql, (int)slen,
171
+ &stmt, NULL);
172
+ if (rc != SQLITE_OK) {
173
+ if (stmt != NULL) sqlite3_finalize(stmt);
174
+ return NULL;
175
+ }
176
+ return (void *)stmt;
177
+ }
178
+
179
+ int32_t shim_step(void *stmt) {
180
+ int rc = sqlite3_step((sqlite3_stmt *)stmt);
181
+ if (rc == SQLITE_ROW) return 0;
182
+ return (int32_t)rc;
183
+ }
184
+
185
+ int32_t shim_reset(void *stmt) {
186
+ return (int32_t)sqlite3_reset((sqlite3_stmt *)stmt);
187
+ }
188
+
189
+ int32_t shim_finalize(void *stmt) {
190
+ if (stmt == NULL) return SQLITE_OK;
191
+ return (int32_t)sqlite3_finalize((sqlite3_stmt *)stmt);
192
+ }
193
+
194
+ int32_t shim_clear_bindings(void *stmt) {
195
+ return (int32_t)sqlite3_clear_bindings((sqlite3_stmt *)stmt);
196
+ }
197
+
198
+ int32_t shim_stmt_readonly(void *stmt) {
199
+ return sqlite3_stmt_readonly((sqlite3_stmt *)stmt) ? 1 : 0;
200
+ }
201
+
202
+ int32_t shim_expanded_sql(void *stmt, uint8_t *buf, size_t len) {
203
+ char *sql = sqlite3_expanded_sql((sqlite3_stmt *)stmt);
204
+ int32_t n;
205
+ if (sql == NULL) return -1;
206
+ n = copy_cstr(sql, buf, len);
207
+ sqlite3_free(sql);
208
+ return n;
209
+ }
210
+
211
+ /* ------------------------------------------------------------------ */
212
+ /* binding */
213
+ /* ------------------------------------------------------------------ */
214
+
215
+ int32_t shim_bind_count(void *stmt) {
216
+ return (int32_t)sqlite3_bind_parameter_count((sqlite3_stmt *)stmt);
217
+ }
218
+
219
+ int32_t shim_bind_index(void *stmt, const uint8_t *name, size_t nlen) {
220
+ char *z = dup_cstr(name, nlen);
221
+ int idx;
222
+ if (z == NULL) return 0;
223
+ idx = sqlite3_bind_parameter_index((sqlite3_stmt *)stmt, z);
224
+ free(z);
225
+ return (int32_t)idx;
226
+ }
227
+
228
+ int32_t shim_bind_int(void *stmt, int32_t idx, int64_t val) {
229
+ return (int32_t)sqlite3_bind_int64((sqlite3_stmt *)stmt, (int)idx,
230
+ (sqlite3_int64)val);
231
+ }
232
+
233
+ int32_t shim_bind_dbl(void *stmt, int32_t idx, double val) {
234
+ return (int32_t)sqlite3_bind_double((sqlite3_stmt *)stmt, (int)idx, val);
235
+ }
236
+
237
+ /* The text span is length-delimited; SQLITE_TRANSIENT copies the bytes
238
+ * inside the call — required because the borrow is call-scoped. */
239
+ int32_t shim_bind_text(void *stmt, int32_t idx, const uint8_t *val,
240
+ size_t vlen) {
241
+ return (int32_t)sqlite3_bind_text((sqlite3_stmt *)stmt, (int)idx,
242
+ (const char *)val, (int)vlen,
243
+ SQLITE_TRANSIENT);
244
+ }
245
+
246
+ int32_t shim_bind_blob(void *stmt, int32_t idx, const uint8_t *val,
247
+ size_t vlen) {
248
+ return (int32_t)sqlite3_bind_blob((sqlite3_stmt *)stmt, (int)idx, val,
249
+ (int)vlen, SQLITE_TRANSIENT);
250
+ }
251
+
252
+ int32_t shim_bind_null(void *stmt, int32_t idx) {
253
+ return (int32_t)sqlite3_bind_null((sqlite3_stmt *)stmt, (int)idx);
254
+ }
255
+
256
+ /* ------------------------------------------------------------------ */
257
+ /* result set access */
258
+ /* ------------------------------------------------------------------ */
259
+
260
+ int32_t shim_column_count(void *stmt) {
261
+ return (int32_t)sqlite3_column_count((sqlite3_stmt *)stmt);
262
+ }
263
+
264
+ int32_t shim_column_name(void *stmt, int32_t idx, uint8_t *buf, size_t len) {
265
+ const char *name = sqlite3_column_name((sqlite3_stmt *)stmt, (int)idx);
266
+ return copy_cstr(name, buf, len);
267
+ }
268
+
269
+ /* which: 0 = origin column, 1 = table, 2 = database, 3 = declared type.
270
+ * Needs SQLITE_ENABLE_COLUMN_METADATA for 0-2; decltype works always. */
271
+ int32_t shim_column_meta(void *stmt, int32_t idx, int32_t which, uint8_t *buf,
272
+ size_t len) {
273
+ sqlite3_stmt *s = (sqlite3_stmt *)stmt;
274
+ const char *v = NULL;
275
+ switch (which) {
276
+ case 0: v = sqlite3_column_origin_name(s, (int)idx); break;
277
+ case 1: v = sqlite3_column_table_name(s, (int)idx); break;
278
+ case 2: v = sqlite3_column_database_name(s, (int)idx); break;
279
+ case 3: v = sqlite3_column_decltype(s, (int)idx); break;
280
+ default: return -2;
281
+ }
282
+ return copy_cstr(v, buf, len);
283
+ }
284
+
285
+ int32_t shim_column_type(void *stmt, int32_t idx) {
286
+ return (int32_t)sqlite3_column_type((sqlite3_stmt *)stmt, (int)idx);
287
+ }
288
+
289
+ int64_t shim_column_int64(void *stmt, int32_t idx) {
290
+ return (int64_t)sqlite3_column_int64((sqlite3_stmt *)stmt, (int)idx);
291
+ }
292
+
293
+ double shim_column_dbl(void *stmt, int32_t idx) {
294
+ return sqlite3_column_double((sqlite3_stmt *)stmt, (int)idx);
295
+ }
296
+
297
+ int32_t shim_column_text(void *stmt, int32_t idx, uint8_t *buf, size_t len) {
298
+ sqlite3_stmt *s = (sqlite3_stmt *)stmt;
299
+ const void *v = sqlite3_column_text(s, (int)idx);
300
+ int32_t n = (int32_t)sqlite3_column_bytes(s, (int)idx);
301
+ return copy_bytes(v, n, buf, len);
302
+ }
303
+
304
+ int32_t shim_column_blob(void *stmt, int32_t idx, uint8_t *buf, size_t len) {
305
+ sqlite3_stmt *s = (sqlite3_stmt *)stmt;
306
+ const void *v = sqlite3_column_blob(s, (int)idx);
307
+ int32_t n = (int32_t)sqlite3_column_bytes(s, (int)idx);
308
+ return copy_bytes(v, n, buf, len);
309
+ }
310
+
311
+ /* ------------------------------------------------------------------ */
312
+ /* write bookkeeping */
313
+ /* ------------------------------------------------------------------ */
314
+
315
+ int64_t shim_last_insert_rowid(void *db) {
316
+ return (int64_t)sqlite3_last_insert_rowid((sqlite3 *)db);
317
+ }
318
+
319
+ int32_t shim_changes(void *db) {
320
+ return (int32_t)sqlite3_changes((sqlite3 *)db);
321
+ }
@@ -0,0 +1 @@
1
+ 3.50.4 (3500400)