2 ;; @description MySQL v.4 interface
3 ;; @version v2.31 - addition for mysql_escape_string (Jeff)
4 ;; @author Lutz Mueller 2003, Gordon Fischer 2005, Jeff 2007
6 ;; newLISP connection to the MySQL v 4.1 database
8 ;; Current tested MySQL version is 4.1.14
10 ;; See also @link http://www.mysql.com www.mysql.com
12 ;; This file is tested with MySQL 4.0/4.1 and will not work on
13 ;; previous versions 3.22 and 3.23 which need different offsets
14 ;; into the MYSQL result data structure.
16 ;; <h3>Implemented functions</h3>
18 ;; MySQL:init ................ get a database handle MYSQL
19 ;; MySQL:connect ............. connect to a database
20 ;; MySQL:query ............... execute a SQL statement
21 ;; MySQL:num-rows ............ rows in result of query
22 ;; MySQL:num-fields .......... columns in result of query
23 ;; MySQL:fetch-row ........... get row from the query result
24 ;; MySQL:fetch-all ........... get all rows from the last query
25 ;; MySQL:database ............ return all database names
26 ;; MySQL:tables .............. return all tables names
27 ;; MySQL:fields .............. return all fields in a table
28 ;; MySQL:data-seek ........... position in result for fetching
29 ;; MySQL:affected-rows ....... number of affected rows from operation
30 ;; MySQL:inserted-id ......... last value of auto increment id operation
31 ;; MySQL:escape .............. escapes SQL input string using mysql_escape_string
32 ;; MySQL:error ............... get error message
33 ;; MySQL:close-db ............ close database connection
36 ;; For details on usage see the documentation for the mysql5.lsp module.
40 (set 'libmysqlclient
"/usr/lib/libmysqlclient.so.14")
42 (import libmysqlclient
"mysql_init")
43 (import libmysqlclient
"mysql_real_connect")
44 (import libmysqlclient
"mysql_get_host_info")
45 (import libmysqlclient
"mysql_escape_string")
46 (import libmysqlclient
"mysql_query")
47 (import libmysqlclient
"mysql_real_query")
48 (import libmysqlclient
"mysql_store_result")
49 (import libmysqlclient
"mysql_free_result")
50 (import libmysqlclient
"mysql_data_seek")
51 (import libmysqlclient
"mysql_fetch_row")
52 (import libmysqlclient
"mysql_close")
53 (import libmysqlclient
"mysql_fetch_field_direct")
54 (import libmysqlclient
"mysql_insert_id")
56 ; initialize database access, get an access handle MYSQL
59 (set 'MYSQL
(mysql_init 0))
60 (if (= MYSQL
0) (set 'MYSQL nil
))
63 ; connect to a specific database
65 (define (connect host user passw database
)
66 (not(= (mysql_real_connect MYSQL host user passw database
0 0 0) 0)))
68 ; send a SQL string for evaluation
71 (if MYSQL_RES
(mysql_free_result MYSQL_RES
))
72 (set 'result
(= (mysql_query MYSQL sql
) 0))
73 (set 'MYSQL_RES
(mysql_store_result MYSQL
))
74 (if (= MYSQL_RES
0) (set 'MYSQL_RES nil
))
75 (if (and result
(find "insert into" sql
1)) (set 'result
(inserted-id)))
78 ; number of rows from last query
81 (if MYSQL_RES
(get-int MYSQL_RES
)))
83 ; number of columns from last query
86 (if MYSQL_RES
(get-int (int (+ MYSQL_RES
60)))))
89 ; format the result based on the field type.
92 (define (keep-type res_ptr field_addr column_num
, data
)
93 (set 'type_ptr
(mysql_fetch_field_direct res_ptr
(int column_num
)))
94 ; The field type is the 20th field of the MySQL_FIELD structure
95 ; since fields 1-19 are all 4 byte fields we get the enum value
97 (set 'data
(get-int (int (+ type_ptr
(* 19 4)))))
98 ; Consult 'enum_field_types' in mysql_com.h for values
99 (if (= data
1) ;; boolean
100 (get-string field_addr
)
101 (= data
3) ;; integer
102 (int (get-string field_addr
))
103 (= data
12) ;; datetime
104 (apply date-value
(map int
(parse (get-string field_addr
) "[-: ]" 0)))
106 (float (get-string field_addr
))
108 (get-string field_addr
)
112 ; fetch a row from a query, subsequent calls go trough the table
113 ; until the bottom is reached
117 (set 'rdata
(mysql_fetch_row MYSQL_RES
))
122 (dotimes (field (num-fields))
123 (set 'field_addr
(get-int (int (+ rdata
(* field
4)))))
125 (push nil row -
1) ;; what to do when the field contains NULL
126 (push (keep-type MYSQL_RES field_addr field
) row -
1)))
129 ; return all rows/columns from the last query
133 (dotimes (x (num-rows)) (push (fetch-row) all
))
136 ; get a list of databases
139 (query "show databases;")
142 ; get a list of tables
145 (query "show tables;")
148 ; get a list of fields
150 (define (fields table
)
151 (query (append "show fields from " table
";"))
155 ; position to row in result set
157 (define (data-seek offset
)
160 (mysql_data_seek MYSQL_RES offset
)
163 ; Escapes input value using mysql_escape_string
164 (define (escape value
, safe-value
)
165 (set 'safe-value
(dup " " (+ 1 (length value
))))
166 (MySQL:mysql_escape_string safe-value value
(length value
))
169 ; text info about error
172 (if MYSQL
(get-string (+ MYSQL
60))))
174 ; number of affected rows by last MySQL:query operation
176 (define (affected-rows)
178 (get-int (int (+ MYSQL
368)))))
180 ; last insert_id from auto increment field
182 (define (inserted-id)
183 (if MYSQL
(mysql_insert_id MYSQL
)))
185 ; close database access
188 (if MYSQL_RES
(mysql_free_result MYSQL_RES
))
189 (if MYSQL
(mysql_close MYSQL
))
196 ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
198 ; test data base functions
203 (MySQL:connect
0 "" 0 "test")
205 (println "databases:")
206 (MySQL:query
"show databases;")
207 (dotimes (x (MySQL:num-rows
)) (println (MySQL:fetch-row
)))
210 (MySQL:query
"create table fruits (name CHAR(20),
212 num INT(4) AUTO_INCREMENT UNIQUE);")
214 (MySQL:query
"insert into fruits values ('apples', 11, null);")
215 (println "inserted-id: " (MySQL:inserted-id
))
216 (MySQL:query
"insert into fruits values ('oranges', 22, null);")
217 (println "inserted-id: " (MySQL:inserted-id
))
218 (MySQL:query
"insert into fruits values ('bananas', 33, null);")
219 (println "inserted-id: " (MySQL:inserted-id
))
221 (println "\n" (MySQL:affected-rows
) " affected rows in query")
223 (println "inserted into fruits:")
224 (MySQL:query
"select * from fruits;")
225 (dotimes (x (MySQL:num-rows
)) (println (MySQL:fetch-row
)))
227 (println "rows = " (MySQL:num-rows
) " fields = " (MySQL:num-fields
))
231 (MySQL:query
"show tables;")
232 (dotimes (x (MySQL:num-rows
)) (println (MySQL:fetch-row
)))
235 (MySQL:query
"select * from fruits;")
237 (println "data-seek to offset 2:")
238 (println (MySQL:fetch-row
))
241 (println "fetch-all:")
242 (println (MySQL:query
"select * from fruits;"))
243 (println (MySQL:fetch-all
))
245 (MySQL:query
"drop table fruits;")