Initial commit of newLISP.
[newlisp.git] / modules / sqlite3.lsp
blob5f80148faa92547b6535d4c5b398c2888bfb60fd
1 ;; @module sqlite3.lsp
2 ;; @description SQLite3 database interface routines
3 ;; @version 1.6 - comments redone for automatic documentation
4 ;; @version 1.7 - a fix getting types when null values are present (thanks Dmitry)
5 ;; @version 1.8 - a fix to make 64-Bit integers work (thanks Dmitry)
6 ;; @version 1.9 - new library detection routine
7 ;; @author Lutz Mueller, 2004-7
8 ;;
9 ;; <h2>Module for SQLite3 database bindings</h2>
10 ;; To use this module include the following 'load' statement at the
11 ;; beginning of the program file:
12 ;; <pre>
13 ;; (load "/usr/share/newlisp/modules/sqlite3.lsp")
14 ;; </pre>
16 ;; SQLite version 3.0 introduced a new database format and is incompatible
17 ;; whith the previous 2.1 to 2.8 format. Old SQLite 2.x based databases can
18 ;; be converted using the old and new sqlite client application:
20 ;; sqlite OLD.DB .dump | sqlite3 NEW.DB
22 ;; While in sqlite 2.8 all returned fields where of string type, SQLite3
23 ;; returns, text, integer or float. Blobs are returned as text and NULLs
24 ;; are returned as nil.
26 ;; See also the documentation at @link http://sqlite.org sqlite.org
28 ;; <h2>Requirements:</h2>
29 ;; One of the libraries sqlite3.dll for Win32 or libsqlite3.so for UNIX like
30 ;; operating systems is required from http://www.sqlite.org.
32 ;; SQLite is an <in-process> database. The library contains the whole database
33 ;; system. An extra database server is not required. SQLite also has limited
34 ;; mutiuser capabilities for accessing a common database from several programs
35 ;; at the same time. See the documentaion at @link http://sqlite.org sqlite.org
36 ;; for details.
38 ;; The following is a short example how to use SQLite3:
40 ;; @example
41 ;; (sql3:open "MYDB") ; opens/creates a database returns a handle (ignore)
42 ;; ; or 'nil' on failure
44 ;; (sql3:sql "select * from mytable;") ; make a SQL query, return result
46 ;; (sql3:error) ; return error text
48 ;; (sql3:close) ; close the database
50 ;; Function calls returning 'nil' signal that an error has occurred. The
51 ;; function 'sql3:error' can then be used to get details about the error
52 ;; as a text string.
54 ;; At the bottom of the source file 'sqlite3.lsp' a test routine called
55 ;; 'test-sqlite3' can be found to test for correct installation of SQLite.
57 (context 'sql3)
59 ; set library to path-name of the library on your platform OS
61 (set 'files (list
62 "/usr/local/lib/libsqlite3.so" ; Linyx and BSDs
63 "/usr/lib/libsqlite3.0.dylib" ; Mac OSX Darwin
64 "/usr/local/lib/libsqlite3.so" ; Solaris
65 (string (env "PROGRAMFILES") "/sqlite3/sqlite3.dll") ; Win32/MinGW
69 (set 'library (files (or
70 (find true (map file? files))
71 (begin (println "cannot find sqlite3 library") (exit)))))
73 (import library "sqlite3_open" "cdecl")
74 (import library "sqlite3_close" "cdecl")
75 (import library "sqlite3_prepare" "cdecl")
76 (import library "sqlite3_step" "cdecl")
77 (import library "sqlite3_column_count" "cdecl")
78 (import library "sqlite3_column_name" "cdecl")
79 (import library "sqlite3_column_type" "cdecl")
80 (import library "sqlite3_column_int" "cdecl")
81 (import library "sqlite3_column_double" "cdecl")
82 (import library "sqlite3_column_text" "cdecl")
83 (import library "sqlite3_column_blob" "cdecl")
84 (import library "sqlite3_column_bytes" "cdecl")
85 (import library "sqlite3_finalize" "cdecl")
86 (import library "sqlite3_get_table" "cdecl")
87 (import library "sqlite3_last_insert_rowid" "cdecl")
88 (import library "sqlite3_changes" "cdecl")
89 (import library "sqlite3_busy_timeout" "cdecl")
90 (import library "sqlite3_errmsg" "cdecl")
93 ; gloablly used vars and constants
95 (define db nil) ; database handle
96 (define dbp "\000\000\000\000") ; ptr to database handle
97 (define error-message nil) ; error message
98 (define col-names '()) ; list of column headers
99 (define col-types '()) ; list of column types
100 (define pstm "\000\000\000\000") ; ptr to compiled sql
102 (constant 'SQLITE_OK 0)
103 (constant 'SQLITE_ROW 100)
104 (constant 'SQLITE_DONE 101)
106 (constant 'SQLITE_TYPES '(
108 SQLITE_INTEGER
109 SQLITE_FLOAT
110 SQLITE_TEXT
111 SQLITE_BLOB
112 SQLITE_NULL))
114 ;; @syntax (sql3:open <str-db-name>)
115 ;; @param <str-db-name> The name of the database.
116 ;; @return A database handle (discard), or 'nil' on failure.
118 ;; Opens or creates a database. If the database does exist it gets opened,
119 ;; else a new database with the name given is created.
120 ;; If trying to open a database that already has been opened 'nil' is returned
121 ;; and an error text can be retrieved using 'sql3:error'.
123 (define (sql3:open db-name)
124 ; only open if not alrady done
125 (if (not db)
126 (begin
127 (set 'result (sqlite3_open db-name dbp))
128 (if (!= result SQLITE_OK)
129 (set 'db nil)
130 (set 'db (get-int dbp))))
131 (begin
132 (set 'error-message "A database is already open")
133 nil))
136 ; close the currently open database ;;;
139 (define (sql3:close) ;; overwrite the close in MAIN
140 (if db (begin
141 (sqlite3_close db)
142 (set 'db nil)
143 true)))
145 ;; @syntax (sql3:sql <str-sql>)
146 ;; @param <str-sql> The SQL statement.
148 ;; Executes the SQL statement in <str-sql>. For 'select' statements an array
149 ;; of the result set is returned or '()' for the empty set. For other statements
150 ;; 'true' is returned for a successful outcome. On failure 'nil' is returened
151 ;; and 'sql3:error' can be used to retrieve the error text.
153 (define (sql sql-str)
154 (set 'result nil 'done nil 'error-message nil)
155 (set 'sqarray '());
156 (set 'col-names '());
157 (set 'col-types '());
159 ; set up parameters for sqlite3_prepare() call
160 (set 'ppstm "\000\000\000\000") ; pointer to statement ptr
161 (set 'pptail "\000\000\000\000") ; pointer to statement tail
163 ; compile the sql statment
164 (if db (set 'result (sqlite3_prepare db sql-str -1 ppstm pptail)))
166 ; set up parameters for sqlite3_step() call
167 (set 'pstm (get-int ppstm))
169 ; execute the compiled statement
170 (if (= result SQLITE_OK)
171 (while (not done)
172 ;; execute statement until done/101 or
173 (set 'result (sqlite3_step pstm))
174 (set 'num-cols (sqlite3_column_count pstm))
175 (if (empty? col-names) (set 'col-names (get-names pstm num-cols)))
176 (set 'col-types (get-types pstm num-cols))
177 (if (= result SQLITE_ROW)
178 (push (get-values pstm num-cols) sqarray -1)
179 (set 'done true) ;; received done/101 or error
183 ; if done/101 finalize
184 (if (= result SQLITE_DONE)
185 (begin
186 (set 'result (sqlite3_finalize pstm))
187 ; for 'select' statements return the array else 'true'
188 (if (> num-cols 0) sqarray true))
189 (if (= result 0) true (set-error))))
192 (define (get-values pstm cols)
193 (set 'row '())
194 (dotimes (idx cols)
195 (set 'i (int idx)) ; all loop vars are float
196 (case (nth idx col-types idx)
197 ; (SQLITE_INTEGER
198 ; (push (sqlite3_column_int pstm i) row -1))
199 ; fixed for 64-bit, thanks Dmitry
200 (SQLITE_INTEGER
201 (set 'pstr (sqlite3_column_text pstm i))
202 (if (= pstr 0)
203 (push nil row -1)
204 (push (int (get-string pstr)) row -1)))
205 (SQLITE_FLOAT
206 (set 'pstr (sqlite3_column_text pstm i))
207 (if (= pstr 0)
208 (push nil row -1)
209 (push (float (get-string pstr)) row -1)))
210 (SQLITE_TEXT
211 (set 'pstr (sqlite3_column_text pstm i))
212 (if (= pstr 0)
213 (push "" row -1)
214 (push (get-string pstr) row -1)))
216 ; not tested yet
217 (SQLITE_BLOB
218 (set 'pstr (sqlite3_column_blob pstm i))
219 (set 'len (sqlite3_column_bytes pstm i))
220 (set 'buff (dup "\000" len))
221 (if (= pstr 0)
222 (push "" row -1)
223 (begin
224 (cpymem pstr buff len)
225 (push buff row -1))))
226 (SQLITE_NULL
227 (push nil row -1))))
228 row)
230 (define (get-names pstm cols)
231 (set 'row '())
232 (dotimes (idx cols)
233 (set 'i (int idx)) ; all loop vars are float
234 (set 'ps (sqlite3_column_name pstm i))
235 (if (= ps 0) ;; check for null pointer to result
236 (push "" row -1)
237 (push (get-string ps) row -1)))
238 row)
240 (define (get-types pstm cols)
241 (set 'row '())
242 (dotimes (idx cols)
243 (set 'i (int idx)) ; all loop vars are float
244 (push (nth (sqlite3_column_type pstm i) SQLITE_TYPES) row -1))
245 row)
248 ;; @syntax (sql3:rowid)
249 ;; @return The last row id from last 'insert'.
251 (define (rowid)
252 (if db (sqlite3_last_insert_rowid db)))
254 ;; @syntax (sql3:tables)
255 ;; @return A list of tables in the database.
257 (define (tables)
258 (if db (begin
259 (set 'lst (sql "select tbl_name from sqlite_master")) ))
260 (if lst (set 'lst (first (transpose lst)))))
263 ;; @syntax (sql3:columns <str-tabel-name>)
264 ;; @return A list of column names for a table.
266 (define (columns aTable)
267 (if (list? (sql (append "select * from " aTable " where 0;")))
268 col-names))
271 ;; @syntax (sql3:changes)
272 ;; @return The Number of rows changed/affected by the last SQL statement.
274 (define (changes)
275 (if db (sqlite3_changes db)))
279 ;; @syntax (sql3:timeout <num-milli-seconds>)
280 ;; @return 'true' on success or 'nil' on failure.
282 ;; Sets busy timeout in milliseconds.
284 (define (timeout ms)
285 (if db (zero? (sqlite3_busy_timeout db (int ms)))))
289 ;; @syntax (sql3:error)
290 ;; @return The error text of the last error occured in 'sql3:sql'.
292 (define (error) error-message)
294 (define (set-error)
295 (set 'result (sqlite3_errmsg db))
296 (if (= result 0)
297 (set 'error-message nil)
298 (set 'error-message (get-string result))
304 (context 'MAIN)
306 ; -------------------------------------------------------------------------
308 ; test the database routines
310 ; if there is an old "TEST" db from an earlier sqlite 2.8 delete it first
312 (define (test-sqlite3)
313 (if (sql3:open "TEST")
314 (println "database opened/created, ... Ok")
315 (println "problem opening/creating database"))
317 (if (sql3:sql "create table fruits (name CHAR(20), qty INT(3), price FLOAT(10), blobtext BLOB);")
318 (println "created table fruits, ... Ok")
319 (println "problem creating table fruits"))
321 (if (sql3:sql "insert into fruits values ('apples', 11, 1.234, X'41424300010101');")
322 (println "inserted, last row id: " (sql3:rowid) ", ... Ok")
323 (println "problem inserting row"))
325 (if (sql3:sql "insert into fruits values ('oranges', 22, 2.345, X'42434400020202');")
326 (println "inserted, last row id: " (sql3:rowid) ", ... Ok")
327 (println "problem inserting row"))
329 (if (sql3:sql "insert into fruits values ('bananas', 33, 3.456, X'44454600030303');")
330 (println "inserted, last row id: " (sql3:rowid) ", ... Ok")
331 (println "problem inserting row"))
333 (if (sql3:sql
334 "insert into fruits values ('grapes', 123456789012345678, 7.89, X'47484900040404');")
335 (println "inserted, last row id: " (sql3:rowid) ", ... Ok")
336 (println "problem inserting row"))
338 (set 'sqarray (sql3:sql "select * from fruits;"))
340 (if sqarray
341 (begin
342 (println "selected rows: ")
343 (map println sqarray)
344 (println "column names: ")
345 (map println sql3:col-names)
346 (println "... Ok")
348 (println "problem with select"))
350 (if (sql3:sql "delete from fruits where 1;")
351 (println "deleted, rows affected: " (sql3:changes) ", ... Ok")
352 (println "problem deleting rows"))
354 (if (list? (sql3:tables) )
355 (println "tables: " (sql3:tables) ", ... Ok")
356 (println "problem in sql3:tables"))
358 (if (list? (sql3:columns "fruits") )
359 (println "columns: " (sql3:columns "fruits") ", ... Ok")
360 (println "problem in sql3:columns"))
363 (if (sql3:sql "drop table fruits;")
364 (println "table fruits dropped, ... Ok")
365 (println "problem dropping table fruits"))
368 (sql3:close)
372 ; eof ;