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