3 docCopyright("Steve Dekorte", 2004)
4 docLicense("BSD revised")
5 docCategory("Databases")
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'")
28 typedef int (ResultRowCallback
)(void *, int , char **, char **);
30 #define DATA(self) ((IoSQLiteData *)IoObject_dataPointer(self))
33 static int IoSQLite_resultRow(void *context, int argc, char **argv, char **azColName);
34 static int IoSQLite_busyHandler(void *context, const char *s, int n);
37 IoTag
*IoSQLite_newTag(void *state
)
39 IoTag
*tag
= IoTag_newWithName_("SQLite");
40 IoTag_state_(tag
, state
);
41 IoTag_cloneFunc_(tag
, (IoTagCloneFunc
*)IoSQLite_rawClone
);
42 IoTag_freeFunc_(tag
, (IoTagFreeFunc
*)IoSQLite_free
);
43 IoTag_markFunc_(tag
, (IoTagMarkFunc
*)IoSQLite_mark
);
47 IoSQLite
*IoSQLite_proto(void *state
)
49 IoObject
*self
= IoObject_new(state
);
50 IoObject_tag_(self
, IoSQLite_newTag(state
));
52 IoObject_setDataPointer_(self
, calloc(1, sizeof(IoSQLiteData
)));
53 DATA(self
)->path
= IOSYMBOL(".");
54 IoSQLite_error_(self
, "");
56 IoState_registerProtoWithFunc_(state
, self
, IoSQLite_proto
);
59 IoMethodTable methodTable
[] = {
60 {"setPath", IoSQLite_setPath
},
61 {"path", IoSQLite_path
},
62 {"open", IoSQLite_open
},
63 {"close", IoSQLite_close
},
64 {"exec", IoSQLite_exec
},
65 {"error", IoSQLite_errorMessage
},
66 {"version", IoSQLite_version
},
67 {"setTimeoutSeconds", IoSQLite_setTimeoutSeconds
},
68 {"timeoutSeconds", IoSQLite_timeoutSeconds
},
69 {"rowsChangedCount", IoSQLite_changes
},
70 {"lastInsertRowId", IoSQLite_lastInsertRowId
},
71 {"tableNames", IoSQLite_tableNames
},
72 {"viewNames", IoSQLite_viewNames
},
73 {"columnNamesOfTable", IoSQLite_columnNamesOfTable
},
74 {"debugOn", IoSQLite_debugOn
},
75 {"debugOff", IoSQLite_debugOff
},
76 {"isOpen", IoSQLite_isOpen
},
77 {"escapeString", IoSQLite_escapeString
},
80 IoObject_addMethodTable_(self
, methodTable
);
85 IoSQLite
*IoSQLite_rawClone(IoSQLite
*proto
)
87 IoObject
*self
= IoObject_rawClonePrimitive(proto
);
88 IoObject_setDataPointer_(self
, cpalloc(IoObject_dataPointer(proto
), sizeof(IoSQLiteData
)));
89 DATA(self
)->error
= NULL
;
90 IoSQLite_error_(self
, "");
94 /* ----------------------------------------------------------- */
96 IoSQLite
*IoSQLite_new(void *state
)
98 IoObject
*proto
= IoState_protoWithInitFunction_(state
, IoSQLite_proto
);
99 return IOCLONE(proto
);
102 IoSQLite
*IoSQLite_newWithPath_(void *state
, IoSymbol
*path
)
104 IoSQLite
*self
= IoSQLite_new(state
);
105 DATA(self
)->path
= IOREF(path
);
109 void IoSQLite_free(IoSQLite
*self
)
111 if (DATA(self
)->db
) sqlite_close(DATA(self
)->db
);
112 if (DATA(self
)->error
) free(DATA(self
)->error
);
113 free(IoObject_dataPointer(self
));
116 void IoSQLite_mark(IoSQLite
*self
)
118 IoObject_shouldMark((IoObject
*)DATA(self
)->path
);
120 if (DATA(self
)->results
)
122 IoObject_shouldMark((IoObject
*)DATA(self
)->results
);
126 void IoSQLite_error_(IoSQLite
*self
, char *error
)
128 DATA(self
)->error
= strcpy((char *)realloc(DATA(self
)->error
, strlen(error
)+1), error
);
130 if (strlen(DATA(self
)->error
) && DATA(self
)->debugOn
)
132 IoState_print_(IOSTATE
, "*** IoSQLite error '%s' ***\n", DATA(self
)->error
);
136 char *IoSQLite_error(IoSQLite
*self
)
138 return DATA(self
)->error
;
141 /* ----------------------------------------------------------- */
143 static int IoSQLite_busyHandler(void *context
, const char *s
, int n
)
145 IoSQLite
*self
= context
;
146 IoState_yield(IOSTATE
);
150 IoObject
*IoSQLite_path(IoSQLite
*self
, IoObject
*locals
, IoMessage
*m
)
154 "Returns the path to the database file. ")
157 return DATA(self
)->path
;
160 IoObject
*IoSQLite_setPath(IoSQLite
*self
, IoObject
*locals
, IoMessage
*m
)
164 "Sets the path to the database file. Returns self. ")
167 DATA(self
)->path
= IOREF(IoMessage_locals_symbolArgAt_(m
, locals
, 0));
171 IoObject
*IoSQLite_timeoutSeconds(IoSQLite
*self
, IoObject
*locals
, IoMessage
*m
)
174 docSlot("timeoutSeconds",
175 "Returns the number of seconds to wait before timing out an open call. If the number is 0, an open call will never timeout. ")
177 return IONUMBER(DATA(self
)->timeoutSeconds
);
180 IoObject
*IoSQLite_setTimeoutSeconds(IoSQLite
*self
, IoObject
*locals
, IoMessage
*m
)
183 docSlot("setTimeoutSeconds(aNumber)",
184 "Sets the open timeout to aNumber. If aNumber is 0, an open call will never timeout. Returns self. ")
187 IoNumber
*num
= IoMessage_locals_numberArgAt_(m
, locals
, 0);
188 IOASSERT(IoNumber_asDouble(num
) >= 0, "SQLite timeout must be a positive number");
189 DATA(self
)->timeoutSeconds
= IoNumber_asDouble(num
);
193 IoObject
*IoSQLite_open(IoSQLite
*self
, IoObject
*locals
, IoMessage
*m
)
196 docSlot("open(optionalPathString)",
197 """Opens the database.Returns self on success or nil upon failure.
199 If the databse is locked, "yield" will be called until it is accessable or timeoutSeconds has expired.
205 if (DATA(self
)->debugOn
)
207 IoState_print_(IOSTATE
, "IoSQLite opening '%s'\n", CSTRING(DATA(self
)->path
));
210 DATA(self
)->db
= sqlite_open(CSTRING(DATA(self
)->path
), 0, &zErrMsg
);
214 IoSQLite_error_(self
, zErrMsg
);
218 IoSQLite_error_(self
, "");
221 sqlite_busy_handler(DATA(self
)->db
, IoSQLite_busyHandler
, self
);
222 sqlite_busy_timeout(DATA(self
)->db
, DATA(self
)->timeoutSeconds
*1000);
226 IoObject
*IoSQLite_isOpen(IoSQLite
*self
, IoObject
*locals
, IoMessage
*m
)
229 docSlot("isOpen", "Returns true if the database is open, false otherwise.")
232 return IOBOOL(self
, DATA(self
)->db
!= NULL
);
235 IoObject
*IoSQLite_close(IoSQLite
*self
, IoObject
*locals
, IoMessage
*m
)
239 "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. ")
244 sqlite_close(DATA(self
)->db
);
245 DATA(self
)->db
= NULL
;
251 static int IoSQLite_singleItemResultRow(void *context
, int argc
, char **argv
, char **azColName
)
253 IoSQLite
*self
= context
;
259 value
= IOSYMBOL(argv
[i
]);
263 value
= IOSYMBOL((char *)"NULL");
266 IoList_rawAppend_(DATA(self
)->results
, value
);
271 static int IoSQLite_columnNamesResultRow(void *context
, int argc
, char **argv
, char **azColName
)
273 IoSQLite
*self
= context
;
276 for (i
= 0; i
< argc
; i
++)
278 if (!strcmp(azColName
[i
], "name"))
280 IoList_rawAppend_(DATA(self
)->results
, IOSYMBOL(argv
[i
]));
288 static int IoSQLite_resultRow(void *context
, int argc
, char **argv
, char **azColName
)
290 IoSQLite
*self
= context
;
291 IoState_pushRetainPool(IOSTATE
);
294 IoMap
*map
= IoMap_new(IOSTATE
);
295 PHash
*hash
= IoMap_rawHash(map
);
297 IoSymbol
*key
, *value
;
299 for(i
= 0; i
< argc
; i
++)
301 key
= IOSYMBOL(azColName
[i
]);
305 value
= IOSYMBOL(argv
[i
]);
309 value
= IOSYMBOL((char *)"NULL");
312 PHash_at_put_(hash
, key
, value
);
313 /*printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL"); */
316 IoList_rawAppend_(DATA(self
)->results
, map
);
319 IoState_popRetainPool(IOSTATE
);
324 IoObject
*IoSQLite_execWithCallback(IoSQLite
*self
,
328 ResultRowCallback
*callback
)
334 IoSQLite_open(self
, locals
, m
);
342 DATA(self
)->results
= IOREF(IoList_new(IOSTATE
));
344 if (DATA(self
)->debugOn
)
346 IoState_print_(IOSTATE
, "*** %s ***\n", CSTRING(s
));
351 int rc
= sqlite_exec(DATA(self
)->db
, CSTRING(s
), callback
, self
, &zErrMsg
);
355 IoSQLite_error_(self
, zErrMsg
);
356 IoState_error_(IOSTATE
, m
, zErrMsg
);
360 IoSQLite_error_(self
, "");
364 results
= DATA(self
)->results
;
365 DATA(self
)->results
= NULL
;
369 IoObject
*IoSQLite_exec(IoSQLite
*self
, IoObject
*locals
, IoMessage
*m
)
372 docSlot("exec(aString)",
373 "Opens the database if it is not already open and executes
374 aString as an sql command. Results a List of Map objects or Nil if
375 there was an error. Each map holds the contents of a row.
376 The key/value pairs of the maps being column name/column value
381 IoSymbol
*s
= IoMessage_locals_seqArgAt_(m
, locals
, 0);
382 return IoSQLite_execWithCallback(self
, locals
, m
, s
, IoSQLite_resultRow
);
385 IoObject
*IoSQLite_errorMessage(IoSQLite
*self
, IoObject
*locals
, IoMessage
*m
)
389 "Results a string containing the current error. If there is no error, Nil is returned. ")
392 if (strlen(DATA(self
)->error
)==0)
397 return IOSYMBOL(DATA(self
)->error
);
400 IoObject
*IoSQLite_version(IoSQLite
*self
, IoObject
*locals
, IoMessage
*m
)
404 "Results a string the version of SQLite being used. ")
407 return IOSYMBOL(SQLITE_VERSION
);
410 IoObject
*IoSQLite_changes(IoSQLite
*self
, IoObject
*locals
, IoMessage
*m
)
414 "Returns the number of rows that were changed by the most recent SQL statement. Or Nil if the database is closed.")
422 return IONUMBER(sqlite_changes(DATA(self
)->db
));
425 IoObject
*IoSQLite_lastInsertRowId(IoSQLite
*self
, IoObject
*locals
, IoMessage
*m
)
428 docSlot("lastInsertRowId",
429 "Returns the number with the row id of the last row inserted. ")
437 return IONUMBER(sqlite_last_insert_rowid(DATA(self
)->db
));
440 IoObject
*IoSQLite_tableNames(IoSQLite
*self
, IoObject
*locals
, IoMessage
*m
)
443 docSlot("tableNames",
444 "Returns a list containing the names of all tables in the database.")
447 IoSymbol
*s
= IOSYMBOL("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name");
448 return IoSQLite_execWithCallback(self
, locals
, m
, s
, IoSQLite_singleItemResultRow
);
451 IoObject
*IoSQLite_viewNames(IoSQLite
*self
, IoObject
*locals
, IoMessage
*m
)
455 "Returns a list containing the names of all
456 views in the database.")
459 IoSymbol
*s
= IOSYMBOL("SELECT name FROM sqlite_master WHERE type='view' ORDER BY name");
460 return IoSQLite_execWithCallback(self
, locals
, m
, s
, IoSQLite_singleItemResultRow
);
463 IoObject
*IoSQLite_columnNamesOfTable(IoSQLite
*self
, IoObject
*locals
, IoMessage
*m
)
466 docSlot("columnNamesOfTable(tableName)",
467 "Returns a list containing the names of all columns in the specified table.")
470 IoSymbol
*tableName
= IoMessage_locals_symbolArgAt_(m
, locals
, 0);
471 IoSymbol
*s
= IoSeq_newSymbolWithFormat_(IOSTATE
, "PRAGMA TABLE_INFO(%s)", CSTRING(tableName
));
472 return IoSQLite_execWithCallback(self
, locals
, m
, s
, IoSQLite_columnNamesResultRow
);
475 IoObject
*IoSQLite_debugOn(IoSQLite
*self
, IoObject
*locals
, IoMessage
*m
)
479 "Turns on debugging.")
482 DATA(self
)->debugOn
= 1;
486 IoObject
*IoSQLite_debugOff(IoSQLite
*self
, IoObject
*locals
, IoMessage
*m
)
490 "Turns off debugging.")
493 DATA(self
)->debugOn
= 0;
497 IoObject
*IoSQLite_escapeString(IoSQLite
*self
, IoObject
*locals
, IoMessage
*m
)
500 docSlot("escapeString(aString)",
501 "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.")
504 IoSymbol
*s
= IoMessage_locals_seqArgAt_(m
, locals
, 0);
505 char *newString
= sqlite_mprintf("%q", CSTRING(s
));
506 UArray
*ba
= UArray_newWithCString_(newString
);
507 sqlite_freemem(newString
);
508 return IoState_symbolWithUArray_copy_(IOSTATE
, ba
, 0);