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
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
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 ;;;; *************************************************************************
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.
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
42 (uffi:def-struct mysql-net
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
)
56 (return-errno 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
)
68 (uffi:def-struct mysql-used-mem
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
))
82 (uffi:def-enum mysql-field-types
109 (uffi:def-struct mysql-field
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
124 (org_table (* :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
138 (org_table (* :char
))
140 (catalog_db (* :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
159 (month :unsigned-int
)
162 (minute :unsigned-int
)
163 (second :unsigned-int
)
164 (second-part :unsigned-long
)
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
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
)))
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
)
197 (init-command (* :char
))
200 (unix-socket (* :char
))
202 (my-cnf-file (* :char
))
203 (my-cnf-group (* :char
))
204 (charset-dir (* :char
))
205 (charset-name (* :char
))
210 (ssl-capath (* :char
)))
212 (uffi:def-enum mysql-option
218 :read-default-group
))
220 (uffi:def-enum mysql-status
225 (uffi:def-struct mysql-mysql
226 (net (:struct mysql-net
))
227 (connected-fd (* :char
))
231 (unix-socket (* :char
))
232 (server-version (* :char
))
233 (host-info (* :char
))
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
))
254 (reconnect mysql-bool
)
255 (options (:struct mysql-options
))
256 (scramble-buff (:array
:char
9))
257 (charset :pointer-void
)
258 (server-language :unsigned-int
))
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
))
272 (current-row mysql-row
)
273 (lengths (* :unsigned-long
))
274 (handle (:struct-pointer mysql-mysql
))
277 #+(or mysql-client-v4.1 mysql-client-v5
)
278 (uffi:def-enum mysql-field-types
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
)
289 (buffer-length :unsigned-long
)
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
)))
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
))
320 (unix-socket :cstring
)
321 (clientflag :unsigned-long
))
323 :returning
(* mysql-mysql
))
325 (declaim (inline mysql-close
))
326 (uffi:def-function
"mysql_close"
327 ((sock (* mysql-mysql
)))
331 (declaim (inline mysql-select-db
))
332 (uffi:def-function
"mysql_select_db"
333 ((mysql (* mysql-mysql
))
338 (declaim (inline mysql-query
))
339 (uffi:def-function
"mysql_query"
340 ((mysql (* mysql-mysql
))
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
))
352 (length :unsigned-int
))
356 (declaim (inline mysql-shutdown
))
357 (uffi:def-function
"mysql_shutdown"
358 ((mysql (* mysql-mysql
)))
362 (declaim (inline mysql-dump-debug-info
))
363 (uffi:def-function
"mysql_dump_debug_info"
364 ((mysql (* mysql-mysql
)))
368 (declaim (inline mysql-refresh
))
369 (uffi:def-function
"mysql_refresh"
370 ((mysql (* mysql-mysql
))
371 (refresh-options :unsigned-int
))
375 (declaim (inline mysql-kill
))
376 (uffi:def-function
"mysql_kill"
377 ((mysql (* mysql-mysql
))
378 (pid :unsigned-long
))
382 (declaim (inline mysql-ping
))
383 (uffi:def-function
"mysql_ping"
384 ((mysql (* mysql-mysql
)))
388 (declaim (inline mysql-stat
))
389 (uffi:def-function
"mysql_stat"
390 ((mysql (* mysql-mysql
)))
394 (declaim (inline mysql-get-server-info
))
395 (uffi:def-function
"mysql_get_server_info"
396 ((mysql (* mysql-mysql
)))
400 (declaim (inline mysql-get-host-info
))
401 (uffi:def-function
"mysql_get_host_info"
402 ((mysql (* mysql-mysql
)))
406 (declaim (inline mysql-get-proto-info
))
407 (uffi:def-function
"mysql_get_proto_info"
408 ((mysql (* mysql-mysql
)))
410 :returning
:unsigned-int
)
412 (declaim (inline mysql-list-dbs
))
413 (uffi:def-function
"mysql_list_dbs"
414 ((mysql (* mysql-mysql
))
417 :returning
(* mysql-mysql-res
))
419 (declaim (inline mysql-list-tables
))
420 (uffi:def-function
"mysql_list_tables"
421 ((mysql (* mysql-mysql
))
424 :returning
(* mysql-mysql-res
))
426 (declaim (inline mysql-list-fields
))
427 (uffi:def-function
"mysql_list_fields"
428 ((mysql (* mysql-mysql
))
432 :returning
(* mysql-mysql-res
))
434 (declaim (inline mysql-list-processes
))
435 (uffi:def-function
"mysql_list_processes"
436 ((mysql (* mysql-mysql
)))
438 :returning
(* mysql-mysql-res
))
440 (declaim (inline mysql-store-result
))
441 (uffi:def-function
"mysql_store_result"
442 ((mysql (* mysql-mysql
)))
444 :returning
(* mysql-mysql-res
))
446 (declaim (inline mysql-use-result
))
447 (uffi:def-function
"mysql_use_result"
448 ((mysql (* mysql-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
)
460 (declaim (inline mysql-free-result
))
461 (uffi:def-function
"mysql_free_result"
462 ((res (* mysql-mysql-res
)))
466 (declaim (inline mysql-row-seek
))
467 (uffi:def-function
"mysql_row_seek"
468 ((res (* mysql-mysql-res
))
469 (offset mysql-row-offset
))
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
))
478 :returning mysql-field-offset
)
480 (declaim (inline mysql-fetch-row
))
481 (uffi:def-function
"mysql_fetch_row"
482 ((res (* mysql-mysql-res
)))
484 :returning
(* (* :unsigned-char
)))
486 (declaim (inline mysql-fetch-lengths
))
487 (uffi:def-function
"mysql_fetch_lengths"
488 ((res (* mysql-mysql-res
)))
490 :returning
(* :unsigned-long
))
492 (declaim (inline mysql-fetch-field
))
493 (uffi:def-function
"mysql_fetch_field"
494 ((res (* mysql-mysql-res
)))
496 :returning
(* mysql-field
))
498 (declaim (inline mysql-fetch-fields
))
499 (uffi:def-function
"mysql_fetch_fields"
500 ((res (* mysql-mysql-res
)))
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
))
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
))
517 :returning
:unsigned-int
)
519 (declaim (inline mysql-debug
))
520 (uffi:def-function
"mysql_debug"
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
)
545 (length :unsigned-long
))
546 :module
"clsql-mysql"
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"
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"
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"
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"
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"
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"
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"
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"
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
)))
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
)))
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
)))
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
667 (declaim (inline clsql-mysql-eof
))
668 (uffi:def-function
("mysql_eof" clsql-mysql-eof
)
669 ((res (* mysql-mysql-res
)))
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
)))
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
695 (declaim (inline mysql-info
))
696 (uffi:def-function
("mysql_info" mysql-info
)
697 ((mysql (* mysql-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"
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
)))