b58c8b010fd1c2ff72d36b02c85d56c5a950fd99
[clsql.git] / db-mysql / mysql-api.cl
1 ;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-
2 ;;;; *************************************************************************
3 ;;;; FILE IDENTIFICATION
4 ;;;;
5 ;;;; Name:          mysql.cl
6 ;;;; Purpose:       Low-level MySQL interface using UFFI
7 ;;;; Programmers:   Kevin M. Rosenberg based on 
8 ;;;;                Original code by Pierre R. Mai 
9 ;;;; Date Started:  Feb 2002
10 ;;;;
11 ;;;; $Id: mysql-api.cl,v 1.3 2002/09/30 02:45:16 kevin Exp $
12 ;;;;
13 ;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg
14 ;;;; and Copyright (c) 1999-2001 by Pierre R. Mai
15 ;;;;
16 ;;;; CLSQL users are granted the rights to distribute and use this software
17 ;;;; as governed by the terms of the Lisp Lesser GNU Public License
18 ;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL.
19 ;;;; *************************************************************************
20
21 (declaim (optimize (debug 3) (speed 3) (safety 1) (compilation-speed 0)))
22
23 (in-package :mysql)
24
25 ;;;; Modifications from original code
26 ;;;;  - Updated C-structures to conform to structures in MySQL 3.23.46
27 ;;;;  - Changed from CMUCL interface to UFFI
28 ;;;;  - Added and call a C-helper file to support 64-bit integers
29 ;;;;    that are used in a few routines.
30 ;;;;  - Removed all references to interiors of C-structions, this will
31 ;;;;    increase robustness when MySQL's internal structures change.
32  
33 ;;;; Type definitions
34
35 ;;; Basic Types
36
37 (uffi:def-foreign-type mysql-socket :int)
38 (uffi:def-foreign-type mysql-bool :char)
39 (uffi:def-foreign-type mysql-byte :unsigned-char)
40
41 (uffi:def-enum mysql-net-type
42     (:tcp-ip
43      :socket
44      :named-pipe))
45
46 (uffi:def-struct mysql-net
47     (vio :pointer-void)
48   (fd mysql-socket)
49   (fcntl :int)
50   (buff (* :unsigned-char))
51   (buff-end (* :unsigned-char))
52   (write-pos (* :unsigned-char))
53   (read-pos (* :unsigned-char))
54   (last-error (:array :char 200))
55   (last-errno :unsigned-int)
56   (max-packet :unsigned-int)
57   (timeout :unsigned-int)
58   (pkt-nr :unsigned-int)
59   (error mysql-bool)
60   (return-errno mysql-bool)
61   (compress mysql-bool)
62   (no-send-ok mysql-bool)
63   (remain-in-buf :unsigned-long)
64   (length :unsigned-long)
65   (buf-length :unsigned-long)
66   (where-b :unsigned-long)
67   (return-status (* :unsigned-int))
68   (reading-or-writing :unsigned-char)
69   (save-char :char))
70
71 ;;; Mem-Root
72 (uffi:def-struct mysql-used-mem
73     (next :pointer-self)
74   (left :unsigned-int)
75   (size :unsigned-int))
76
77 (uffi:def-struct mysql-mem-root
78     (free (:struct-pointer mysql-used-mem))
79   (used (:struct-pointer mysql-used-mem))
80   (pre-alloc (:struct-pointer mysql-used-mem))
81   (min-alloc :unsigned-int)
82   (block-size :unsigned-int)
83   (error-handler :pointer-void))
84
85 ;;; MYSQL-FIELD
86 (uffi:def-enum mysql-field-types
87     (:decimal
88      :tiny
89      :short
90      :long
91      :float
92      :double
93      :null
94      :timestamp
95      :longlong
96      :int24
97      :date
98      :time
99      :datetime
100      :year
101      :newdate
102      (:enum 247)
103      (:set 248)
104      (:tiny-blob 249)
105      (:medium-blob 250)
106      (:long-blob 251)
107      (:blob 252)
108      (:var-string 253)
109      (:string 254)))
110   
111 (uffi:def-struct mysql-field
112     (name (* :char))
113   (table (* :char))
114   (def (* :char))
115   (type mysql-field-types)
116   (length :unsigned-int)
117   (max-length :unsigned-int)
118   (flags :unsigned-int)
119   (decimals :unsigned-int))
120
121 ;;; MYSQL-ROWS
122
123 (uffi:def-array-pointer mysql-row (* :unsigned-char))
124
125 (uffi:def-array-pointer mysql-field-vector (* mysql-field))
126
127 (uffi:def-foreign-type mysql-field-offset :unsigned-int)
128
129 (uffi:def-struct mysql-rows
130     (next :pointer-self)
131   (data mysql-row))
132
133 (uffi:def-foreign-type mysql-row-offset (:struct-pointer mysql-rows))
134
135 (uffi:def-struct mysql-data
136     (rows-high32 :unsigned-long)
137   (rows-low32 :unsigned-long)
138   (fields :unsigned-int)
139   (data (:struct-pointer mysql-rows))
140   (alloc (:struct mysql-mem-root)))
141
142 ;;; MYSQL
143 (uffi:def-struct mysql-options
144     (connect-timeout :unsigned-int)
145   (client-flag :unsigned-int)
146   (compress mysql-bool)
147   (named-pipe mysql-bool)
148   (port :unsigned-int)
149   (host (* :char))
150   (init-command (* :char))
151   (user (* :char))
152   (password (* :char))
153   (unix-socket (* :char))
154   (db (* :char))
155   (my-cnf-file (* :char))
156   (my-cnf-group (* :char))
157   (charset-dir (* :char))
158   (charset-name (* :char))
159   (use-ssl mysql-bool)
160   (ssl-key (* :char))
161   (ssl-cert (* :char))
162   (ssl-ca (* :char))
163   (ssl-capath (* :char)))
164
165 (uffi:def-enum mysql-option
166     (:connect-timeout
167      :compress
168      :named-pipe
169      :init-command
170      :read-default-file
171      :read-default-group))
172
173 (uffi:def-enum mysql-status
174     (:ready 
175      :get-result
176      :use-result))
177
178 (uffi:def-struct mysql-mysql
179     (net (:struct mysql-net))
180   (connected-fd (* :char))
181   (host (* :char))
182   (user (* :char))
183   (passwd (* :char))
184   (unix-socket (* :char))
185   (server-version (* :char))
186   (host-info (* :char))
187   (info (* :char))
188   (db (* :char))
189   (port :unsigned-int)
190   (client-flag :unsigned-int)
191   (server-capabilities :unsigned-int)
192   (protocol-version :unsigned-int)
193   (field-count :unsigned-int)
194   (server-status :unsigned-int)
195   (thread-id :unsigned-long)
196   (affected-rows-high32 :unsigned-long)
197   (affected-rows-low32 :unsigned-long)
198   (insert-id-high32 :unsigned-long)
199   (insert-id-low32 :unsigned-long)
200   (extra-info-high32 :unsigned-long)
201   (extra-info-low32 :unsigned-long)
202   (packet-length :unsigned-long)
203   (status mysql-status)
204   (fields (:struct-pointer mysql-field))
205   (field-alloc (:struct mysql-mem-root))
206   (free-me mysql-bool)
207   (reconnect mysql-bool)
208   (options (:struct mysql-options))
209   (scramble-buff (:array :char 9))
210   (charset :pointer-void)
211   (server-language :unsigned-int))
212
213
214 ;;; MYSQL-RES
215 (uffi:def-struct mysql-mysql-res
216     (row-count-high32 :unsigned-long)
217   (row-count-low32 :unsigned-long)
218   (field-count :unsigned-int)
219   (current-field :unsigned-int)
220   (fields (:struct-pointer mysql-field))
221   (data (:struct-pointer mysql-data))
222   (data-cursor (:struct-pointer mysql-rows))
223   (field-alloc (:struct mysql-mem-root))
224   (row mysql-row)
225   (current-row mysql-row)
226   (lengths (* :unsigned-long))
227   (handle (:struct-pointer mysql-mysql))
228   (eof mysql-bool))
229
230 ;;;; The Foreign C routines
231 (declaim (inline mysql-init))
232 (uffi:def-function "mysql_init"
233   ((mysql (* mysql-mysql)))
234   :module "mysql" 
235   :returning (* mysql-mysql))
236
237 (declaim (inline mysql-connect))
238 (uffi:def-function "mysql_connect"
239     ((mysql (* mysql-mysql))
240      (host :cstring)
241      (user :cstring)
242      (passwd :cstring))
243   :module "mysql"
244   :returning (* mysql-mysql))
245
246 ;; Need to comment this out for LW 4.2.6
247 ;; ? bug in LW version
248 ;;(declaim (inline mysql-real-connect))
249 (uffi:def-function "mysql_real_connect"
250     ((mysql (* mysql-mysql))
251      (host :cstring)
252      (user :cstring)
253      (passwd :cstring)
254      (db :cstring)
255      (port :unsigned-int)
256      (unix-socket :cstring)
257      (clientflag :unsigned-int))
258   :module "mysql"
259   :returning (* mysql-mysql))
260
261 (declaim (inline mysql-close))
262 (uffi:def-function "mysql_close"
263     ((sock (* mysql-mysql)))
264   :module "mysql"
265   :returning :void)
266
267 (declaim (inline mysql-select-db))
268 (uffi:def-function "mysql_select_db"
269   ((mysql (* mysql-mysql))
270    (db :cstring))
271   :module "mysql"
272   :returning :int)
273
274 (declaim (inline mysql-query))
275 (uffi:def-function "mysql_query"
276     ((mysql (* mysql-mysql))
277      (query :cstring))
278   :module "mysql"
279   :returning :int)
280
281  ;;; I doubt that this function is really useful for direct Lisp usage,
282 ;;; but it is here for completeness...
283
284 (declaim (inline mysql-real-query))
285 (uffi:def-function "mysql_real_query"
286     ((mysql (* mysql-mysql))
287      (query :cstring)
288      (length :unsigned-int))
289   :module "mysql"
290   :returning :int)
291
292 (declaim (inline mysql-create-db))
293 (uffi:def-function "mysql_create_db"
294   ((mysql (* mysql-mysql))
295    (db :cstring))
296   :module "mysql"
297   :returning :int)
298
299 (declaim (inline mysql-drop-db))
300 (uffi:def-function "mysql_drop_db"
301     ((mysql (* mysql-mysql))
302      (db :cstring))
303   :module "mysql"
304   :returning :int)
305
306 (declaim (inline mysql-shutdown))
307 (uffi:def-function "mysql_shutdown"
308   ((mysql (* mysql-mysql)))
309   :module "mysql"
310   :returning :int)
311
312 (declaim (inline mysql-dump-debug-info))
313 (uffi:def-function "mysql_dump_debug_info"
314   ((mysql (* mysql-mysql)))
315   :module "mysql"
316   :returning :int)
317
318 (declaim (inline mysql-refresh))
319 (uffi:def-function "mysql_refresh"
320   ((mysql (* mysql-mysql))
321    (refresh-options :unsigned-int))
322   :module "mysql"
323   :returning :int)
324
325 (declaim (inline mysql-kill))
326 (uffi:def-function "mysql_kill"
327     ((mysql (* mysql-mysql))
328      (pid :unsigned-long))
329   :module "mysql"
330   :returning :int)
331
332 (declaim (inline mysql-ping))
333 (uffi:def-function "mysql_ping"
334     ((mysql (* mysql-mysql)))
335   :module "mysql"
336   :returning :int)
337
338 (declaim (inline mysql-stat))
339 (uffi:def-function "mysql_stat"
340   ((mysql (* mysql-mysql)))
341   :module "mysql"
342   :returning :cstring)
343
344 (declaim (inline mysql-get-server-info))
345 (uffi:def-function "mysql_get_server_info"
346     ((mysql (* mysql-mysql)))
347   :module "mysql"
348   :returning :cstring)
349
350 (declaim (inline mysql-get-client-info))
351 (uffi:def-function "mysql_get_client_info"
352     ()
353   :module "mysql"
354   :returning :cstring)
355
356 (declaim (inline mysql-get-host-info))
357 (uffi:def-function "mysql_get_host_info"
358     ((mysql (* mysql-mysql)))
359   :module "mysql"
360   :returning :cstring)
361
362 (declaim (inline mysql-get-proto-info))
363 (uffi:def-function "mysql_get_proto_info"
364   ((mysql (* mysql-mysql)))
365   :module "mysql"
366   :returning :unsigned-int)
367
368 (declaim (inline mysql-list-dbs))
369 (uffi:def-function "mysql_list_dbs"
370   ((mysql (* mysql-mysql))
371    (wild :cstring))
372   :module "mysql"
373   :returning (* mysql-mysql-res))
374
375 (declaim (inline mysql-list-tables))
376 (uffi:def-function "mysql_list_tables"
377   ((mysql (* mysql-mysql))
378    (wild :cstring))
379   :module "mysql"
380   :returning (* mysql-mysql-res))
381
382 (declaim (inline mysql-list-fields))
383 (uffi:def-function "mysql_list_fields"
384   ((mysql (* mysql-mysql))
385    (table :cstring)
386    (wild :cstring))
387   :module "mysql"
388   :returning (* mysql-mysql-res))
389
390 (declaim (inline mysql-list-processes))
391 (uffi:def-function "mysql_list_processes"
392   ((mysql (* mysql-mysql)))
393   :module "mysql"
394   :returning (* mysql-mysql-res))
395
396 (declaim (inline mysql-store-result))
397 (uffi:def-function "mysql_store_result"
398   ((mysql (* mysql-mysql)))
399   :module "mysql"
400   :returning (* mysql-mysql-res))
401
402 (declaim (inline mysql-use-result))
403 (uffi:def-function "mysql_use_result"
404   ((mysql (* mysql-mysql)))
405   :module "mysql"
406   :returning (* mysql-mysql-res))
407
408 (declaim (inline mysql-options))
409 (uffi:def-function "mysql_options"
410   ((mysql (* mysql-mysql))
411    (option mysql-option)
412    (arg :cstring))
413   :module "mysql"
414   :returning :int)
415
416 (declaim (inline mysql-free-result))
417 (uffi:def-function "mysql_free_result"
418     ((res (* mysql-mysql-res)))
419   :module "mysql"
420   :returning :void)
421
422 (declaim (inline mysql-row-seek))
423 (uffi:def-function "mysql_row_seek"
424   ((res (* mysql-mysql-res))
425    (offset mysql-row-offset))
426   :module "mysql"
427   :returning mysql-row-offset)
428
429 (declaim (inline mysql-field-seek))
430 (uffi:def-function "mysql_field_seek"
431   ((res (* mysql-mysql-res))
432   (offset mysql-field-offset))
433   :module "mysql"
434   :returning mysql-field-offset)
435
436 (declaim (inline mysql-fetch-row))
437 (uffi:def-function "mysql_fetch_row"
438     ((res (* mysql-mysql-res)))
439   :module "mysql"
440   :returning (* (* :unsigned-char)))
441
442 (declaim (inline mysql-fetch-lengths))
443 (uffi:def-function "mysql_fetch_lengths"
444   ((res (* mysql-mysql-res)))
445   :module "mysql"
446   :returning (* :unsigned-long))
447
448 (declaim (inline mysql-fetch-field))
449 (uffi:def-function "mysql_fetch_field"
450   ((res (* mysql-mysql-res)))
451   :module "mysql"
452   :returning (* mysql-field))
453
454 (declaim (inline mysql-fetch-fields))
455 (uffi:def-function "mysql_fetch_fields"
456   ((res (* mysql-mysql-res)))
457   :module "mysql"
458   :returning (* mysql-field))
459
460 (declaim (inline mysql-fetch-field-direct))
461 (uffi:def-function "mysql_fetch_field_direct"
462   ((res (* mysql-mysql-res))
463    (field-num :unsigned-int))
464   :module "mysql"
465   :returning (* mysql-field))
466
467 (declaim (inline mysql-escape-string))
468 (uffi:def-function "mysql_escape_string"
469     ((to :cstring)
470      (from :cstring)
471      (length :unsigned-int))
472   :module "mysql"
473   :returning :unsigned-int)
474
475 (declaim (inline mysql-debug))
476 (uffi:def-function "mysql_debug"
477     ((debug :cstring))
478   :module "mysql"
479   :returning :void)
480
481 (declaim (inline clsql-mysql-num-rows))
482 (uffi:def-function "clsql_mysql_num_rows"
483     ((res (* mysql-mysql-res))
484      (p-high32 (* :unsigned-int)))
485   :module "clsql-mysql"
486   :returning :unsigned-int)
487
488
489 ;;;; Equivalents of C Macro definitions for accessing various fields
490 ;;;; in the internal MySQL Datastructures
491
492
493 (declaim (inline mysql-num-rows))
494 (defun mysql-num-rows (res)
495   (uffi:with-foreign-object (p-high32 :unsigned-int)
496     (let ((low32 (clsql-mysql-num-rows res p-high32))
497           (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
498       (if (zerop high32)
499           low32
500         (make-64-bit-integer high32 low32)))))
501
502 (uffi:def-function "clsql_mysql_affected_rows"
503     ((mysql (* mysql-mysql))
504      (p-high32 (* :unsigned-int)))
505   :returning :unsigned-int
506   :module "clsql-mysql")
507
508 (defun mysql-affected-rows (mysql)
509   (uffi:with-foreign-object (p-high32 :unsigned-int)
510     (let ((low32 (clsql-mysql-affected-rows mysql p-high32))
511           (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
512       (if (zerop high32)
513           low32
514         (make-64-bit-integer high32 low32)))))
515
516 (uffi:def-function "clsql_mysql_insert_id"
517     ((res (* mysql-mysql))
518      (p-high32 (* :unsigned-int)))
519   :returning :unsigned-int
520   :module "clsql-mysql")
521
522 (defun mysql-insert-id (mysql)
523   (uffi:with-foreign-object (p-high32 :unsigned-int)
524   (let ((low32 (clsql-mysql-insert-id mysql p-high32))
525         (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
526     (if (zerop high32)
527         low32
528       (make-64-bit-integer high32 low32)))))
529
530
531 (declaim (inline mysql-num-fields))
532 (uffi:def-function "mysql_num_fields" 
533   ((res (* mysql-mysql-res)))
534   :returning :unsigned-int
535   :module "mysql")
536                  
537 (declaim (inline clsql-mysql-eof))
538 (uffi:def-function ("mysql_eof" clsql-mysql-eof)
539   ((res (* mysql-mysql-res)))
540   :returning :char
541   :module "mysql")
542
543 (declaim (inline mysql-eof))
544 (defun mysql-eof (res)
545   (if (zerop (clsql-mysql-eof res))
546       nil
547     t))
548
549 (declaim (inline mysql-error))
550 (uffi:def-function ("mysql_error" mysql-error)
551   ((mysql (* mysql-mysql)))
552   :returning :cstring
553   :module "mysql")
554
555 (declaim (inline mysql-error-string))
556 (defun mysql-error-string (mysql)
557   (uffi:convert-from-cstring (mysql-error mysql)))
558
559 (declaim (inline mysql-errno))
560 (uffi:def-function "mysql_errno"
561   ((mysql (* mysql-mysql)))
562   :returning :unsigned-int
563   :module "mysql")
564
565 (declaim (inline mysql-info))
566 (uffi:def-function ("mysql_info" mysql-info)
567   ((mysql (* mysql-mysql)))
568   :returning :cstring
569   :module "mysql")
570
571 (declaim (inline mysql-info-string))
572 (defun mysql-info-string (mysql)
573   (uffi:convert-from-cstring (mysql-info mysql)))
574
575 (declaim (inline clsql-mysql-data-seek))
576 (uffi:def-function "clsql_mysql_data_seek"
577   ((res (* mysql-mysql-res))
578    (offset-high32 :unsigned-int)
579    (offset-low32 :unsigned-int))
580   :module "clsql-mysql"
581   :returning :void)
582
583
584 (defun mysql-data-seek (res offset)
585   (multiple-value-bind (high32 low32) (split-64-bit-integer offset)
586     (clsql-mysql-data-seek res high32 low32)))