r8801: v4 changes
[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 #-(or :mysql-client-v3 :mysql-client-v4)
110 (eval-when (:compile-toplevel :load-toplevel :execute)
111   (pushnew :mysql-client-v3 cl:*features*))
112
113 #+:mysql-client-v3
114 (uffi:def-struct mysql-field
115     (name (* :char))
116   (table (* :char))
117   (def (* :char))
118   (type mysql-field-types)
119   (length :unsigned-int)
120   (max-length :unsigned-int)
121   (flags :unsigned-int)
122   (decimals :unsigned-int))
123
124 ;; structure changed in mysql 4 client
125 #+:mysql-client-v4
126 (uffi:def-struct mysql-field
127     (name (* :char))
128   (table (* :char))
129   (org_table (* :char))
130   (db (* :char))
131   (def (* :char))
132   (length :unsigned-int)
133   (max-length :unsigned-int)
134   (flags :unsigned-int)
135   (decimals :unsigned-int)
136   (type mysql-field-types))
137
138 ;;; MYSQL-ROWS
139
140 (uffi:def-array-pointer mysql-row (* :unsigned-char))
141
142 (uffi:def-array-pointer mysql-field-vector (* mysql-field))
143
144 (uffi:def-foreign-type mysql-field-offset :unsigned-int)
145
146 (uffi:def-struct mysql-rows
147     (next :pointer-self)
148   (data mysql-row))
149
150 (uffi:def-foreign-type mysql-row-offset (:struct-pointer mysql-rows))
151
152 (uffi:def-struct mysql-data
153     (rows-high32 :unsigned-long)
154   (rows-low32 :unsigned-long)
155   (fields :unsigned-int)
156   (data (:struct-pointer mysql-rows))
157   (alloc (:struct mysql-mem-root)))
158
159 ;;; MYSQL
160 (uffi:def-struct mysql-options
161     (connect-timeout :unsigned-int)
162   (client-flag :unsigned-int)
163   (compress mysql-bool)
164   (named-pipe mysql-bool)
165   (port :unsigned-int)
166   (host (* :char))
167   (init-command (* :char))
168   (user (* :char))
169   (password (* :char))
170   (unix-socket (* :char))
171   (db (* :char))
172   (my-cnf-file (* :char))
173   (my-cnf-group (* :char))
174   (charset-dir (* :char))
175   (charset-name (* :char))
176   (use-ssl mysql-bool)
177   (ssl-key (* :char))
178   (ssl-cert (* :char))
179   (ssl-ca (* :char))
180   (ssl-capath (* :char)))
181
182 (uffi:def-enum mysql-option
183     (:connect-timeout
184      :compress
185      :named-pipe
186      :init-command
187      :read-default-file
188      :read-default-group))
189
190 (uffi:def-enum mysql-status
191     (:ready 
192      :get-result
193      :use-result))
194
195 (uffi:def-struct mysql-mysql
196     (net (:struct mysql-net))
197   (connected-fd (* :char))
198   (host (* :char))
199   (user (* :char))
200   (passwd (* :char))
201   (unix-socket (* :char))
202   (server-version (* :char))
203   (host-info (* :char))
204   (info (* :char))
205   (db (* :char))
206   (port :unsigned-int)
207   (client-flag :unsigned-int)
208   (server-capabilities :unsigned-int)
209   (protocol-version :unsigned-int)
210   (field-count :unsigned-int)
211   (server-status :unsigned-int)
212   (thread-id :unsigned-long)
213   (affected-rows-high32 :unsigned-long)
214   (affected-rows-low32 :unsigned-long)
215   (insert-id-high32 :unsigned-long)
216   (insert-id-low32 :unsigned-long)
217   (extra-info-high32 :unsigned-long)
218   (extra-info-low32 :unsigned-long)
219   (packet-length :unsigned-long)
220   (status mysql-status)
221   (fields (:struct-pointer mysql-field))
222   (field-alloc (:struct mysql-mem-root))
223   (free-me mysql-bool)
224   (reconnect mysql-bool)
225   (options (:struct mysql-options))
226   (scramble-buff (:array :char 9))
227   (charset :pointer-void)
228   (server-language :unsigned-int))
229
230
231 ;;; MYSQL-RES
232 (uffi:def-struct mysql-mysql-res
233     (row-count-high32 :unsigned-long)
234   (row-count-low32 :unsigned-long)
235   (field-count :unsigned-int)
236   (current-field :unsigned-int)
237   (fields (:struct-pointer mysql-field))
238   (data (:struct-pointer mysql-data))
239   (data-cursor (:struct-pointer mysql-rows))
240   (field-alloc (:struct mysql-mem-root))
241   (row mysql-row)
242   (current-row mysql-row)
243   (lengths (* :unsigned-long))
244   (handle (:struct-pointer mysql-mysql))
245   (eof mysql-bool))
246
247 ;;;; The Foreign C routines
248 (declaim (inline mysql-init))
249 (uffi:def-function "mysql_init"
250   ((mysql (* mysql-mysql)))
251   :module "mysql" 
252   :returning (* mysql-mysql))
253
254 #-mysql-client-v4
255 (declaim (inline mysql-connect))
256 #-mysql-client-v4
257 (uffi:def-function "mysql_connect"
258     ((mysql (* mysql-mysql))
259      (host :cstring)
260      (user :cstring)
261      (passwd :cstring))
262   :module "mysql"
263   :returning (* mysql-mysql))
264
265 ;; Need to comment this out for LW 4.2.6
266 ;; ? bug in LW version
267 ;;(declaim (inline mysql-real-connect))
268 (uffi:def-function "mysql_real_connect"
269     ((mysql (* mysql-mysql))
270      (host :cstring)
271      (user :cstring)
272      (passwd :cstring)
273      (db :cstring)
274      (port :unsigned-int)
275      (unix-socket :cstring)
276      (clientflag :unsigned-int))
277   :module "mysql"
278   :returning (* mysql-mysql))
279
280 (declaim (inline mysql-close))
281 (uffi:def-function "mysql_close"
282     ((sock (* mysql-mysql)))
283   :module "mysql"
284   :returning :void)
285
286 (declaim (inline mysql-select-db))
287 (uffi:def-function "mysql_select_db"
288   ((mysql (* mysql-mysql))
289    (db :cstring))
290   :module "mysql"
291   :returning :int)
292
293 (declaim (inline mysql-query))
294 (uffi:def-function "mysql_query"
295     ((mysql (* mysql-mysql))
296      (query :cstring))
297   :module "mysql"
298   :returning :int)
299
300  ;;; I doubt that this function is really useful for direct Lisp usage,
301 ;;; but it is here for completeness...
302
303 (declaim (inline mysql-real-query))
304 (uffi:def-function "mysql_real_query"
305     ((mysql (* mysql-mysql))
306      (query :cstring)
307      (length :unsigned-int))
308   :module "mysql"
309   :returning :int)
310
311 #-mysql-client-v4
312 (declaim (inline mysql-create-db))
313 #-mysql-client-v4
314 (uffi:def-function "mysql_create_db"
315   ((mysql (* mysql-mysql))
316    (db :cstring))
317   :module "mysql"
318   :returning :int)
319
320 #-mysql-client-v4
321 (declaim (inline mysql-drop-db))
322 #-mysql-client-v4
323 (uffi:def-function "mysql_drop_db"
324     ((mysql (* mysql-mysql))
325      (db :cstring))
326   :module "mysql"
327   :returning :int)
328
329 (declaim (inline mysql-shutdown))
330 (uffi:def-function "mysql_shutdown"
331   ((mysql (* mysql-mysql)))
332   :module "mysql"
333   :returning :int)
334
335 (declaim (inline mysql-dump-debug-info))
336 (uffi:def-function "mysql_dump_debug_info"
337   ((mysql (* mysql-mysql)))
338   :module "mysql"
339   :returning :int)
340
341 (declaim (inline mysql-refresh))
342 (uffi:def-function "mysql_refresh"
343   ((mysql (* mysql-mysql))
344    (refresh-options :unsigned-int))
345   :module "mysql"
346   :returning :int)
347
348 (declaim (inline mysql-kill))
349 (uffi:def-function "mysql_kill"
350     ((mysql (* mysql-mysql))
351      (pid :unsigned-long))
352   :module "mysql"
353   :returning :int)
354
355 (declaim (inline mysql-ping))
356 (uffi:def-function "mysql_ping"
357     ((mysql (* mysql-mysql)))
358   :module "mysql"
359   :returning :int)
360
361 (declaim (inline mysql-stat))
362 (uffi:def-function "mysql_stat"
363   ((mysql (* mysql-mysql)))
364   :module "mysql"
365   :returning :cstring)
366
367 (declaim (inline mysql-get-server-info))
368 (uffi:def-function "mysql_get_server_info"
369     ((mysql (* mysql-mysql)))
370   :module "mysql"
371   :returning :cstring)
372
373 (declaim (inline mysql-get-client-info))
374 (uffi:def-function "mysql_get_client_info"
375     ()
376   :module "mysql"
377   :returning :cstring)
378
379 (declaim (inline mysql-get-host-info))
380 (uffi:def-function "mysql_get_host_info"
381     ((mysql (* mysql-mysql)))
382   :module "mysql"
383   :returning :cstring)
384
385 (declaim (inline mysql-get-proto-info))
386 (uffi:def-function "mysql_get_proto_info"
387   ((mysql (* mysql-mysql)))
388   :module "mysql"
389   :returning :unsigned-int)
390
391 (declaim (inline mysql-list-dbs))
392 (uffi:def-function "mysql_list_dbs"
393   ((mysql (* mysql-mysql))
394    (wild :cstring))
395   :module "mysql"
396   :returning (* mysql-mysql-res))
397
398 (declaim (inline mysql-list-tables))
399 (uffi:def-function "mysql_list_tables"
400   ((mysql (* mysql-mysql))
401    (wild :cstring))
402   :module "mysql"
403   :returning (* mysql-mysql-res))
404
405 (declaim (inline mysql-list-fields))
406 (uffi:def-function "mysql_list_fields"
407   ((mysql (* mysql-mysql))
408    (table :cstring)
409    (wild :cstring))
410   :module "mysql"
411   :returning (* mysql-mysql-res))
412
413 (declaim (inline mysql-list-processes))
414 (uffi:def-function "mysql_list_processes"
415   ((mysql (* mysql-mysql)))
416   :module "mysql"
417   :returning (* mysql-mysql-res))
418
419 (declaim (inline mysql-store-result))
420 (uffi:def-function "mysql_store_result"
421   ((mysql (* mysql-mysql)))
422   :module "mysql"
423   :returning (* mysql-mysql-res))
424
425 (declaim (inline mysql-use-result))
426 (uffi:def-function "mysql_use_result"
427   ((mysql (* mysql-mysql)))
428   :module "mysql"
429   :returning (* mysql-mysql-res))
430
431 (declaim (inline mysql-options))
432 (uffi:def-function "mysql_options"
433   ((mysql (* mysql-mysql))
434    (option mysql-option)
435    (arg :cstring))
436   :module "mysql"
437   :returning :int)
438
439 (declaim (inline mysql-free-result))
440 (uffi:def-function "mysql_free_result"
441     ((res (* mysql-mysql-res)))
442   :module "mysql"
443   :returning :void)
444
445 (declaim (inline mysql-row-seek))
446 (uffi:def-function "mysql_row_seek"
447   ((res (* mysql-mysql-res))
448    (offset mysql-row-offset))
449   :module "mysql"
450   :returning mysql-row-offset)
451
452 (declaim (inline mysql-field-seek))
453 (uffi:def-function "mysql_field_seek"
454   ((res (* mysql-mysql-res))
455   (offset mysql-field-offset))
456   :module "mysql"
457   :returning mysql-field-offset)
458
459 (declaim (inline mysql-fetch-row))
460 (uffi:def-function "mysql_fetch_row"
461     ((res (* mysql-mysql-res)))
462   :module "mysql"
463   :returning (* (* :unsigned-char)))
464
465 (declaim (inline mysql-fetch-lengths))
466 (uffi:def-function "mysql_fetch_lengths"
467   ((res (* mysql-mysql-res)))
468   :module "mysql"
469   :returning (* :unsigned-long))
470
471 (declaim (inline mysql-fetch-field))
472 (uffi:def-function "mysql_fetch_field"
473   ((res (* mysql-mysql-res)))
474   :module "mysql"
475   :returning (* mysql-field))
476
477 (declaim (inline mysql-fetch-fields))
478 (uffi:def-function "mysql_fetch_fields"
479   ((res (* mysql-mysql-res)))
480   :module "mysql"
481   :returning (* mysql-field))
482
483 (declaim (inline mysql-fetch-field-direct))
484 (uffi:def-function "mysql_fetch_field_direct"
485   ((res (* mysql-mysql-res))
486    (field-num :unsigned-int))
487   :module "mysql"
488   :returning (* mysql-field))
489
490 (declaim (inline mysql-escape-string))
491 (uffi:def-function "mysql_escape_string"
492     ((to :cstring)
493      (from :cstring)
494      (length :unsigned-int))
495   :module "mysql"
496   :returning :unsigned-int)
497
498 (declaim (inline mysql-debug))
499 (uffi:def-function "mysql_debug"
500     ((debug :cstring))
501   :module "mysql"
502   :returning :void)
503
504 (declaim (inline clsql-mysql-num-rows))
505 (uffi:def-function "clsql_mysql_num_rows"
506     ((res (* mysql-mysql-res))
507      (p-high32 (* :unsigned-int)))
508   :module "clsql-mysql"
509   :returning :unsigned-int)
510
511
512 ;;;; Equivalents of C Macro definitions for accessing various fields
513 ;;;; in the internal MySQL Datastructures
514
515
516 (declaim (inline mysql-num-rows))
517 (defun mysql-num-rows (res)
518   (uffi:with-foreign-object (p-high32 :unsigned-int)
519     (let ((low32 (clsql-mysql-num-rows res p-high32))
520           (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
521       (if (zerop high32)
522           low32
523         (make-64-bit-integer high32 low32)))))
524
525 (uffi:def-function "clsql_mysql_affected_rows"
526     ((mysql (* mysql-mysql))
527      (p-high32 (* :unsigned-int)))
528   :returning :unsigned-int
529   :module "clsql-mysql")
530
531 (defun mysql-affected-rows (mysql)
532   (uffi:with-foreign-object (p-high32 :unsigned-int)
533     (let ((low32 (clsql-mysql-affected-rows mysql p-high32))
534           (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
535       (if (zerop high32)
536           low32
537         (make-64-bit-integer high32 low32)))))
538
539 (uffi:def-function "clsql_mysql_insert_id"
540     ((res (* mysql-mysql))
541      (p-high32 (* :unsigned-int)))
542   :returning :unsigned-int
543   :module "clsql-mysql")
544
545 (defun mysql-insert-id (mysql)
546   (uffi:with-foreign-object (p-high32 :unsigned-int)
547   (let ((low32 (clsql-mysql-insert-id mysql p-high32))
548         (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
549     (if (zerop high32)
550         low32
551       (make-64-bit-integer high32 low32)))))
552
553
554 (declaim (inline mysql-num-fields))
555 (uffi:def-function "mysql_num_fields" 
556   ((res (* mysql-mysql-res)))
557   :returning :unsigned-int
558   :module "mysql")
559                  
560 (declaim (inline clsql-mysql-eof))
561 (uffi:def-function ("mysql_eof" clsql-mysql-eof)
562   ((res (* mysql-mysql-res)))
563   :returning :char
564   :module "mysql")
565
566 (declaim (inline mysql-eof))
567 (defun mysql-eof (res)
568   (if (zerop (clsql-mysql-eof res))
569       nil
570     t))
571
572 (declaim (inline mysql-error))
573 (uffi:def-function ("mysql_error" mysql-error)
574   ((mysql (* mysql-mysql)))
575   :returning :cstring
576   :module "mysql")
577
578 (declaim (inline mysql-error-string))
579 (defun mysql-error-string (mysql)
580   (uffi:convert-from-cstring (mysql-error mysql)))
581
582 (declaim (inline mysql-errno))
583 (uffi:def-function "mysql_errno"
584   ((mysql (* mysql-mysql)))
585   :returning :unsigned-int
586   :module "mysql")
587
588 (declaim (inline mysql-info))
589 (uffi:def-function ("mysql_info" mysql-info)
590   ((mysql (* mysql-mysql)))
591   :returning :cstring
592   :module "mysql")
593
594 (declaim (inline mysql-info-string))
595 (defun mysql-info-string (mysql)
596   (uffi:convert-from-cstring (mysql-info mysql)))
597
598 (declaim (inline clsql-mysql-data-seek))
599 (uffi:def-function "clsql_mysql_data_seek"
600   ((res (* mysql-mysql-res))
601    (offset-high32 :unsigned-int)
602    (offset-low32 :unsigned-int))
603   :module "clsql-mysql"
604   :returning :void)
605
606
607 (defun mysql-data-seek (res offset)
608   (multiple-value-bind (high32 low32) (split-64-bit-integer offset)
609     (clsql-mysql-data-seek res high32 low32)))