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