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))
136 (uffi:def-struct mysql-field
138 (org_table (* :char))
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))
160 (uffi:def-array-pointer mysql-row (* :unsigned-char))
162 (uffi:def-array-pointer mysql-field-vector (* mysql-field))
164 (uffi:def-foreign-type mysql-field-offset :unsigned-int)
166 (uffi:def-struct mysql-rows
170 (uffi:def-foreign-type mysql-row-offset (:struct-pointer mysql-rows))
172 (uffi:def-struct mysql-data
173 (rows-high32 :unsigned-long)
174 (rows-low32 :unsigned-long)
175 (fields :unsigned-int)
176 (data (:struct-pointer mysql-rows))
177 (alloc (:struct mysql-mem-root)))
180 (uffi:def-struct mysql-options
181 (connect-timeout :unsigned-int)
182 (client-flag :unsigned-int)
183 (compress mysql-bool)
184 (named-pipe mysql-bool)
187 (init-command (* :char))
190 (unix-socket (* :char))
192 (my-cnf-file (* :char))
193 (my-cnf-group (* :char))
194 (charset-dir (* :char))
195 (charset-name (* :char))
200 (ssl-capath (* :char)))
202 (uffi:def-enum mysql-option
208 :read-default-group))
210 (uffi:def-enum mysql-status
215 (uffi:def-struct mysql-mysql
216 (net (:struct mysql-net))
217 (connected-fd (* :char))
221 (unix-socket (* :char))
222 (server-version (* :char))
223 (host-info (* :char))
227 (client-flag :unsigned-int)
228 (server-capabilities :unsigned-int)
229 (protocol-version :unsigned-int)
230 (field-count :unsigned-int)
231 (server-status :unsigned-int)
232 (thread-id :unsigned-long)
233 (affected-rows-high32 :unsigned-long)
234 (affected-rows-low32 :unsigned-long)
235 (insert-id-high32 :unsigned-long)
236 (insert-id-low32 :unsigned-long)
237 (extra-info-high32 :unsigned-long)
238 (extra-info-low32 :unsigned-long)
239 (packet-length :unsigned-long)
240 (status mysql-status)
241 (fields (:struct-pointer mysql-field))
242 (field-alloc (:struct mysql-mem-root))
244 (reconnect mysql-bool)
245 (options (:struct mysql-options))
246 (scramble-buff (:array :char 9))
247 (charset :pointer-void)
248 (server-language :unsigned-int))
252 (uffi:def-struct mysql-mysql-res
253 (row-count-high32 :unsigned-long)
254 (row-count-low32 :unsigned-long)
255 (field-count :unsigned-int)
256 (current-field :unsigned-int)
257 (fields (:struct-pointer mysql-field))
258 (data (:struct-pointer mysql-data))
259 (data-cursor (:struct-pointer mysql-rows))
260 (field-alloc (:struct mysql-mem-root))
262 (current-row mysql-row)
263 (lengths (* :unsigned-long))
264 (handle (:struct-pointer mysql-mysql))
268 (uffi:def-enum mysql-field-types
274 (uffi:def-struct mysql-bind
275 (length (* :unsigned-long))
276 (is-null (* mysql-bool))
277 (buffer :pointer-void)
279 (buffer-length :unsigned-long)
281 (inter_buffer (* :unsigned-char))
282 (offset :unsigned-long)
283 (internal-length :unsigned-long)
284 (param-number :unsigned-int)
285 (pack-length :unsigned-int)
286 (is-signed mysql-bool)
287 (long-data-used mysql-bool)
288 (internal-is-null mysql-bool)
289 (store-param-func :pointer-void)
290 (fetch-result :pointer-void)
291 (skip-result :pointer-void))
293 ;;;; The Foreign C routines
294 (declaim (inline mysql-init))
295 (uffi:def-function "mysql_init"
296 ((mysql (* mysql-mysql)))
298 :returning (* mysql-mysql))
301 (declaim (inline mysql-connect))
303 (uffi:def-function "mysql_connect"
304 ((mysql (* mysql-mysql))
309 :returning (* mysql-mysql))
311 ;; Need to comment this out for LW 4.2.6
312 ;; ? bug in LW version
313 #-lispworks (declaim (inline mysql-real-connect))
314 (uffi:def-function "mysql_real_connect"
315 ((mysql (* mysql-mysql))
321 (unix-socket :cstring)
322 (clientflag :unsigned-long))
324 :returning (* mysql-mysql))
326 (declaim (inline mysql-close))
327 (uffi:def-function "mysql_close"
328 ((sock (* mysql-mysql)))
332 (declaim (inline mysql-select-db))
333 (uffi:def-function "mysql_select_db"
334 ((mysql (* mysql-mysql))
339 (declaim (inline mysql-query))
340 (uffi:def-function "mysql_query"
341 ((mysql (* mysql-mysql))
346 ;;; I doubt that this function is really useful for direct Lisp usage,
347 ;;; but it is here for completeness...
349 (declaim (inline mysql-real-query))
350 (uffi:def-function "mysql_real_query"
351 ((mysql (* mysql-mysql))
353 (length :unsigned-int))
358 (declaim (inline mysql-create-db))
360 (uffi:def-function "mysql_create_db"
361 ((mysql (* mysql-mysql))
367 (declaim (inline mysql-drop-db))
369 (uffi:def-function "mysql_drop_db"
370 ((mysql (* mysql-mysql))
375 (declaim (inline mysql-shutdown))
376 (uffi:def-function "mysql_shutdown"
377 ((mysql (* mysql-mysql)))
381 (declaim (inline mysql-dump-debug-info))
382 (uffi:def-function "mysql_dump_debug_info"
383 ((mysql (* mysql-mysql)))
387 (declaim (inline mysql-refresh))
388 (uffi:def-function "mysql_refresh"
389 ((mysql (* mysql-mysql))
390 (refresh-options :unsigned-int))
394 (declaim (inline mysql-kill))
395 (uffi:def-function "mysql_kill"
396 ((mysql (* mysql-mysql))
397 (pid :unsigned-long))
401 (declaim (inline mysql-ping))
402 (uffi:def-function "mysql_ping"
403 ((mysql (* mysql-mysql)))
407 (declaim (inline mysql-stat))
408 (uffi:def-function "mysql_stat"
409 ((mysql (* mysql-mysql)))
413 (declaim (inline mysql-get-server-info))
414 (uffi:def-function "mysql_get_server_info"
415 ((mysql (* mysql-mysql)))
419 (declaim (inline mysql-get-host-info))
420 (uffi:def-function "mysql_get_host_info"
421 ((mysql (* mysql-mysql)))
425 (declaim (inline mysql-get-proto-info))
426 (uffi:def-function "mysql_get_proto_info"
427 ((mysql (* mysql-mysql)))
429 :returning :unsigned-int)
431 (declaim (inline mysql-list-dbs))
432 (uffi:def-function "mysql_list_dbs"
433 ((mysql (* mysql-mysql))
436 :returning (* mysql-mysql-res))
438 (declaim (inline mysql-list-tables))
439 (uffi:def-function "mysql_list_tables"
440 ((mysql (* mysql-mysql))
443 :returning (* mysql-mysql-res))
445 (declaim (inline mysql-list-fields))
446 (uffi:def-function "mysql_list_fields"
447 ((mysql (* mysql-mysql))
451 :returning (* mysql-mysql-res))
453 (declaim (inline mysql-list-processes))
454 (uffi:def-function "mysql_list_processes"
455 ((mysql (* mysql-mysql)))
457 :returning (* mysql-mysql-res))
459 (declaim (inline mysql-store-result))
460 (uffi:def-function "mysql_store_result"
461 ((mysql (* mysql-mysql)))
463 :returning (* mysql-mysql-res))
465 (declaim (inline mysql-use-result))
466 (uffi:def-function "mysql_use_result"
467 ((mysql (* mysql-mysql)))
469 :returning (* mysql-mysql-res))
471 (declaim (inline mysql-options))
472 (uffi:def-function "mysql_options"
473 ((mysql (* mysql-mysql))
474 (option mysql-option)
479 (declaim (inline mysql-free-result))
480 (uffi:def-function "mysql_free_result"
481 ((res (* mysql-mysql-res)))
485 (declaim (inline mysql-row-seek))
486 (uffi:def-function "mysql_row_seek"
487 ((res (* mysql-mysql-res))
488 (offset mysql-row-offset))
490 :returning mysql-row-offset)
492 (declaim (inline mysql-field-seek))
493 (uffi:def-function "mysql_field_seek"
494 ((res (* mysql-mysql-res))
495 (offset mysql-field-offset))
497 :returning mysql-field-offset)
499 (declaim (inline mysql-fetch-row))
500 (uffi:def-function "mysql_fetch_row"
501 ((res (* mysql-mysql-res)))
503 :returning (* (* :unsigned-char)))
505 (declaim (inline mysql-fetch-lengths))
506 (uffi:def-function "mysql_fetch_lengths"
507 ((res (* mysql-mysql-res)))
509 :returning (* :unsigned-long))
511 (declaim (inline mysql-fetch-field))
512 (uffi:def-function "mysql_fetch_field"
513 ((res (* mysql-mysql-res)))
515 :returning (* mysql-field))
517 (declaim (inline mysql-fetch-fields))
518 (uffi:def-function "mysql_fetch_fields"
519 ((res (* mysql-mysql-res)))
521 :returning (* mysql-field))
523 (declaim (inline mysql-fetch-field-direct))
524 (uffi:def-function "mysql_fetch_field_direct"
525 ((res (* mysql-mysql-res))
526 (field-num :unsigned-int))
528 :returning (* mysql-field))
530 (declaim (inline mysql-escape-string))
531 (uffi:def-function "mysql_escape_string"
534 (length :unsigned-int))
536 :returning :unsigned-int)
538 (declaim (inline mysql-debug))
539 (uffi:def-function "mysql_debug"
544 (declaim (inline clsql-mysql-num-rows))
545 (uffi:def-function "clsql_mysql_num_rows"
546 ((res (* mysql-mysql-res))
547 (p-high32 (* :unsigned-int)))
548 :module "clsql-mysql"
549 :returning :unsigned-int)
552 (uffi:def-foreign-type mysql-stmt-ptr :pointer-void)
555 (uffi:def-function "mysql_stmt_init"
556 ((res (* mysql-mysql-res)))
557 :module "clsql-mysql"
558 :returning mysql-stmt-ptr)
561 (uffi:def-function "mysql_stmt_prepare"
562 ((stmt mysql-stmt-ptr)
564 (length :unsigned-long))
565 :module "clsql-mysql"
569 (uffi:def-function "mysql_stmt_param_count"
570 ((stmt mysql-stmt-ptr))
571 :module "clsql-mysql"
572 :returning :unsigned-int)
575 (uffi:def-function "mysql_stmt_bind_param"
576 ((stmt mysql-stmt-ptr)
577 (bind (* mysql-bind)))
578 :module "clsql-mysql"
582 (uffi:def-function "mysql_stmt_bind_result"
583 ((stmt mysql-stmt-ptr)
584 (bind (* mysql-bind)))
585 :module "clsql-mysql"
589 (uffi:def-function "mysql_stmt_result_metadata"
590 ((stmt mysql-stmt-ptr))
591 :module "clsql-mysql"
592 :returning (* mysql-mysql-res))
596 (uffi:def-function "mysql_stmt_execute"
597 ((stmt mysql-stmt-ptr))
598 :module "clsql-mysql"
602 (uffi:def-function "mysql_stmt_fetch"
603 ((stmt mysql-stmt-ptr))
604 :module "clsql-mysql"
608 (uffi:def-function "mysql_stmt_free_result"
609 ((stmt mysql-stmt-ptr))
610 :module "clsql-mysql"
614 (uffi:def-function "mysql_stmt_close"
615 ((stmt mysql-stmt-ptr))
616 :module "clsql-mysql"
620 (uffi:def-function "mysql_stmt_errno"
621 ((stmt mysql-stmt-ptr))
622 :module "clsql-mysql"
623 :returning :unsigned-int)
626 (uffi:def-function "mysql_stmt_error"
627 ((stmt mysql-stmt-ptr))
628 :module "clsql-mysql"
632 ;;;; Equivalents of C Macro definitions for accessing various fields
633 ;;;; in the internal MySQL Datastructures
636 (declaim (inline mysql-num-rows))
637 (defun mysql-num-rows (res)
638 (uffi:with-foreign-object (p-high32 :unsigned-int)
639 (let ((low32 (clsql-mysql-num-rows res p-high32))
640 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
643 (make-64-bit-integer high32 low32)))))
645 (uffi:def-function "clsql_mysql_affected_rows"
646 ((mysql (* mysql-mysql))
647 (p-high32 (* :unsigned-int)))
648 :returning :unsigned-int
649 :module "clsql-mysql")
651 (defun mysql-affected-rows (mysql)
652 (uffi:with-foreign-object (p-high32 :unsigned-int)
653 (let ((low32 (clsql-mysql-affected-rows mysql p-high32))
654 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
657 (make-64-bit-integer high32 low32)))))
659 (uffi:def-function "clsql_mysql_insert_id"
660 ((res (* mysql-mysql))
661 (p-high32 (* :unsigned-int)))
662 :returning :unsigned-int
663 :module "clsql-mysql")
665 (defun mysql-insert-id (mysql)
666 (uffi:with-foreign-object (p-high32 :unsigned-int)
667 (let ((low32 (clsql-mysql-insert-id mysql p-high32))
668 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
671 (make-64-bit-integer high32 low32)))))
674 (declaim (inline mysql-num-fields))
675 (uffi:def-function "mysql_num_fields"
676 ((res (* mysql-mysql-res)))
677 :returning :unsigned-int
680 (declaim (inline clsql-mysql-eof))
681 (uffi:def-function ("mysql_eof" clsql-mysql-eof)
682 ((res (* mysql-mysql-res)))
686 (declaim (inline mysql-eof))
687 (defun mysql-eof (res)
688 (if (zerop (clsql-mysql-eof res))
692 (declaim (inline mysql-error))
693 (uffi:def-function ("mysql_error" mysql-error)
694 ((mysql (* mysql-mysql)))
698 (declaim (inline mysql-error-string))
699 (defun mysql-error-string (mysql)
700 (uffi:convert-from-cstring (mysql-error mysql)))
702 (declaim (inline mysql-errno))
703 (uffi:def-function "mysql_errno"
704 ((mysql (* mysql-mysql)))
705 :returning :unsigned-int
708 (declaim (inline mysql-info))
709 (uffi:def-function ("mysql_info" mysql-info)
710 ((mysql (* mysql-mysql)))
714 (declaim (inline mysql-info-string))
715 (defun mysql-info-string (mysql)
716 (uffi:convert-from-cstring (mysql-info mysql)))
718 (declaim (inline clsql-mysql-data-seek))
719 (uffi:def-function "clsql_mysql_data_seek"
720 ((res (* mysql-mysql-res))
721 (offset-high32 :unsigned-int)
722 (offset-low32 :unsigned-int))
723 :module "clsql-mysql"
726 (defun mysql-data-seek (res offset)
727 (multiple-value-bind (high32 low32) (split-64-bit-integer offset)
728 (clsql-mysql-data-seek res high32 low32)))