3 docCopyright("Steve Dekorte", 2004)
4 docLicense("BSD revised")
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:
9 db setPath("myDatabase.sqlite")
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'")
20 docCategory("Databases")
23 #include "IoSQLite3.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
);
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
},
81 IoObject_addMethodTable_(self
, methodTable
);
86 IoSQLite3
*IoSQLite3_rawClone(IoSQLite3
*proto
)
88 IoObject
*self
= IoObject_rawClonePrimitive(proto
);
89 IoObject_setDataPointer_(self
, cpalloc(IoObject_dataPointer(proto
), sizeof(IoSQLite3Data
)));
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
);
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
);
153 IoObject
*IoSQLite3_path(IoSQLite3
*self
, IoObject
*locals
, IoMessage
*m
)
157 "Returns the path to the database file. ")
160 return DATA(self
)->path
;
163 IoObject
*IoSQLite3_setPath(IoSQLite3
*self
, IoObject
*locals
, IoMessage
*m
)
167 "Sets the path to the database file. Returns self. ")
170 DATA(self
)->path
= IOREF(IoMessage_locals_symbolArgAt_(m
, locals
, 0));
174 IoObject
*IoSQLite3_timeoutSeconds(IoSQLite3
*self
, IoObject
*locals
, IoMessage
*m
)
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
)
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
);
198 IoObject
*IoSQLite3_open(IoSQLite3
*self
, IoObject
*locals
, IoMessage
*m
)
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);
225 IoObject
*IoSQLite3_isOpen(IoSQLite3
*self
, IoObject
*locals
, IoMessage
*m
)
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
)
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. ")
243 sqlite3_close(DATA(self
)->db
);
244 DATA(self
)->db
= NULL
;
250 static int IoSQLite3_singleItemResultRow(void *context
, int argc
, char **argv
, char **azColName
)
252 IoSQLite3
*self
= context
;
258 value
= IOSYMBOL(argv
[i
]);
262 value
= IOSYMBOL((char *)"NULL");
265 IoList_rawAppend_(DATA(self
)->results
, value
);
269 static int IoSQLite3_columnNamesResultRow(void *context
, int argc
, char **argv
, char **azColName
)
271 IoSQLite3
*self
= context
;
274 for (i
= 0; i
< argc
; i
++)
276 if (!strcmp(azColName
[i
], "name"))
278 IoList_rawAppend_(DATA(self
)->results
, IOSYMBOL(argv
[i
]));
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
);
294 IoSymbol
*key
, *value
;
296 for(i
= 0; i
< argc
; i
++)
298 key
= IOSYMBOL(azColName
[i
]);
302 value
= IOSYMBOL(argv
[i
]);
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
);
321 IoObject
*IoSQLite3_execWithCallback(IoSQLite3
*self
,
322 IoObject
*locals
, IoMessage
*m
, IoSymbol
*s
, ResultRowCallback
*callback
)
328 IoSQLite3_open(self
, locals
, m
);
336 DATA(self
)->results
= IOREF(IoList_new(IOSTATE
));
338 if (DATA(self
)->debugOn
)
340 IoState_print_(IOSTATE
, "*** %s ***\n", CSTRING(s
));
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
;
355 IoObject
*IoSQLite3_exec(IoSQLite3
*self
, IoObject
*locals
, IoMessage
*m
)
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
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
)
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
)
383 return IOSYMBOL(IoSQLite3_error(self
));
386 IoObject
*IoSQLite3_version(IoSQLite3
*self
, IoObject
*locals
, IoMessage
*m
)
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
)
400 "Returns the number of rows that were changed by the most
401 recent SQL statement. Or Nil if the database is closed.")
409 return IONUMBER(sqlite3_changes(DATA(self
)->db
));
412 IoObject
*IoSQLite3_lastInsertRowId(IoSQLite3
*self
, IoObject
*locals
, IoMessage
*m
)
415 docSlot("lastInsertRowId",
416 "Returns the number with the row id of the last row inserted. ")
424 return IONUMBER(sqlite3_last_insert_rowid(DATA(self
)->db
));
427 IoObject
*IoSQLite3_tableNames(IoSQLite3
*self
, IoObject
*locals
, IoMessage
*m
)
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
)
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
)
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
)
466 "Turns on debugging.")
469 DATA(self
)->debugOn
= 1;
473 IoObject
*IoSQLite3_debugOff(IoSQLite3
*self
, IoObject
*locals
, IoMessage
*m
)
477 "Turns off debugging.")
480 DATA(self
)->debugOn
= 0;
484 IoObject
*IoSQLite3_escapeString(IoSQLite3
*self
, IoObject
*locals
, IoMessage
*m
)
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);