r2753: move files
[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.1 2002/09/18 07:43:40 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 ;; Need to comment this out for LW 4.2.6
246 ;; ? bug in LW version
247 ;;(declaim (inline mysql-real-connect))
248 (uffi:def-function "mysql_real_connect"
249     ((mysql (* mysql-mysql))
250      (host :cstring)
251      (user :cstring)
252      (passwd :cstring)
253      (db :cstring)
254      (port :unsigned-int)
255      (unix-socket :cstring)
256      (clientflag :unsigned-int))
257   :module "mysql"
258   :returning (* mysql-mysql))
259
260 (declaim (inline mysql-close))
261 (uffi:def-function "mysql_close"
262     ((sock (* mysql-mysql)))
263   :module "mysql"
264   :returning :void)
265
266 (declaim (inline mysql-select-db))
267 (uffi:def-function "mysql_select_db"
268   ((mysql (* mysql-mysql))
269    (db :cstring))
270   :module "mysql"
271   :returning :int)
272
273 (declaim (inline mysql-query))
274 (uffi:def-function "mysql_query"
275     ((mysql (* mysql-mysql))
276      (query :cstring))
277   :module "mysql"
278   :returning :int)
279
280  ;;; I doubt that this function is really useful for direct Lisp usage,
281 ;;; but it is here for completeness...
282
283 (declaim (inline mysql-real-query))
284 (uffi:def-function "mysql_real_query"
285     ((mysql (* mysql-mysql))
286      (query :cstring)
287      (length :unsigned-int))
288   :module "mysql"
289   :returning :int)
290
291 (declaim (inline mysql-create-db))
292 (uffi:def-function "mysql_create_db"
293   ((mysql (* mysql-mysql))
294    (db :cstring))
295   :module "mysql"
296   :returning :int)
297
298 (declaim (inline mysql-drop-db))
299 (uffi:def-function "mysql_drop_db"
300     ((mysql (* mysql-mysql))
301      (db :cstring))
302   :module "mysql"
303   :returning :int)
304
305 (declaim (inline mysql-shutdown))
306 (uffi:def-function "mysql_shutdown"
307   ((mysql (* mysql-mysql)))
308   :module "mysql"
309   :returning :int)
310
311 (declaim (inline mysql-dump-debug-info))
312 (uffi:def-function "mysql_dump_debug_info"
313   ((mysql (* mysql-mysql)))
314   :module "mysql"
315   :returning :int)
316
317 (declaim (inline mysql-refresh))
318 (uffi:def-function "mysql_refresh"
319   ((mysql (* mysql-mysql))
320    (refresh-options :unsigned-int))
321   :module "mysql"
322   :returning :int)
323
324 (declaim (inline mysql-kill))
325 (uffi:def-function "mysql_kill"
326     ((mysql (* mysql-mysql))
327      (pid :unsigned-long))
328   :module "mysql"
329   :returning :int)
330
331 (declaim (inline mysql-ping))
332 (uffi:def-function "mysql_ping"
333     ((mysql (* mysql-mysql)))
334   :module "mysql"
335   :returning :int)
336
337 (declaim (inline mysql-stat))
338 (uffi:def-function "mysql_stat"
339   ((mysql (* mysql-mysql)))
340   :module "mysql"
341   :returning :cstring)
342
343 (declaim (inline mysql-get-server-info))
344 (uffi:def-function "mysql_get_server_info"
345     ((mysql (* mysql-mysql)))
346   :module "mysql"
347   :returning :cstring)
348
349 (declaim (inline mysql-get-client-info))
350 (uffi:def-function "mysql_get_client_info"
351     ()
352   :module "mysql"
353   :returning :cstring)
354
355 (declaim (inline mysql-get-host-info))
356 (uffi:def-function "mysql_get_host_info"
357     ((mysql (* mysql-mysql)))
358   :module "mysql"
359   :returning :cstring)
360
361 (declaim (inline mysql-get-proto-info))
362 (uffi:def-function "mysql_get_proto_info"
363   ((mysql (* mysql-mysql)))
364   :module "mysql"
365   :returning :unsigned-int)
366
367 (declaim (inline mysql-list-dbs))
368 (uffi:def-function "mysql_list_dbs"
369   ((mysql (* mysql-mysql))
370    (wild :cstring))
371   :module "mysql"
372   :returning (* mysql-mysql-res))
373
374 (declaim (inline mysql-list-tables))
375 (uffi:def-function "mysql_list_tables"
376   ((mysql (* mysql-mysql))
377    (wild :cstring))
378   :module "mysql"
379   :returning (* mysql-mysql-res))
380
381 (declaim (inline mysql-list-fields))
382 (uffi:def-function "mysql_list_fields"
383   ((mysql (* mysql-mysql))
384    (table :cstring)
385    (wild :cstring))
386   :module "mysql"
387   :returning (* mysql-mysql-res))
388
389 (declaim (inline mysql-list-processes))
390 (uffi:def-function "mysql_list_processes"
391   ((mysql (* mysql-mysql)))
392   :module "mysql"
393   :returning (* mysql-mysql-res))
394
395 (declaim (inline mysql-store-result))
396 (uffi:def-function "mysql_store_result"
397   ((mysql (* mysql-mysql)))
398   :module "mysql"
399   :returning (* mysql-mysql-res))
400
401 (declaim (inline mysql-use-result))
402 (uffi:def-function "mysql_use_result"
403   ((mysql (* mysql-mysql)))
404   :module "mysql"
405   :returning (* mysql-mysql-res))
406
407 (declaim (inline mysql-options))
408 (uffi:def-function "mysql_options"
409   ((mysql (* mysql-mysql))
410    (option mysql-option)
411    (arg :cstring))
412   :module "mysql"
413   :returning :int)
414
415 (declaim (inline mysql-free-result))
416 (uffi:def-function "mysql_free_result"
417     ((res (* mysql-mysql-res)))
418   :module "mysql"
419   :returning :void)
420
421 (declaim (inline mysql-row-seek))
422 (uffi:def-function "mysql_row_seek"
423   ((res (* mysql-mysql-res))
424    (offset mysql-row-offset))
425   :module "mysql"
426   :returning mysql-row-offset)
427
428 (declaim (inline mysql-field-seek))
429 (uffi:def-function "mysql_field_seek"
430   ((res (* mysql-mysql-res))
431   (offset mysql-field-offset))
432   :module "mysql"
433   :returning mysql-field-offset)
434
435 (declaim (inline mysql-fetch-row))
436 (uffi:def-function "mysql_fetch_row"
437     ((res (* mysql-mysql-res)))
438   :module "mysql"
439   :returning mysql-row)
440
441 (declaim (inline mysql-fetch-lengths))
442 (uffi:def-function "mysql_fetch_lengths"
443   ((res (* mysql-mysql-res)))
444   :module "mysql"
445   :returning (* :unsigned-long))
446
447 (declaim (inline mysql-fetch-field))
448 (uffi:def-function "mysql_fetch_field"
449   ((res (* mysql-mysql-res)))
450   :module "mysql"
451   :returning (* mysql-field))
452
453 (declaim (inline mysql-fetch-fields))
454 (uffi:def-function "mysql_fetch_fields"
455   ((res (* mysql-mysql-res)))
456   :module "mysql"
457   :returning mysql-field-vector)
458
459 (declaim (inline mysql-fetch-field-direct))
460 (uffi:def-function "mysql_fetch_field_direct"
461   ((res (* mysql-mysql-res))
462    (field-num :unsigned-int))
463   :module "mysql"
464   :returning (* mysql-field))
465
466 (declaim (inline mysql-escape-string))
467 (uffi:def-function "mysql_escape_string"
468     ((to :cstring)
469      (from :cstring)
470      (length :unsigned-int))
471   :module "mysql"
472   :returning :unsigned-int)
473
474 (declaim (inline mysql-debug))
475 (uffi:def-function "mysql_debug"
476     ((debug :cstring))
477   :module "mysql"
478   :returning :void)
479
480 (declaim (inline clsql-mysql-num-rows))
481 (uffi:def-function "clsql_mysql_num_rows"
482     ((res (* mysql-mysql-res))
483      (p-high32 (* :unsigned-int)))
484   :module "clsql-mysql"
485   :returning :unsigned-int)
486
487
488 ;;;; Equivalents of C Macro definitions for accessing various fields
489 ;;;; in the internal MySQL Datastructures
490
491
492 (declaim (inline mysql-num-rows))
493 (defun mysql-num-rows (res)
494   (uffi:with-foreign-object (p-high32 :unsigned-int)
495     (let ((low32 (clsql-mysql-num-rows res p-high32))
496           (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
497       (if (zerop high32)
498           low32
499         (make-64-bit-integer high32 low32)))))
500
501 (uffi:def-function "clsql_mysql_affected_rows"
502     ((mysql (* mysql-mysql))
503      (p-high32 (* :unsigned-int)))
504   :returning :unsigned-int
505   :module "clsql-mysql")
506
507 (defun mysql-affected-rows (mysql)
508   (uffi:with-foreign-object (p-high32 :unsigned-int)
509     (let ((low32 (clsql-mysql-affected-rows mysql 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_insert_id"
516     ((res (* mysql-mysql))
517      (p-high32 (* :unsigned-int)))
518   :returning :unsigned-int
519   :module "clsql-mysql")
520
521 (defun mysql-insert-id (mysql)
522   (uffi:with-foreign-object (p-high32 :unsigned-int)
523   (let ((low32 (clsql-mysql-insert-id 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
530 (declaim (inline mysql-num-fields))
531 (uffi:def-function "mysql_num_fields" 
532   ((res (* mysql-mysql-res)))
533   :returning :unsigned-int
534   :module "mysql")
535                  
536 (declaim (inline clsql-mysql-eof))
537 (uffi:def-function ("mysql_eof" clsql-mysql-eof)
538   ((res (* mysql-mysql-res)))
539   :returning :char
540   :module "mysql")
541
542 (declaim (inline mysql-eof))
543 (defun mysql-eof (res)
544   (if (zerop (clsql-mysql-eof res))
545       nil
546     t))
547
548 (declaim (inline mysql-error))
549 (uffi:def-function ("mysql_error" mysql-error)
550   ((mysql (* mysql-mysql)))
551   :returning :cstring
552   :module "mysql")
553
554 (declaim (inline mysql-error-string))
555 (defun mysql-error-string (mysql)
556   (uffi:convert-from-cstring (mysql-error mysql)))
557
558 (declaim (inline mysql-errno))
559 (uffi:def-function "mysql_errno"
560   ((mysql (* mysql-mysql)))
561   :returning :unsigned-int
562   :module "mysql")
563
564 (declaim (inline mysql-info))
565 (uffi:def-function ("mysql_info" mysql-info)
566   ((mysql (* mysql-mysql)))
567   :returning :cstring
568   :module "mysql")
569
570 (declaim (inline mysql-info-string))
571 (defun mysql-info-string (mysql)
572   (uffi:convert-from-cstring (mysql-info mysql)))
573
574 (declaim (inline clsql-mysql-data-seek))
575 (uffi:def-function "clsql_mysql_data_seek"
576   ((res (* mysql-mysql-res))
577    (offset-high32 :unsigned-int)
578    (offset-low32 :unsigned-int))
579   :module "clsql-mysql"
580   :returning :void)
581
582
583 (defun mysql-data-seek (res offset)
584   (multiple-value-bind (high32 low32) (split-64-bit-integer offset)
585     (clsql-mysql-data-seek res high32 low32)))
586