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