Updating built in Io code to use += instead of x = x + y
[io/quag.git] / addons / SQLite3 / source / IoSQLite3.c
bloba29364c1740d5d810a7843219c0a09166c3ca172
1 /*#io
2 SQLite3 ioDoc(
3 docCopyright("Steve Dekorte", 2004)
4 docLicense("BSD revised")
5 docObject("SQLite3")
6 docDescription("""SQLite provides a embedded simple and fast (2x faster than PostgreSQL or MySQL) SQL database. See http://www.hwaci.com/sw/sqlite/ for details. It's SQL command set is described at http://www.hwaci.com/sw/sqlite/lang.html. SQLite was written by Dr. Richard Hipp who offers consulting services for custom modifications and support of SQLite. Example:
7 <pre>
8 db := SQLite clone
9 db setPath("myDatabase.sqlite")
10 db open
11 db exec("CREATE TABLE Dbm (key, value)")
12 db exec("CREATE INDEX DbmIndex ON Dbm (key)")
13 db exec("INSERT INTO Dbm ('key', 'value') VALUES ('a', '123')")
14 db exec("INSERT INTO Dbm ('key', 'value') VALUES ('a', 'efg')")
15 rows := db exec("SELECT key, value FROM Dbm WHERE key='a'")
16 db exec("DELETE FROM Dbm WHERE key='a'")
17 rows := db exec("SELECT key, value FROM Dbm WHERE key='a'")
18 db close
19 </pre>""")
20 docCategory("Databases")
23 #include "IoSQLite3.h"
24 #include "IoState.h"
25 #include "IoNumber.h"
26 #include "IoList.h"
27 #include "IoMap.h"
29 typedef int (ResultRowCallback)(void *, int , char **, char **);
31 #define DATA(self) ((IoSQLite3Data *)IoObject_dataPointer(self))
34 static int IoSQLite3_resultRow(void *context, int argc, char **argv, char **azColName);
35 static int IoSQLite3_busyHandler(void *context, const char *s, int n);
38 IoTag *IoSQLite3_newTag(void *state)
40 IoTag *tag = IoTag_newWithName_("SQLite3");
41 IoTag_state_(tag, state);
42 IoTag_cloneFunc_(tag, (IoTagCloneFunc *)IoSQLite3_rawClone);
43 IoTag_freeFunc_(tag, (IoTagFreeFunc *)IoSQLite3_free);
44 IoTag_markFunc_(tag, (IoTagMarkFunc *)IoSQLite3_mark);
45 return tag;
48 IoSQLite3 *IoSQLite3_proto(void *state)
50 IoObject *self = IoObject_new(state);
51 IoObject_tag_(self, IoSQLite3_newTag(state));
53 IoObject_setDataPointer_(self, calloc(1, sizeof(IoSQLite3Data)));
54 DATA(self)->path = IOSYMBOL(".");
56 IoState_registerProtoWithFunc_(state, self, IoSQLite3_proto);
59 IoMethodTable methodTable[] = {
60 {"setPath", IoSQLite3_setPath},
61 {"path", IoSQLite3_path},
62 {"open", IoSQLite3_open},
63 {"close", IoSQLite3_close},
64 {"exec", IoSQLite3_exec},
65 {"error", IoSQLite3_errorMessage},
66 {"version", IoSQLite3_version},
67 {"setTimeoutSeconds", IoSQLite3_setTimeoutSeconds},
68 {"timeoutSeconds", IoSQLite3_timeoutSeconds},
69 {"rowsChangedCount", IoSQLite3_changes},
70 {"lastInsertRowId", IoSQLite3_lastInsertRowId},
71 {"tableNames", IoSQLite3_tableNames},
72 {"viewNames", IoSQLite3_viewNames},
74 {"columnNamesOfTable", IoSQLite3_columnNamesOfTable},
75 {"debugOn", IoSQLite3_debugOn},
76 {"debugOff", IoSQLite3_debugOff},
77 {"isOpen", IoSQLite3_isOpen},
78 {"escapeString", IoSQLite3_escapeString},
79 {NULL, NULL},
81 IoObject_addMethodTable_(self, methodTable);
83 return self;
86 IoSQLite3 *IoSQLite3_rawClone(IoSQLite3 *proto)
88 IoObject *self = IoObject_rawClonePrimitive(proto);
89 IoObject_setDataPointer_(self, cpalloc(IoObject_dataPointer(proto), sizeof(IoSQLite3Data)));
90 return self;
93 /* ----------------------------------------------------------- */
95 IoSQLite3 *IoSQLite3_new(void *state)
97 IoObject *proto = IoState_protoWithInitFunction_(state, IoSQLite3_proto);
98 return IOCLONE(proto);
101 IoSQLite3 *IoSQLite3_newWithPath_(void *state, IoSymbol *path)
103 IoSQLite3 *self = IoSQLite3_new(state);
104 DATA(self)->path = IOREF(path);
105 return self;
108 void IoSQLite3_free(IoSQLite3 *self)
110 if (DATA(self)->db) sqlite3_close(DATA(self)->db);
111 free(IoObject_dataPointer(self));
114 void IoSQLite3_mark(IoSQLite3 *self)
116 IoObject_shouldMark((IoObject *)DATA(self)->path);
118 if (DATA(self)->results)
120 IoObject_shouldMark((IoObject *)DATA(self)->results);
124 void IoSQLite3_showError(IoSQLite3 *self)
126 int status = sqlite3_errcode(DATA(self)->db);
128 if (status != SQLITE_OK)
130 const char *error = IoSQLite3_error(self);
132 if (DATA(self)->debugOn)
134 IoState_print_(IOSTATE, "*** IoSQLite3 error '%s' ***\n", error);
139 const char *IoSQLite3_error(IoSQLite3 *self)
141 return sqlite3_errmsg(DATA(self)->db);
144 /* ----------------------------------------------------------- */
146 static int IoSQLite3_busyHandler(void *context, int n)
148 IoSQLite3 *self = context;
149 IoState_yield(IOSTATE);
150 return 1;
153 IoObject *IoSQLite3_path(IoSQLite3 *self, IoObject *locals, IoMessage *m)
155 /*#io
156 docSlot("path",
157 "Returns the path to the database file. ")
160 return DATA(self)->path;
163 IoObject *IoSQLite3_setPath(IoSQLite3 *self, IoObject *locals, IoMessage *m)
165 /*#io
166 docSlot("setPath",
167 "Sets the path to the database file. Returns self. ")
170 DATA(self)->path = IOREF(IoMessage_locals_symbolArgAt_(m, locals, 0));
171 return self;
174 IoObject *IoSQLite3_timeoutSeconds(IoSQLite3 *self, IoObject *locals, IoMessage *m)
176 /*#io
177 docSlot("timeoutSeconds",
178 "Returns the number of seconds to wait before timing out an
179 open call. If the number is 0, an open call will never timeout. ")
181 return IONUMBER(DATA(self)->timeoutSeconds);
184 IoObject *IoSQLite3_setTimeoutSeconds(IoSQLite3 *self, IoObject *locals, IoMessage *m)
186 /*#io
187 docSlot("setTimeoutSeconds(aNumber)",
188 "Sets the open timeout to aNumber. If aNumber is 0, an open
189 call will never timeout. Returns self. ")
192 IoNumber *num = IoMessage_locals_numberArgAt_(m, locals, 0);
193 IOASSERT(IoNumber_asDouble(num) >= 0, "SQLite timeout must be a positive number");
194 DATA(self)->timeoutSeconds = IoNumber_asDouble(num);
195 return self;
198 IoObject *IoSQLite3_open(IoSQLite3 *self, IoObject *locals, IoMessage *m)
200 /*#io
201 docSlot("open(optionalPathString)",
202 """Opens the database. If there is an optionalPathString argument,
203 the path is set to it's value before opening the database. If path is "" or ":memory:"
204 a database will be created in-memory, otherwise the file specified by path is opened.
205 Returns self or Nil upon failure.
207 If the databse is locked, "yield" will be called until it is accessable or
208 timeoutSeconds has expired. """)
211 if (IoMessage_argCount(m) > 0)
213 DATA(self)->path = IOREF(IoMessage_locals_symbolArgAt_(m, locals, 0));
216 sqlite3_open(CSTRING(DATA(self)->path), &(DATA(self)->db));
218 IoSQLite3_showError(self);
220 sqlite3_busy_handler(DATA(self)->db, IoSQLite3_busyHandler, self);
221 sqlite3_busy_timeout(DATA(self)->db, DATA(self)->timeoutSeconds * 1000);
222 return self;
225 IoObject *IoSQLite3_isOpen(IoSQLite3 *self, IoObject *locals, IoMessage *m)
227 /*#io
228 docSlot("isOpen", "Returns true if the database is open, false otherwise.")
231 return IOBOOL(self, DATA(self)->db != NULL);
234 IoObject *IoSQLite3_close(IoSQLite3 *self, IoObject *locals, IoMessage *m)
236 /*#io
237 docSlot("close",
238 "Closes the database if it is open. Returns self. If the database is open when the open is garbage collected, it will be automatically closed. ")
241 if (DATA(self)->db)
243 sqlite3_close(DATA(self)->db);
244 DATA(self)->db = NULL;
247 return self;
250 static int IoSQLite3_singleItemResultRow(void *context, int argc, char **argv, char **azColName)
252 IoSQLite3 *self = context;
253 int i = 0;
254 IoSymbol *value;
256 if (argv[i])
258 value = IOSYMBOL(argv[i]);
260 else
262 value = IOSYMBOL((char *)"NULL");
265 IoList_rawAppend_(DATA(self)->results, value);
266 return 0;
269 static int IoSQLite3_columnNamesResultRow(void *context, int argc, char **argv, char **azColName)
271 IoSQLite3 *self = context;
272 int i = 0;
274 for (i= 0; i < argc; i ++)
276 if (!strcmp(azColName[i], "name"))
278 IoList_rawAppend_(DATA(self)->results, IOSYMBOL(argv[i]));
279 break;
282 return 0;
285 static int IoSQLite3_resultRow(void *context, int argc, char **argv, char **azColName)
287 IoSQLite3 *self = context;
288 IoState_pushRetainPool(IOSTATE);
291 IoMap *map = IoMap_new(IOSTATE);
292 PHash *hash = IoMap_rawHash(map);
293 int i;
294 IoSymbol *key, *value;
296 for(i = 0; i < argc; i ++)
298 key = IOSYMBOL(azColName[i]);
300 if (argv[i])
302 value = IOSYMBOL(argv[i]);
304 else
306 value = IOSYMBOL((char *)"NULL");
309 PHash_at_put_(hash, key, value);
310 /*printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL"); */
313 IoList_rawAppend_(DATA(self)->results, map);
316 IoState_popRetainPool(IOSTATE);
318 return 0;
321 IoObject *IoSQLite3_execWithCallback(IoSQLite3 *self,
322 IoObject *locals, IoMessage *m, IoSymbol *s, ResultRowCallback *callback)
324 IoList *results;
326 if (!DATA(self)->db)
328 IoSQLite3_open(self, locals, m);
330 if (!DATA(self)->db)
332 return IONIL(self);
336 DATA(self)->results = IOREF(IoList_new(IOSTATE));
338 if (DATA(self)->debugOn)
340 IoState_print_(IOSTATE, "*** %s ***\n", CSTRING(s));
344 char *zErrMsg;
345 sqlite3_exec(DATA(self)->db, CSTRING(s), callback, self, &zErrMsg);
347 IoSQLite3_showError(self);
350 results = DATA(self)->results;
351 DATA(self)->results = NULL;
352 return results;
355 IoObject *IoSQLite3_exec(IoSQLite3 *self, IoObject *locals, IoMessage *m)
357 /*#io
358 docSlot("exec(aString)",
359 "Opens the database if it is not already open and executes
360 aString as an sql command. Results a List of Map objects or Nil if
361 there was an error. Each map holds the contents of a row.
362 The key/value pairs of the maps being column name/column value
363 pairs for a row. ")
367 IoSymbol *s = IoMessage_locals_seqArgAt_(m, locals, 0);
368 return IoSQLite3_execWithCallback(self, locals, m, s, IoSQLite3_resultRow);
371 IoObject *IoSQLite3_errorMessage(IoSQLite3 *self, IoObject *locals, IoMessage *m)
373 /*#io
374 docSlot("error",
375 "Results a string containing the current error. If there is no error, Nil is returned. ")
378 if (sqlite3_errcode(DATA(self)->db) == SQLITE_OK)
380 return IONIL(self);
383 return IOSYMBOL(IoSQLite3_error(self));
386 IoObject *IoSQLite3_version(IoSQLite3 *self, IoObject *locals, IoMessage *m)
388 /*#io
389 docSlot("version",
390 "Results a string the version of SQLite being used. ")
393 return IOSYMBOL(SQLITE_VERSION);
396 IoObject *IoSQLite3_changes(IoSQLite3 *self, IoObject *locals, IoMessage *m)
398 /*#io
399 docSlot("changes",
400 "Returns the number of rows that were changed by the most
401 recent SQL statement. Or Nil if the database is closed.")
404 if (!DATA(self)->db)
406 return IONUMBER(0);
409 return IONUMBER(sqlite3_changes(DATA(self)->db));
412 IoObject *IoSQLite3_lastInsertRowId(IoSQLite3 *self, IoObject *locals, IoMessage *m)
414 /*#io
415 docSlot("lastInsertRowId",
416 "Returns the number with the row id of the last row inserted. ")
419 if (!DATA(self)->db)
421 return IONIL(self);
424 return IONUMBER(sqlite3_last_insert_rowid(DATA(self)->db));
427 IoObject *IoSQLite3_tableNames(IoSQLite3 *self, IoObject *locals, IoMessage *m)
429 /*#io
430 docSlot("tableNames",
431 "Returns a list containing the names of all tables in the database.")
434 IoSymbol *s = IOSYMBOL("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name");
435 return IoSQLite3_execWithCallback(self, locals, m, s, IoSQLite3_singleItemResultRow);
438 IoObject *IoSQLite3_viewNames(IoSQLite3 *self, IoObject *locals, IoMessage *m)
440 /*#io
441 docSlot("viewNames",
442 "Returns a list containing the names of all
443 views in the database.")
446 IoSymbol *s = IOSYMBOL("SELECT name FROM sqlite_master WHERE type='view' ORDER BY name");
447 return IoSQLite3_execWithCallback(self, locals, m, s, IoSQLite3_singleItemResultRow);
450 IoObject *IoSQLite3_columnNamesOfTable(IoSQLite3 *self, IoObject *locals, IoMessage *m)
452 /*#io
453 docSlot("columnNamesOfTable(tableName)",
454 "Returns a list containing the names of all columns in the specified table.")
457 IoSymbol *tableName = IoMessage_locals_symbolArgAt_(m, locals, 0);
458 IoSymbol *s = IoSeq_newSymbolWithFormat_(IOSTATE, "PRAGMA TABLE_INFO(%s)", CSTRING(tableName));
459 return IoSQLite3_execWithCallback(self, locals, m, s, IoSQLite3_columnNamesResultRow);
462 IoObject *IoSQLite3_debugOn(IoSQLite3 *self, IoObject *locals, IoMessage *m)
464 /*#io
465 docSlot("debugOn",
466 "Turns on debugging.")
469 DATA(self)->debugOn = 1;
470 return self;
473 IoObject *IoSQLite3_debugOff(IoSQLite3 *self, IoObject *locals, IoMessage *m)
475 /*#io
476 docSlot("debugOff",
477 "Turns off debugging.")
480 DATA(self)->debugOn = 0;
481 return self;
484 IoObject *IoSQLite3_escapeString(IoSQLite3 *self, IoObject *locals, IoMessage *m)
486 /*#io
487 docSlot("escapeString(aString)",
488 "Returns a translated version of aString by making two copies of every single-quote (') character. This has the effect of escaping the end-of-string meaning of single-quote within a string literal.")
491 IoSymbol *s = IoMessage_locals_seqArgAt_(m, locals, 0);
492 char *newString = sqlite3_mprintf("%q", CSTRING(s));
493 UArray *ba = UArray_newWithCString_(newString);
494 sqlite3_free(newString);
495 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);