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 :char)
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
109 #-(or :mysql-client-v3 :mysql-client-v4)
110 (eval-when (:compile-toplevel :load-toplevel :execute)
111 (pushnew :mysql-client-v3 cl:*features*))
114 (uffi:def-struct mysql-field
118 (type mysql-field-types)
119 (length :unsigned-int)
120 (max-length :unsigned-int)
121 (flags :unsigned-int)
122 (decimals :unsigned-int))
124 ;; structure changed in mysql 4 client
126 (uffi:def-struct mysql-field
129 (org_table (* :char))
132 (length :unsigned-int)
133 (max-length :unsigned-int)
134 (flags :unsigned-int)
135 (decimals :unsigned-int)
136 (type mysql-field-types))
140 (uffi:def-array-pointer mysql-row (* :unsigned-char))
142 (uffi:def-array-pointer mysql-field-vector (* mysql-field))
144 (uffi:def-foreign-type mysql-field-offset :unsigned-int)
146 (uffi:def-struct mysql-rows
150 (uffi:def-foreign-type mysql-row-offset (:struct-pointer mysql-rows))
152 (uffi:def-struct mysql-data
153 (rows-high32 :unsigned-long)
154 (rows-low32 :unsigned-long)
155 (fields :unsigned-int)
156 (data (:struct-pointer mysql-rows))
157 (alloc (:struct mysql-mem-root)))
160 (uffi:def-struct mysql-options
161 (connect-timeout :unsigned-int)
162 (client-flag :unsigned-int)
163 (compress mysql-bool)
164 (named-pipe mysql-bool)
167 (init-command (* :char))
170 (unix-socket (* :char))
172 (my-cnf-file (* :char))
173 (my-cnf-group (* :char))
174 (charset-dir (* :char))
175 (charset-name (* :char))
180 (ssl-capath (* :char)))
182 (uffi:def-enum mysql-option
188 :read-default-group))
190 (uffi:def-enum mysql-status
195 (uffi:def-struct mysql-mysql
196 (net (:struct mysql-net))
197 (connected-fd (* :char))
201 (unix-socket (* :char))
202 (server-version (* :char))
203 (host-info (* :char))
207 (client-flag :unsigned-int)
208 (server-capabilities :unsigned-int)
209 (protocol-version :unsigned-int)
210 (field-count :unsigned-int)
211 (server-status :unsigned-int)
212 (thread-id :unsigned-long)
213 (affected-rows-high32 :unsigned-long)
214 (affected-rows-low32 :unsigned-long)
215 (insert-id-high32 :unsigned-long)
216 (insert-id-low32 :unsigned-long)
217 (extra-info-high32 :unsigned-long)
218 (extra-info-low32 :unsigned-long)
219 (packet-length :unsigned-long)
220 (status mysql-status)
221 (fields (:struct-pointer mysql-field))
222 (field-alloc (:struct mysql-mem-root))
224 (reconnect mysql-bool)
225 (options (:struct mysql-options))
226 (scramble-buff (:array :char 9))
227 (charset :pointer-void)
228 (server-language :unsigned-int))
232 (uffi:def-struct mysql-mysql-res
233 (row-count-high32 :unsigned-long)
234 (row-count-low32 :unsigned-long)
235 (field-count :unsigned-int)
236 (current-field :unsigned-int)
237 (fields (:struct-pointer mysql-field))
238 (data (:struct-pointer mysql-data))
239 (data-cursor (:struct-pointer mysql-rows))
240 (field-alloc (:struct mysql-mem-root))
242 (current-row mysql-row)
243 (lengths (* :unsigned-long))
244 (handle (:struct-pointer mysql-mysql))
247 ;;;; The Foreign C routines
248 (declaim (inline mysql-init))
249 (uffi:def-function "mysql_init"
250 ((mysql (* mysql-mysql)))
252 :returning (* mysql-mysql))
255 (declaim (inline mysql-connect))
257 (uffi:def-function "mysql_connect"
258 ((mysql (* mysql-mysql))
263 :returning (* mysql-mysql))
265 ;; Need to comment this out for LW 4.2.6
266 ;; ? bug in LW version
267 ;;(declaim (inline mysql-real-connect))
268 (uffi:def-function "mysql_real_connect"
269 ((mysql (* mysql-mysql))
275 (unix-socket :cstring)
276 (clientflag :unsigned-int))
278 :returning (* mysql-mysql))
280 (declaim (inline mysql-close))
281 (uffi:def-function "mysql_close"
282 ((sock (* mysql-mysql)))
286 (declaim (inline mysql-select-db))
287 (uffi:def-function "mysql_select_db"
288 ((mysql (* mysql-mysql))
293 (declaim (inline mysql-query))
294 (uffi:def-function "mysql_query"
295 ((mysql (* mysql-mysql))
300 ;;; I doubt that this function is really useful for direct Lisp usage,
301 ;;; but it is here for completeness...
303 (declaim (inline mysql-real-query))
304 (uffi:def-function "mysql_real_query"
305 ((mysql (* mysql-mysql))
307 (length :unsigned-int))
312 (declaim (inline mysql-create-db))
314 (uffi:def-function "mysql_create_db"
315 ((mysql (* mysql-mysql))
321 (declaim (inline mysql-drop-db))
323 (uffi:def-function "mysql_drop_db"
324 ((mysql (* mysql-mysql))
329 (declaim (inline mysql-shutdown))
330 (uffi:def-function "mysql_shutdown"
331 ((mysql (* mysql-mysql)))
335 (declaim (inline mysql-dump-debug-info))
336 (uffi:def-function "mysql_dump_debug_info"
337 ((mysql (* mysql-mysql)))
341 (declaim (inline mysql-refresh))
342 (uffi:def-function "mysql_refresh"
343 ((mysql (* mysql-mysql))
344 (refresh-options :unsigned-int))
348 (declaim (inline mysql-kill))
349 (uffi:def-function "mysql_kill"
350 ((mysql (* mysql-mysql))
351 (pid :unsigned-long))
355 (declaim (inline mysql-ping))
356 (uffi:def-function "mysql_ping"
357 ((mysql (* mysql-mysql)))
361 (declaim (inline mysql-stat))
362 (uffi:def-function "mysql_stat"
363 ((mysql (* mysql-mysql)))
367 (declaim (inline mysql-get-server-info))
368 (uffi:def-function "mysql_get_server_info"
369 ((mysql (* mysql-mysql)))
373 (declaim (inline mysql-get-client-info))
374 (uffi:def-function "mysql_get_client_info"
379 (declaim (inline mysql-get-host-info))
380 (uffi:def-function "mysql_get_host_info"
381 ((mysql (* mysql-mysql)))
385 (declaim (inline mysql-get-proto-info))
386 (uffi:def-function "mysql_get_proto_info"
387 ((mysql (* mysql-mysql)))
389 :returning :unsigned-int)
391 (declaim (inline mysql-list-dbs))
392 (uffi:def-function "mysql_list_dbs"
393 ((mysql (* mysql-mysql))
396 :returning (* mysql-mysql-res))
398 (declaim (inline mysql-list-tables))
399 (uffi:def-function "mysql_list_tables"
400 ((mysql (* mysql-mysql))
403 :returning (* mysql-mysql-res))
405 (declaim (inline mysql-list-fields))
406 (uffi:def-function "mysql_list_fields"
407 ((mysql (* mysql-mysql))
411 :returning (* mysql-mysql-res))
413 (declaim (inline mysql-list-processes))
414 (uffi:def-function "mysql_list_processes"
415 ((mysql (* mysql-mysql)))
417 :returning (* mysql-mysql-res))
419 (declaim (inline mysql-store-result))
420 (uffi:def-function "mysql_store_result"
421 ((mysql (* mysql-mysql)))
423 :returning (* mysql-mysql-res))
425 (declaim (inline mysql-use-result))
426 (uffi:def-function "mysql_use_result"
427 ((mysql (* mysql-mysql)))
429 :returning (* mysql-mysql-res))
431 (declaim (inline mysql-options))
432 (uffi:def-function "mysql_options"
433 ((mysql (* mysql-mysql))
434 (option mysql-option)
439 (declaim (inline mysql-free-result))
440 (uffi:def-function "mysql_free_result"
441 ((res (* mysql-mysql-res)))
445 (declaim (inline mysql-row-seek))
446 (uffi:def-function "mysql_row_seek"
447 ((res (* mysql-mysql-res))
448 (offset mysql-row-offset))
450 :returning mysql-row-offset)
452 (declaim (inline mysql-field-seek))
453 (uffi:def-function "mysql_field_seek"
454 ((res (* mysql-mysql-res))
455 (offset mysql-field-offset))
457 :returning mysql-field-offset)
459 (declaim (inline mysql-fetch-row))
460 (uffi:def-function "mysql_fetch_row"
461 ((res (* mysql-mysql-res)))
463 :returning (* (* :unsigned-char)))
465 (declaim (inline mysql-fetch-lengths))
466 (uffi:def-function "mysql_fetch_lengths"
467 ((res (* mysql-mysql-res)))
469 :returning (* :unsigned-long))
471 (declaim (inline mysql-fetch-field))
472 (uffi:def-function "mysql_fetch_field"
473 ((res (* mysql-mysql-res)))
475 :returning (* mysql-field))
477 (declaim (inline mysql-fetch-fields))
478 (uffi:def-function "mysql_fetch_fields"
479 ((res (* mysql-mysql-res)))
481 :returning (* mysql-field))
483 (declaim (inline mysql-fetch-field-direct))
484 (uffi:def-function "mysql_fetch_field_direct"
485 ((res (* mysql-mysql-res))
486 (field-num :unsigned-int))
488 :returning (* mysql-field))
490 (declaim (inline mysql-escape-string))
491 (uffi:def-function "mysql_escape_string"
494 (length :unsigned-int))
496 :returning :unsigned-int)
498 (declaim (inline mysql-debug))
499 (uffi:def-function "mysql_debug"
504 (declaim (inline clsql-mysql-num-rows))
505 (uffi:def-function "clsql_mysql_num_rows"
506 ((res (* mysql-mysql-res))
507 (p-high32 (* :unsigned-int)))
508 :module "clsql-mysql"
509 :returning :unsigned-int)
512 ;;;; Equivalents of C Macro definitions for accessing various fields
513 ;;;; in the internal MySQL Datastructures
516 (declaim (inline mysql-num-rows))
517 (defun mysql-num-rows (res)
518 (uffi:with-foreign-object (p-high32 :unsigned-int)
519 (let ((low32 (clsql-mysql-num-rows res p-high32))
520 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
523 (make-64-bit-integer high32 low32)))))
525 (uffi:def-function "clsql_mysql_affected_rows"
526 ((mysql (* mysql-mysql))
527 (p-high32 (* :unsigned-int)))
528 :returning :unsigned-int
529 :module "clsql-mysql")
531 (defun mysql-affected-rows (mysql)
532 (uffi:with-foreign-object (p-high32 :unsigned-int)
533 (let ((low32 (clsql-mysql-affected-rows mysql p-high32))
534 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
537 (make-64-bit-integer high32 low32)))))
539 (uffi:def-function "clsql_mysql_insert_id"
540 ((res (* mysql-mysql))
541 (p-high32 (* :unsigned-int)))
542 :returning :unsigned-int
543 :module "clsql-mysql")
545 (defun mysql-insert-id (mysql)
546 (uffi:with-foreign-object (p-high32 :unsigned-int)
547 (let ((low32 (clsql-mysql-insert-id mysql p-high32))
548 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
551 (make-64-bit-integer high32 low32)))))
554 (declaim (inline mysql-num-fields))
555 (uffi:def-function "mysql_num_fields"
556 ((res (* mysql-mysql-res)))
557 :returning :unsigned-int
560 (declaim (inline clsql-mysql-eof))
561 (uffi:def-function ("mysql_eof" clsql-mysql-eof)
562 ((res (* mysql-mysql-res)))
566 (declaim (inline mysql-eof))
567 (defun mysql-eof (res)
568 (if (zerop (clsql-mysql-eof res))
572 (declaim (inline mysql-error))
573 (uffi:def-function ("mysql_error" mysql-error)
574 ((mysql (* mysql-mysql)))
578 (declaim (inline mysql-error-string))
579 (defun mysql-error-string (mysql)
580 (uffi:convert-from-cstring (mysql-error mysql)))
582 (declaim (inline mysql-errno))
583 (uffi:def-function "mysql_errno"
584 ((mysql (* mysql-mysql)))
585 :returning :unsigned-int
588 (declaim (inline mysql-info))
589 (uffi:def-function ("mysql_info" mysql-info)
590 ((mysql (* mysql-mysql)))
594 (declaim (inline mysql-info-string))
595 (defun mysql-info-string (mysql)
596 (uffi:convert-from-cstring (mysql-info mysql)))
598 (declaim (inline clsql-mysql-data-seek))
599 (uffi:def-function "clsql_mysql_data_seek"
600 ((res (* mysql-mysql-res))
601 (offset-high32 :unsigned-int)
602 (offset-low32 :unsigned-int))
603 :module "clsql-mysql"
607 (defun mysql-data-seek (res offset)
608 (multiple-value-bind (high32 low32) (split-64-bit-integer offset)
609 (clsql-mysql-data-seek res high32 low32)))