Version 4.0.6
[clsql/s11.git] / db-mysql / mysql-api.lisp
blob1f747f93c4e870d92522578e71925a96e63f702a
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 ;;;; This file, part of CLSQL, is Copyright (c) 2002-2009 by Kevin M. Rosenberg
12 ;;;; and Copyright (c) 1999-2001 by Pierre R. Mai
13 ;;;;
14 ;;;; CLSQL users are granted the rights to distribute and use this software
15 ;;;; as governed by the terms of the Lisp Lesser GNU Public License
16 ;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL.
17 ;;;; *************************************************************************
19 (in-package #:mysql)
21 ;;;; Modifications from original code
22 ;;;; - Updated C-structures to conform to structures in MySQL 3.23.46
23 ;;;; - Changed from CMUCL interface to UFFI
24 ;;;; - Added and call a C-helper file to support 64-bit integers
25 ;;;; that are used in a few routines.
26 ;;;; - Removed all references to interiors of C-structions, this will
27 ;;;; increase robustness when MySQL's internal structures change.
29 ;;;; Type definitions
31 ;;; Basic Types
33 (uffi:def-foreign-type mysql-socket :int)
34 (uffi:def-foreign-type mysql-bool :byte)
35 (uffi:def-foreign-type mysql-byte :unsigned-char)
37 (uffi:def-enum mysql-net-type
38 (:tcp-ip
39 :socket
40 :named-pipe))
42 (uffi:def-struct mysql-net
43 (vio :pointer-void)
44 (fd mysql-socket)
45 (fcntl :int)
46 (buff (* :unsigned-char))
47 (buff-end (* :unsigned-char))
48 (write-pos (* :unsigned-char))
49 (read-pos (* :unsigned-char))
50 (last-error (:array :char 200))
51 (last-errno :unsigned-int)
52 (max-packet :unsigned-int)
53 (timeout :unsigned-int)
54 (pkt-nr :unsigned-int)
55 (error mysql-bool)
56 (return-errno mysql-bool)
57 (compress mysql-bool)
58 (no-send-ok mysql-bool)
59 (remain-in-buf :unsigned-long)
60 (length :unsigned-long)
61 (buf-length :unsigned-long)
62 (where-b :unsigned-long)
63 (return-status (* :unsigned-int))
64 (reading-or-writing :unsigned-char)
65 (save-char :char))
67 ;;; Mem-Root
68 (uffi:def-struct mysql-used-mem
69 (next :pointer-self)
70 (left :unsigned-int)
71 (size :unsigned-int))
73 (uffi:def-struct mysql-mem-root
74 (free (:struct-pointer mysql-used-mem))
75 (used (:struct-pointer mysql-used-mem))
76 (pre-alloc (:struct-pointer mysql-used-mem))
77 (min-alloc :unsigned-int)
78 (block-size :unsigned-int)
79 (error-handler :pointer-void))
81 ;;; MYSQL-FIELD
82 (uffi:def-enum mysql-field-types
83 (:decimal
84 :tiny
85 :short
86 :long
87 :float
88 :double
89 :null
90 :timestamp
91 :longlong
92 :int24
93 :date
94 :time
95 :datetime
96 :year
97 :newdate
98 (:enum 247)
99 (:set 248)
100 (:tiny-blob 249)
101 (:medium-blob 250)
102 (:long-blob 251)
103 (:blob 252)
104 (:var-string 253)
105 (:string 254)
106 (:geometry 255)))
108 #+mysql-client-v3
109 (uffi:def-struct mysql-field
110 (name (* :char))
111 (table (* :char))
112 (def (* :char))
113 (type mysql-field-types)
114 (length :unsigned-int)
115 (max-length :unsigned-int)
116 (flags :unsigned-int)
117 (decimals :unsigned-int))
119 ;; structure changed in mysql 4 client
120 #+(and mysql-client-v4 (not mysql-client-v4.1))
121 (uffi:def-struct mysql-field
122 (name (* :char))
123 (table (* :char))
124 (org_table (* :char))
125 (db (* :char))
126 (def (* :char))
127 (length :unsigned-long)
128 (max-length :unsigned-long)
129 (flags :unsigned-int)
130 (decimals :unsigned-int)
131 (type mysql-field-types))
133 #+(or mysql-client-v4.1 mysql-client-v5)
134 (uffi:def-struct mysql-field
135 (name (* :char))
136 (org_name (* :char))
137 (table (* :char))
138 (org_table (* :char))
139 (db (* :char))
140 (catalog_db (* :char))
141 (def (* :char))
142 (length :unsigned-long)
143 (max-length :unsigned-long)
144 (name-length :unsigned-int)
145 (org-name-length :unsigned-int)
146 (table-length :unsigned-int)
147 (org-table-length :unsigned-int)
148 (db-length :unsigned-int)
149 (catalog-length :unsigned-int)
150 (def-length :unsigned-int)
151 (flags :unsigned-int)
152 (decimals :unsigned-int)
153 (charsetnr :unsigned-int)
154 (type mysql-field-types))
157 (uffi:def-struct mysql-time
158 (year :unsigned-int)
159 (month :unsigned-int)
160 (day :unsigned-int)
161 (hour :unsigned-int)
162 (minute :unsigned-int)
163 (second :unsigned-int)
164 (second-part :unsigned-long)
165 (neg mysql-bool)
166 (time-type :int))
168 ;;; MYSQL-ROWS
170 (uffi:def-array-pointer mysql-row (* :unsigned-char))
172 (uffi:def-array-pointer mysql-field-vector (* mysql-field))
174 (uffi:def-foreign-type mysql-field-offset :unsigned-int)
176 (uffi:def-struct mysql-rows
177 (next :pointer-self)
178 (data mysql-row))
180 (uffi:def-foreign-type mysql-row-offset (:struct-pointer mysql-rows))
182 (uffi:def-struct mysql-data
183 (rows-high32 :unsigned-long)
184 (rows-low32 :unsigned-long)
185 (fields :unsigned-int)
186 (data (:struct-pointer mysql-rows))
187 (alloc (:struct mysql-mem-root)))
189 ;;; MYSQL
190 (uffi:def-struct mysql-options
191 (connect-timeout :unsigned-int)
192 (client-flag :unsigned-int)
193 (compress mysql-bool)
194 (named-pipe mysql-bool)
195 (port :unsigned-int)
196 (host (* :char))
197 (init-command (* :char))
198 (user (* :char))
199 (password (* :char))
200 (unix-socket (* :char))
201 (db (* :char))
202 (my-cnf-file (* :char))
203 (my-cnf-group (* :char))
204 (charset-dir (* :char))
205 (charset-name (* :char))
206 (use-ssl mysql-bool)
207 (ssl-key (* :char))
208 (ssl-cert (* :char))
209 (ssl-ca (* :char))
210 (ssl-capath (* :char)))
212 (uffi:def-enum mysql-option
213 (:connect-timeout
214 :compress
215 :named-pipe
216 :init-command
217 :read-default-file
218 :read-default-group))
220 (uffi:def-enum mysql-status
221 (:ready
222 :get-result
223 :use-result))
225 (uffi:def-struct mysql-mysql
226 (net (:struct mysql-net))
227 (connected-fd (* :char))
228 (host (* :char))
229 (user (* :char))
230 (passwd (* :char))
231 (unix-socket (* :char))
232 (server-version (* :char))
233 (host-info (* :char))
234 (info (* :char))
235 (db (* :char))
236 (port :unsigned-int)
237 (client-flag :unsigned-int)
238 (server-capabilities :unsigned-int)
239 (protocol-version :unsigned-int)
240 (field-count :unsigned-int)
241 (server-status :unsigned-int)
242 (thread-id :unsigned-long)
243 (affected-rows-high32 :unsigned-long)
244 (affected-rows-low32 :unsigned-long)
245 (insert-id-high32 :unsigned-long)
246 (insert-id-low32 :unsigned-long)
247 (extra-info-high32 :unsigned-long)
248 (extra-info-low32 :unsigned-long)
249 (packet-length :unsigned-long)
250 (status mysql-status)
251 (fields (:struct-pointer mysql-field))
252 (field-alloc (:struct mysql-mem-root))
253 (free-me mysql-bool)
254 (reconnect mysql-bool)
255 (options (:struct mysql-options))
256 (scramble-buff (:array :char 9))
257 (charset :pointer-void)
258 (server-language :unsigned-int))
261 ;;; MYSQL-RES
262 (uffi:def-struct mysql-mysql-res
263 (row-count-high32 :unsigned-long)
264 (row-count-low32 :unsigned-long)
265 (field-count :unsigned-int)
266 (current-field :unsigned-int)
267 (fields (:struct-pointer mysql-field))
268 (data (:struct-pointer mysql-data))
269 (data-cursor (:struct-pointer mysql-rows))
270 (field-alloc (:struct mysql-mem-root))
271 (row mysql-row)
272 (current-row mysql-row)
273 (lengths (* :unsigned-long))
274 (handle (:struct-pointer mysql-mysql))
275 (eof mysql-bool))
277 #+(or mysql-client-v4.1 mysql-client-v5)
278 (uffi:def-enum mysql-field-types
279 (:ready
280 :get-result
281 :use-result))
283 #+(or mysql-client-v4.1 mysql-client-v5)
284 (uffi:def-struct mysql-bind
285 (length (* :unsigned-long))
286 (is-null (* mysql-bool))
287 (buffer :pointer-void)
288 (buffer-type :int)
289 (buffer-length :unsigned-long)
290 ;; internal use
291 (inter_buffer (* :unsigned-char))
292 (offset :unsigned-long)
293 (internal-length :unsigned-long)
294 (param-number :unsigned-int)
295 (pack-length :unsigned-int)
296 (is-signed mysql-bool)
297 (long-data-used mysql-bool)
298 (internal-is-null mysql-bool)
299 (store-param-func :pointer-void)
300 (fetch-result :pointer-void)
301 (skip-result :pointer-void))
303 ;;;; The Foreign C routines
304 (declaim (inline mysql-init))
305 (uffi:def-function "mysql_init"
306 ((mysql (* mysql-mysql)))
307 :module "mysql"
308 :returning (* mysql-mysql))
310 ;; Need to comment this out for LW 4.2.6
311 ;; ? bug in LW version
312 #-lispworks (declaim (inline mysql-real-connect))
313 (uffi:def-function "mysql_real_connect"
314 ((mysql (* mysql-mysql))
315 (host :cstring)
316 (user :cstring)
317 (passwd :cstring)
318 (db :cstring)
319 (port :unsigned-int)
320 (unix-socket :cstring)
321 (clientflag :unsigned-long))
322 :module "mysql"
323 :returning (* mysql-mysql))
325 (declaim (inline mysql-close))
326 (uffi:def-function "mysql_close"
327 ((sock (* mysql-mysql)))
328 :module "mysql"
329 :returning :void)
331 (declaim (inline mysql-select-db))
332 (uffi:def-function "mysql_select_db"
333 ((mysql (* mysql-mysql))
334 (db :cstring))
335 :module "mysql"
336 :returning :int)
338 (declaim (inline mysql-query))
339 (uffi:def-function "mysql_query"
340 ((mysql (* mysql-mysql))
341 (query :cstring))
342 :module "mysql"
343 :returning :int)
345 ;;; I doubt that this function is really useful for direct Lisp usage,
346 ;;; but it is here for completeness...
348 (declaim (inline mysql-real-query))
349 (uffi:def-function "mysql_real_query"
350 ((mysql (* mysql-mysql))
351 (query :cstring)
352 (length :unsigned-int))
353 :module "mysql"
354 :returning :int)
356 (declaim (inline mysql-shutdown))
357 (uffi:def-function "mysql_shutdown"
358 ((mysql (* mysql-mysql)))
359 :module "mysql"
360 :returning :int)
362 (declaim (inline mysql-dump-debug-info))
363 (uffi:def-function "mysql_dump_debug_info"
364 ((mysql (* mysql-mysql)))
365 :module "mysql"
366 :returning :int)
368 (declaim (inline mysql-refresh))
369 (uffi:def-function "mysql_refresh"
370 ((mysql (* mysql-mysql))
371 (refresh-options :unsigned-int))
372 :module "mysql"
373 :returning :int)
375 (declaim (inline mysql-kill))
376 (uffi:def-function "mysql_kill"
377 ((mysql (* mysql-mysql))
378 (pid :unsigned-long))
379 :module "mysql"
380 :returning :int)
382 (declaim (inline mysql-ping))
383 (uffi:def-function "mysql_ping"
384 ((mysql (* mysql-mysql)))
385 :module "mysql"
386 :returning :int)
388 (declaim (inline mysql-stat))
389 (uffi:def-function "mysql_stat"
390 ((mysql (* mysql-mysql)))
391 :module "mysql"
392 :returning :cstring)
394 (declaim (inline mysql-get-server-info))
395 (uffi:def-function "mysql_get_server_info"
396 ((mysql (* mysql-mysql)))
397 :module "mysql"
398 :returning :cstring)
400 (declaim (inline mysql-get-host-info))
401 (uffi:def-function "mysql_get_host_info"
402 ((mysql (* mysql-mysql)))
403 :module "mysql"
404 :returning :cstring)
406 (declaim (inline mysql-get-proto-info))
407 (uffi:def-function "mysql_get_proto_info"
408 ((mysql (* mysql-mysql)))
409 :module "mysql"
410 :returning :unsigned-int)
412 (declaim (inline mysql-list-dbs))
413 (uffi:def-function "mysql_list_dbs"
414 ((mysql (* mysql-mysql))
415 (wild :cstring))
416 :module "mysql"
417 :returning (* mysql-mysql-res))
419 (declaim (inline mysql-list-tables))
420 (uffi:def-function "mysql_list_tables"
421 ((mysql (* mysql-mysql))
422 (wild :cstring))
423 :module "mysql"
424 :returning (* mysql-mysql-res))
426 (declaim (inline mysql-list-fields))
427 (uffi:def-function "mysql_list_fields"
428 ((mysql (* mysql-mysql))
429 (table :cstring)
430 (wild :cstring))
431 :module "mysql"
432 :returning (* mysql-mysql-res))
434 (declaim (inline mysql-list-processes))
435 (uffi:def-function "mysql_list_processes"
436 ((mysql (* mysql-mysql)))
437 :module "mysql"
438 :returning (* mysql-mysql-res))
440 (declaim (inline mysql-store-result))
441 (uffi:def-function "mysql_store_result"
442 ((mysql (* mysql-mysql)))
443 :module "mysql"
444 :returning (* mysql-mysql-res))
446 (declaim (inline mysql-use-result))
447 (uffi:def-function "mysql_use_result"
448 ((mysql (* mysql-mysql)))
449 :module "mysql"
450 :returning (* mysql-mysql-res))
452 (declaim (inline mysql-options))
453 (uffi:def-function "mysql_options"
454 ((mysql (* mysql-mysql))
455 (option mysql-option)
456 (arg :cstring))
457 :module "mysql"
458 :returning :int)
460 (declaim (inline mysql-free-result))
461 (uffi:def-function "mysql_free_result"
462 ((res (* mysql-mysql-res)))
463 :module "mysql"
464 :returning :void)
466 (declaim (inline mysql-row-seek))
467 (uffi:def-function "mysql_row_seek"
468 ((res (* mysql-mysql-res))
469 (offset mysql-row-offset))
470 :module "mysql"
471 :returning mysql-row-offset)
473 (declaim (inline mysql-field-seek))
474 (uffi:def-function "mysql_field_seek"
475 ((res (* mysql-mysql-res))
476 (offset mysql-field-offset))
477 :module "mysql"
478 :returning mysql-field-offset)
480 (declaim (inline mysql-fetch-row))
481 (uffi:def-function "mysql_fetch_row"
482 ((res (* mysql-mysql-res)))
483 :module "mysql"
484 :returning (* (* :unsigned-char)))
486 (declaim (inline mysql-fetch-lengths))
487 (uffi:def-function "mysql_fetch_lengths"
488 ((res (* mysql-mysql-res)))
489 :module "mysql"
490 :returning (* :unsigned-long))
492 (declaim (inline mysql-fetch-field))
493 (uffi:def-function "mysql_fetch_field"
494 ((res (* mysql-mysql-res)))
495 :module "mysql"
496 :returning (* mysql-field))
498 (declaim (inline mysql-fetch-fields))
499 (uffi:def-function "mysql_fetch_fields"
500 ((res (* mysql-mysql-res)))
501 :module "mysql"
502 :returning (* mysql-field))
504 (declaim (inline mysql-fetch-field-direct))
505 (uffi:def-function "mysql_fetch_field_direct"
506 ((res (* mysql-mysql-res))
507 (field-num :unsigned-int))
508 :module "mysql"
509 :returning (* mysql-field))
511 (declaim (inline mysql-escape-string))
512 (uffi:def-function "mysql_escape_string"
513 ((to (* :unsigned-char))
514 (from (* :unsigned-char))
515 (length :unsigned-int))
516 :module "mysql"
517 :returning :unsigned-int)
519 (declaim (inline mysql-debug))
520 (uffi:def-function "mysql_debug"
521 ((debug :cstring))
522 :module "mysql"
523 :returning :void)
525 (declaim (inline clsql-mysql-num-rows))
526 (uffi:def-function "clsql_mysql_num_rows"
527 ((res (* mysql-mysql-res))
528 (p-high32 (* :unsigned-int)))
529 :module "clsql-mysql"
530 :returning :unsigned-int)
532 #+(or mysql-client-v4.1 mysql-client-v5)
533 (uffi:def-foreign-type mysql-stmt-ptr :pointer-void)
535 #+(or mysql-client-v4.1 mysql-client-v5)
536 (uffi:def-function "mysql_stmt_init"
537 ((res (* mysql-mysql-res)))
538 :module "clsql-mysql"
539 :returning mysql-stmt-ptr)
541 #+(or mysql-client-v4.1 mysql-client-v5)
542 (uffi:def-function "mysql_stmt_prepare"
543 ((stmt mysql-stmt-ptr)
544 (query :cstring)
545 (length :unsigned-long))
546 :module "clsql-mysql"
547 :returning :int)
549 #+(or mysql-client-v4.1 mysql-client-v5)
550 (uffi:def-function "mysql_stmt_param_count"
551 ((stmt mysql-stmt-ptr))
552 :module "clsql-mysql"
553 :returning :unsigned-int)
555 #+(or mysql-client-v4.1 mysql-client-v5)
556 (uffi:def-function "mysql_stmt_bind_param"
557 ((stmt mysql-stmt-ptr)
558 (bind (* mysql-bind)))
559 :module "clsql-mysql"
560 :returning :short)
562 #+(or mysql-client-v4.1 mysql-client-v5)
563 (uffi:def-function "mysql_stmt_bind_result"
564 ((stmt mysql-stmt-ptr)
565 (bind (* mysql-bind)))
566 :module "clsql-mysql"
567 :returning :short)
569 #+(or mysql-client-v4.1 mysql-client-v5)
570 (uffi:def-function "mysql_stmt_result_metadata"
571 ((stmt mysql-stmt-ptr))
572 :module "clsql-mysql"
573 :returning (* mysql-mysql-res))
576 #+(or mysql-client-v4.1 mysql-client-v5)
577 (uffi:def-function "mysql_stmt_execute"
578 ((stmt mysql-stmt-ptr))
579 :module "clsql-mysql"
580 :returning :int)
582 #+(or mysql-client-v4.1 mysql-client-v5)
583 (uffi:def-function "mysql_stmt_store_result"
584 ((stmt mysql-stmt-ptr))
585 :module "clsql-mysql"
586 :returning :int)
588 #+(or mysql-client-v4.1 mysql-client-v5)
589 (uffi:def-function "mysql_stmt_fetch"
590 ((stmt mysql-stmt-ptr))
591 :module "clsql-mysql"
592 :returning :int)
594 #+(or mysql-client-v4.1 mysql-client-v5)
595 (uffi:def-function "mysql_stmt_free_result"
596 ((stmt mysql-stmt-ptr))
597 :module "clsql-mysql"
598 :returning :short)
600 #+(or mysql-client-v4.1 mysql-client-v5)
601 (uffi:def-function "mysql_stmt_close"
602 ((stmt mysql-stmt-ptr))
603 :module "clsql-mysql"
604 :returning :short)
606 #+(or mysql-client-v4.1 mysql-client-v5)
607 (uffi:def-function "mysql_stmt_errno"
608 ((stmt mysql-stmt-ptr))
609 :module "clsql-mysql"
610 :returning :unsigned-int)
612 #+(or mysql-client-v4.1 mysql-client-v5)
613 (uffi:def-function "mysql_stmt_error"
614 ((stmt mysql-stmt-ptr))
615 :module "clsql-mysql"
616 :returning :cstring)
619 ;;;; Equivalents of C Macro definitions for accessing various fields
620 ;;;; in the internal MySQL Datastructures
623 (declaim (inline mysql-num-rows))
624 (defun mysql-num-rows (res)
625 (uffi:with-foreign-object (p-high32 :unsigned-int)
626 (let ((low32 (clsql-mysql-num-rows res p-high32))
627 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
628 (if (zerop high32)
629 low32
630 (make-64-bit-integer high32 low32)))))
632 (uffi:def-function "clsql_mysql_affected_rows"
633 ((mysql (* mysql-mysql))
634 (p-high32 (* :unsigned-int)))
635 :returning :unsigned-int
636 :module "clsql-mysql")
638 (defun mysql-affected-rows (mysql)
639 (uffi:with-foreign-object (p-high32 :unsigned-int)
640 (let ((low32 (clsql-mysql-affected-rows mysql p-high32))
641 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
642 (if (zerop high32)
643 low32
644 (make-64-bit-integer high32 low32)))))
646 (uffi:def-function "clsql_mysql_insert_id"
647 ((res (* mysql-mysql))
648 (p-high32 (* :unsigned-int)))
649 :returning :unsigned-int
650 :module "clsql-mysql")
652 (defun mysql-insert-id (mysql)
653 (uffi:with-foreign-object (p-high32 :unsigned-int)
654 (let ((low32 (clsql-mysql-insert-id mysql p-high32))
655 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
656 (if (zerop high32)
657 low32
658 (make-64-bit-integer high32 low32)))))
661 (declaim (inline mysql-num-fields))
662 (uffi:def-function "mysql_num_fields"
663 ((res (* mysql-mysql-res)))
664 :returning :unsigned-int
665 :module "mysql")
667 (declaim (inline clsql-mysql-eof))
668 (uffi:def-function ("mysql_eof" clsql-mysql-eof)
669 ((res (* mysql-mysql-res)))
670 :returning :char
671 :module "mysql")
673 (declaim (inline mysql-eof))
674 (defun mysql-eof (res)
675 (if (zerop (clsql-mysql-eof res))
679 (declaim (inline mysql-error))
680 (uffi:def-function ("mysql_error" mysql-error)
681 ((mysql (* mysql-mysql)))
682 :returning :cstring
683 :module "mysql")
685 (declaim (inline mysql-error-string))
686 (defun mysql-error-string (mysql)
687 (uffi:convert-from-cstring (mysql-error mysql)))
689 (declaim (inline mysql-errno))
690 (uffi:def-function "mysql_errno"
691 ((mysql (* mysql-mysql)))
692 :returning :unsigned-int
693 :module "mysql")
695 (declaim (inline mysql-info))
696 (uffi:def-function ("mysql_info" mysql-info)
697 ((mysql (* mysql-mysql)))
698 :returning :cstring
699 :module "mysql")
701 (declaim (inline mysql-info-string))
702 (defun mysql-info-string (mysql)
703 (uffi:convert-from-cstring (mysql-info mysql)))
705 (declaim (inline clsql-mysql-data-seek))
706 (uffi:def-function "clsql_mysql_data_seek"
707 ((res (* mysql-mysql-res))
708 (offset-high32 :unsigned-int)
709 (offset-low32 :unsigned-int))
710 :module "clsql-mysql"
711 :returning :void)
713 (defun mysql-data-seek (res offset)
714 (multiple-value-bind (high32 low32) (split-64-bit-integer offset)
715 (clsql-mysql-data-seek res high32 low32)))