1 ;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-
2 ;;;; *************************************************************************
3 ;;;; FILE IDENTIFICATION
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
13 ;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg
14 ;;;; and Copyright (c) 1999-2001 by Pierre R. Mai
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 ;;;; *************************************************************************
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.
35 (uffi:def-foreign-type mysql-socket
:int
)
36 (uffi:def-foreign-type mysql-bool
:byte
)
37 (uffi:def-foreign-type mysql-byte
:unsigned-char
)
39 (uffi:def-enum mysql-net-type
44 (uffi:def-struct mysql-net
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
)
58 (return-errno 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
)
70 (uffi:def-struct mysql-used-mem
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
))
84 (uffi:def-enum mysql-field-types
111 (uffi:def-struct mysql-field
115 (type mysql-field-types
)
116 (length :unsigned-int
)
117 (max-length :unsigned-int
)
118 (flags :unsigned-int
)
119 (decimals :unsigned-int
))
121 ;; structure changed in mysql 4 client
122 #+(and mysql-client-v4
(not mysql-client-v4.1
))
123 (uffi:def-struct mysql-field
126 (org_table (* :char
))
129 (length :unsigned-long
)
130 (max-length :unsigned-long
)
131 (flags :unsigned-int
)
132 (decimals :unsigned-int
)
133 (type mysql-field-types
))
135 #+(or mysql-client-v4.1 mysql-client-v5
)
136 (uffi:def-struct mysql-field
140 (org_table (* :char
))
142 (catalog_db (* :char
))
144 (length :unsigned-long
)
145 (max-length :unsigned-long
)
146 (name-length :unsigned-int
)
147 (org-name-length :unsigned-int
)
148 (table-length :unsigned-int
)
149 (org-table-length :unsigned-int
)
150 (db-length :unsigned-int
)
151 (catalog-length :unsigned-int
)
152 (def-length :unsigned-int
)
153 (flags :unsigned-int
)
154 (decimals :unsigned-int
)
155 (charsetnr :unsigned-int
)
156 (type mysql-field-types
))
159 (uffi:def-struct mysql-time
161 (month :unsigned-int
)
164 (minute :unsigned-int
)
165 (second :unsigned-int
)
166 (second-part :unsigned-long
)
172 (uffi:def-array-pointer mysql-row
(* :unsigned-char
))
174 (uffi:def-array-pointer mysql-field-vector
(* mysql-field
))
176 (uffi:def-foreign-type mysql-field-offset
:unsigned-int
)
178 (uffi:def-struct mysql-rows
182 (uffi:def-foreign-type mysql-row-offset
(:struct-pointer mysql-rows
))
184 (uffi:def-struct mysql-data
185 (rows-high32 :unsigned-long
)
186 (rows-low32 :unsigned-long
)
187 (fields :unsigned-int
)
188 (data (:struct-pointer mysql-rows
))
189 (alloc (:struct mysql-mem-root
)))
192 (uffi:def-struct mysql-options
193 (connect-timeout :unsigned-int
)
194 (client-flag :unsigned-int
)
195 (compress mysql-bool
)
196 (named-pipe mysql-bool
)
199 (init-command (* :char
))
202 (unix-socket (* :char
))
204 (my-cnf-file (* :char
))
205 (my-cnf-group (* :char
))
206 (charset-dir (* :char
))
207 (charset-name (* :char
))
212 (ssl-capath (* :char
)))
214 (uffi:def-enum mysql-option
220 :read-default-group
))
222 (uffi:def-enum mysql-status
227 (uffi:def-struct mysql-mysql
228 (net (:struct mysql-net
))
229 (connected-fd (* :char
))
233 (unix-socket (* :char
))
234 (server-version (* :char
))
235 (host-info (* :char
))
239 (client-flag :unsigned-int
)
240 (server-capabilities :unsigned-int
)
241 (protocol-version :unsigned-int
)
242 (field-count :unsigned-int
)
243 (server-status :unsigned-int
)
244 (thread-id :unsigned-long
)
245 (affected-rows-high32 :unsigned-long
)
246 (affected-rows-low32 :unsigned-long
)
247 (insert-id-high32 :unsigned-long
)
248 (insert-id-low32 :unsigned-long
)
249 (extra-info-high32 :unsigned-long
)
250 (extra-info-low32 :unsigned-long
)
251 (packet-length :unsigned-long
)
252 (status mysql-status
)
253 (fields (:struct-pointer mysql-field
))
254 (field-alloc (:struct mysql-mem-root
))
256 (reconnect mysql-bool
)
257 (options (:struct mysql-options
))
258 (scramble-buff (:array
:char
9))
259 (charset :pointer-void
)
260 (server-language :unsigned-int
))
264 (uffi:def-struct mysql-mysql-res
265 (row-count-high32 :unsigned-long
)
266 (row-count-low32 :unsigned-long
)
267 (field-count :unsigned-int
)
268 (current-field :unsigned-int
)
269 (fields (:struct-pointer mysql-field
))
270 (data (:struct-pointer mysql-data
))
271 (data-cursor (:struct-pointer mysql-rows
))
272 (field-alloc (:struct mysql-mem-root
))
274 (current-row mysql-row
)
275 (lengths (* :unsigned-long
))
276 (handle (:struct-pointer mysql-mysql
))
279 #+(or mysql-client-v4.1 mysql-client-v5
)
280 (uffi:def-enum mysql-field-types
285 #+(or mysql-client-v4.1 mysql-client-v5
)
286 (uffi:def-struct mysql-bind
287 (length (* :unsigned-long
))
288 (is-null (* mysql-bool
))
289 (buffer :pointer-void
)
291 (buffer-length :unsigned-long
)
293 (inter_buffer (* :unsigned-char
))
294 (offset :unsigned-long
)
295 (internal-length :unsigned-long
)
296 (param-number :unsigned-int
)
297 (pack-length :unsigned-int
)
298 (is-signed mysql-bool
)
299 (long-data-used mysql-bool
)
300 (internal-is-null mysql-bool
)
301 (store-param-func :pointer-void
)
302 (fetch-result :pointer-void
)
303 (skip-result :pointer-void
))
305 ;;;; The Foreign C routines
306 (declaim (inline mysql-init
))
307 (uffi:def-function
"mysql_init"
308 ((mysql (* mysql-mysql
)))
310 :returning
(* mysql-mysql
))
312 ;; Need to comment this out for LW 4.2.6
313 ;; ? bug in LW version
314 #-lispworks
(declaim (inline mysql-real-connect
))
315 (uffi:def-function
"mysql_real_connect"
316 ((mysql (* mysql-mysql
))
322 (unix-socket :cstring
)
323 (clientflag :unsigned-long
))
325 :returning
(* mysql-mysql
))
327 (declaim (inline mysql-close
))
328 (uffi:def-function
"mysql_close"
329 ((sock (* mysql-mysql
)))
333 (declaim (inline mysql-select-db
))
334 (uffi:def-function
"mysql_select_db"
335 ((mysql (* mysql-mysql
))
340 (declaim (inline mysql-query
))
341 (uffi:def-function
"mysql_query"
342 ((mysql (* mysql-mysql
))
347 ;;; I doubt that this function is really useful for direct Lisp usage,
348 ;;; but it is here for completeness...
350 (declaim (inline mysql-real-query
))
351 (uffi:def-function
"mysql_real_query"
352 ((mysql (* mysql-mysql
))
354 (length :unsigned-int
))
358 (declaim (inline mysql-shutdown
))
359 (uffi:def-function
"mysql_shutdown"
360 ((mysql (* mysql-mysql
)))
364 (declaim (inline mysql-dump-debug-info
))
365 (uffi:def-function
"mysql_dump_debug_info"
366 ((mysql (* mysql-mysql
)))
370 (declaim (inline mysql-refresh
))
371 (uffi:def-function
"mysql_refresh"
372 ((mysql (* mysql-mysql
))
373 (refresh-options :unsigned-int
))
377 (declaim (inline mysql-kill
))
378 (uffi:def-function
"mysql_kill"
379 ((mysql (* mysql-mysql
))
380 (pid :unsigned-long
))
384 (declaim (inline mysql-ping
))
385 (uffi:def-function
"mysql_ping"
386 ((mysql (* mysql-mysql
)))
390 (declaim (inline mysql-stat
))
391 (uffi:def-function
"mysql_stat"
392 ((mysql (* mysql-mysql
)))
396 (declaim (inline mysql-get-server-info
))
397 (uffi:def-function
"mysql_get_server_info"
398 ((mysql (* mysql-mysql
)))
402 (declaim (inline mysql-get-host-info
))
403 (uffi:def-function
"mysql_get_host_info"
404 ((mysql (* mysql-mysql
)))
408 (declaim (inline mysql-get-proto-info
))
409 (uffi:def-function
"mysql_get_proto_info"
410 ((mysql (* mysql-mysql
)))
412 :returning
:unsigned-int
)
414 (declaim (inline mysql-list-dbs
))
415 (uffi:def-function
"mysql_list_dbs"
416 ((mysql (* mysql-mysql
))
419 :returning
(* mysql-mysql-res
))
421 (declaim (inline mysql-list-tables
))
422 (uffi:def-function
"mysql_list_tables"
423 ((mysql (* mysql-mysql
))
426 :returning
(* mysql-mysql-res
))
428 (declaim (inline mysql-list-fields
))
429 (uffi:def-function
"mysql_list_fields"
430 ((mysql (* mysql-mysql
))
434 :returning
(* mysql-mysql-res
))
436 (declaim (inline mysql-list-processes
))
437 (uffi:def-function
"mysql_list_processes"
438 ((mysql (* mysql-mysql
)))
440 :returning
(* mysql-mysql-res
))
442 (declaim (inline mysql-store-result
))
443 (uffi:def-function
"mysql_store_result"
444 ((mysql (* mysql-mysql
)))
446 :returning
(* mysql-mysql-res
))
448 (declaim (inline mysql-use-result
))
449 (uffi:def-function
"mysql_use_result"
450 ((mysql (* mysql-mysql
)))
452 :returning
(* mysql-mysql-res
))
454 (declaim (inline mysql-options
))
455 (uffi:def-function
"mysql_options"
456 ((mysql (* mysql-mysql
))
457 (option mysql-option
)
462 (declaim (inline mysql-free-result
))
463 (uffi:def-function
"mysql_free_result"
464 ((res (* mysql-mysql-res
)))
468 (declaim (inline mysql-row-seek
))
469 (uffi:def-function
"mysql_row_seek"
470 ((res (* mysql-mysql-res
))
471 (offset mysql-row-offset
))
473 :returning mysql-row-offset
)
475 (declaim (inline mysql-field-seek
))
476 (uffi:def-function
"mysql_field_seek"
477 ((res (* mysql-mysql-res
))
478 (offset mysql-field-offset
))
480 :returning mysql-field-offset
)
482 (declaim (inline mysql-fetch-row
))
483 (uffi:def-function
"mysql_fetch_row"
484 ((res (* mysql-mysql-res
)))
486 :returning
(* (* :unsigned-char
)))
488 (declaim (inline mysql-fetch-lengths
))
489 (uffi:def-function
"mysql_fetch_lengths"
490 ((res (* mysql-mysql-res
)))
492 :returning
(* :unsigned-long
))
494 (declaim (inline mysql-fetch-field
))
495 (uffi:def-function
"mysql_fetch_field"
496 ((res (* mysql-mysql-res
)))
498 :returning
(* mysql-field
))
500 (declaim (inline mysql-fetch-fields
))
501 (uffi:def-function
"mysql_fetch_fields"
502 ((res (* mysql-mysql-res
)))
504 :returning
(* mysql-field
))
506 (declaim (inline mysql-fetch-field-direct
))
507 (uffi:def-function
"mysql_fetch_field_direct"
508 ((res (* mysql-mysql-res
))
509 (field-num :unsigned-int
))
511 :returning
(* mysql-field
))
513 (declaim (inline mysql-escape-string
))
514 (uffi:def-function
"mysql_escape_string"
515 ((to (* :unsigned-char
))
516 (from (* :unsigned-char
))
517 (length :unsigned-int
))
519 :returning
:unsigned-int
)
521 (declaim (inline mysql-debug
))
522 (uffi:def-function
"mysql_debug"
527 (declaim (inline clsql-mysql-num-rows
))
528 (uffi:def-function
"clsql_mysql_num_rows"
529 ((res (* mysql-mysql-res
))
530 (p-high32 (* :unsigned-int
)))
531 :module
"clsql-mysql"
532 :returning
:unsigned-int
)
534 #+(or mysql-client-v4.1 mysql-client-v5
)
535 (uffi:def-foreign-type mysql-stmt-ptr
:pointer-void
)
537 #+(or mysql-client-v4.1 mysql-client-v5
)
538 (uffi:def-function
"mysql_stmt_init"
539 ((res (* mysql-mysql-res
)))
540 :module
"clsql-mysql"
541 :returning mysql-stmt-ptr
)
543 #+(or mysql-client-v4.1 mysql-client-v5
)
544 (uffi:def-function
"mysql_stmt_prepare"
545 ((stmt mysql-stmt-ptr
)
547 (length :unsigned-long
))
548 :module
"clsql-mysql"
551 #+(or mysql-client-v4.1 mysql-client-v5
)
552 (uffi:def-function
"mysql_stmt_param_count"
553 ((stmt mysql-stmt-ptr
))
554 :module
"clsql-mysql"
555 :returning
:unsigned-int
)
557 #+(or mysql-client-v4.1 mysql-client-v5
)
558 (uffi:def-function
"mysql_stmt_bind_param"
559 ((stmt mysql-stmt-ptr
)
560 (bind (* mysql-bind
)))
561 :module
"clsql-mysql"
564 #+(or mysql-client-v4.1 mysql-client-v5
)
565 (uffi:def-function
"mysql_stmt_bind_result"
566 ((stmt mysql-stmt-ptr
)
567 (bind (* mysql-bind
)))
568 :module
"clsql-mysql"
571 #+(or mysql-client-v4.1 mysql-client-v5
)
572 (uffi:def-function
"mysql_stmt_result_metadata"
573 ((stmt mysql-stmt-ptr
))
574 :module
"clsql-mysql"
575 :returning
(* mysql-mysql-res
))
578 #+(or mysql-client-v4.1 mysql-client-v5
)
579 (uffi:def-function
"mysql_stmt_execute"
580 ((stmt mysql-stmt-ptr
))
581 :module
"clsql-mysql"
584 #+(or mysql-client-v4.1 mysql-client-v5
)
585 (uffi:def-function
"mysql_stmt_store_result"
586 ((stmt mysql-stmt-ptr
))
587 :module
"clsql-mysql"
590 #+(or mysql-client-v4.1 mysql-client-v5
)
591 (uffi:def-function
"mysql_stmt_fetch"
592 ((stmt mysql-stmt-ptr
))
593 :module
"clsql-mysql"
596 #+(or mysql-client-v4.1 mysql-client-v5
)
597 (uffi:def-function
"mysql_stmt_free_result"
598 ((stmt mysql-stmt-ptr
))
599 :module
"clsql-mysql"
602 #+(or mysql-client-v4.1 mysql-client-v5
)
603 (uffi:def-function
"mysql_stmt_close"
604 ((stmt mysql-stmt-ptr
))
605 :module
"clsql-mysql"
608 #+(or mysql-client-v4.1 mysql-client-v5
)
609 (uffi:def-function
"mysql_stmt_errno"
610 ((stmt mysql-stmt-ptr
))
611 :module
"clsql-mysql"
612 :returning
:unsigned-int
)
614 #+(or mysql-client-v4.1 mysql-client-v5
)
615 (uffi:def-function
"mysql_stmt_error"
616 ((stmt mysql-stmt-ptr
))
617 :module
"clsql-mysql"
621 ;;;; Equivalents of C Macro definitions for accessing various fields
622 ;;;; in the internal MySQL Datastructures
625 (declaim (inline mysql-num-rows
))
626 (defun mysql-num-rows (res)
627 (uffi:with-foreign-object
(p-high32 :unsigned-int
)
628 (let ((low32 (clsql-mysql-num-rows res p-high32
))
629 (high32 (uffi:deref-pointer p-high32
:unsigned-int
)))
632 (make-64-bit-integer high32 low32
)))))
634 (uffi:def-function
"clsql_mysql_affected_rows"
635 ((mysql (* mysql-mysql
))
636 (p-high32 (* :unsigned-int
)))
637 :returning
:unsigned-int
638 :module
"clsql-mysql")
640 (defun mysql-affected-rows (mysql)
641 (uffi:with-foreign-object
(p-high32 :unsigned-int
)
642 (let ((low32 (clsql-mysql-affected-rows mysql p-high32
))
643 (high32 (uffi:deref-pointer p-high32
:unsigned-int
)))
646 (make-64-bit-integer high32 low32
)))))
648 (uffi:def-function
"clsql_mysql_insert_id"
649 ((res (* mysql-mysql
))
650 (p-high32 (* :unsigned-int
)))
651 :returning
:unsigned-int
652 :module
"clsql-mysql")
654 (defun mysql-insert-id (mysql)
655 (uffi:with-foreign-object
(p-high32 :unsigned-int
)
656 (let ((low32 (clsql-mysql-insert-id mysql p-high32
))
657 (high32 (uffi:deref-pointer p-high32
:unsigned-int
)))
660 (make-64-bit-integer high32 low32
)))))
663 (declaim (inline mysql-num-fields
))
664 (uffi:def-function
"mysql_num_fields"
665 ((res (* mysql-mysql-res
)))
666 :returning
:unsigned-int
669 (declaim (inline clsql-mysql-eof
))
670 (uffi:def-function
("mysql_eof" clsql-mysql-eof
)
671 ((res (* mysql-mysql-res
)))
675 (declaim (inline mysql-eof
))
676 (defun mysql-eof (res)
677 (if (zerop (clsql-mysql-eof res
))
681 (declaim (inline mysql-error
))
682 (uffi:def-function
("mysql_error" mysql-error
)
683 ((mysql (* mysql-mysql
)))
687 (declaim (inline mysql-error-string
))
688 (defun mysql-error-string (mysql)
689 (uffi:convert-from-cstring
(mysql-error mysql
)))
691 (declaim (inline mysql-errno
))
692 (uffi:def-function
"mysql_errno"
693 ((mysql (* mysql-mysql
)))
694 :returning
:unsigned-int
697 (declaim (inline mysql-info
))
698 (uffi:def-function
("mysql_info" mysql-info
)
699 ((mysql (* mysql-mysql
)))
703 (declaim (inline mysql-info-string
))
704 (defun mysql-info-string (mysql)
705 (uffi:convert-from-cstring
(mysql-info mysql
)))
707 (declaim (inline clsql-mysql-data-seek
))
708 (uffi:def-function
"clsql_mysql_data_seek"
709 ((res (* mysql-mysql-res
))
710 (offset-high32 :unsigned-int
)
711 (offset-low32 :unsigned-int
))
712 :module
"clsql-mysql"
715 (defun mysql-data-seek (res offset
)
716 (multiple-value-bind (high32 low32
) (split-64-bit-integer offset
)
717 (clsql-mysql-data-seek res high32 low32
)))