1 ;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-
2 ;;;; *************************************************************************
3 ;;;; FILE IDENTIFICATION
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 ;;;; $Id: mysql-api.lisp,v 1.3 2003/06/08 12:48:55 kevin Exp $
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 ;;;; *************************************************************************
21 (eval-when (:compile-toplevel)
22 (declaim (optimize (debug 3) (speed 3) (safety 1) (compilation-speed 0))))
26 ;;;; Modifications from original code
27 ;;;; - Updated C-structures to conform to structures in MySQL 3.23.46
28 ;;;; - Changed from CMUCL interface to UFFI
29 ;;;; - Added and call a C-helper file to support 64-bit integers
30 ;;;; that are used in a few routines.
31 ;;;; - Removed all references to interiors of C-structions, this will
32 ;;;; increase robustness when MySQL's internal structures change.
38 (uffi:def-foreign-type mysql-socket :int)
39 (uffi:def-foreign-type mysql-bool :char)
40 (uffi:def-foreign-type mysql-byte :unsigned-char)
42 (uffi:def-enum mysql-net-type
47 (uffi:def-struct mysql-net
51 (buff (* :unsigned-char))
52 (buff-end (* :unsigned-char))
53 (write-pos (* :unsigned-char))
54 (read-pos (* :unsigned-char))
55 (last-error (:array :char 200))
56 (last-errno :unsigned-int)
57 (max-packet :unsigned-int)
58 (timeout :unsigned-int)
59 (pkt-nr :unsigned-int)
61 (return-errno mysql-bool)
63 (no-send-ok mysql-bool)
64 (remain-in-buf :unsigned-long)
65 (length :unsigned-long)
66 (buf-length :unsigned-long)
67 (where-b :unsigned-long)
68 (return-status (* :unsigned-int))
69 (reading-or-writing :unsigned-char)
73 (uffi:def-struct mysql-used-mem
78 (uffi:def-struct mysql-mem-root
79 (free (:struct-pointer mysql-used-mem))
80 (used (:struct-pointer mysql-used-mem))
81 (pre-alloc (:struct-pointer mysql-used-mem))
82 (min-alloc :unsigned-int)
83 (block-size :unsigned-int)
84 (error-handler :pointer-void))
87 (uffi:def-enum mysql-field-types
112 #-(or win32 mswindows)
113 (uffi:def-struct mysql-field
117 (type mysql-field-types)
118 (length :unsigned-int)
119 (max-length :unsigned-int)
120 (flags :unsigned-int)
121 (decimals :unsigned-int))
123 ;; structure changed in mysql 4.0.12, win32
124 #+(or win32 mswindows)
125 (uffi:def-struct mysql-field
128 (org_table (* :char))
131 (length :unsigned-int)
132 (max-length :unsigned-int)
133 (flags :unsigned-int)
134 (decimals :unsigned-int)
135 (type mysql-field-types))
139 (uffi:def-array-pointer mysql-row (* :unsigned-char))
141 (uffi:def-array-pointer mysql-field-vector (* mysql-field))
143 (uffi:def-foreign-type mysql-field-offset :unsigned-int)
145 (uffi:def-struct mysql-rows
149 (uffi:def-foreign-type mysql-row-offset (:struct-pointer mysql-rows))
151 (uffi:def-struct mysql-data
152 (rows-high32 :unsigned-long)
153 (rows-low32 :unsigned-long)
154 (fields :unsigned-int)
155 (data (:struct-pointer mysql-rows))
156 (alloc (:struct mysql-mem-root)))
159 (uffi:def-struct mysql-options
160 (connect-timeout :unsigned-int)
161 (client-flag :unsigned-int)
162 (compress mysql-bool)
163 (named-pipe mysql-bool)
166 (init-command (* :char))
169 (unix-socket (* :char))
171 (my-cnf-file (* :char))
172 (my-cnf-group (* :char))
173 (charset-dir (* :char))
174 (charset-name (* :char))
179 (ssl-capath (* :char)))
181 (uffi:def-enum mysql-option
187 :read-default-group))
189 (uffi:def-enum mysql-status
194 (uffi:def-struct mysql-mysql
195 (net (:struct mysql-net))
196 (connected-fd (* :char))
200 (unix-socket (* :char))
201 (server-version (* :char))
202 (host-info (* :char))
206 (client-flag :unsigned-int)
207 (server-capabilities :unsigned-int)
208 (protocol-version :unsigned-int)
209 (field-count :unsigned-int)
210 (server-status :unsigned-int)
211 (thread-id :unsigned-long)
212 (affected-rows-high32 :unsigned-long)
213 (affected-rows-low32 :unsigned-long)
214 (insert-id-high32 :unsigned-long)
215 (insert-id-low32 :unsigned-long)
216 (extra-info-high32 :unsigned-long)
217 (extra-info-low32 :unsigned-long)
218 (packet-length :unsigned-long)
219 (status mysql-status)
220 (fields (:struct-pointer mysql-field))
221 (field-alloc (:struct mysql-mem-root))
223 (reconnect mysql-bool)
224 (options (:struct mysql-options))
225 (scramble-buff (:array :char 9))
226 (charset :pointer-void)
227 (server-language :unsigned-int))
231 (uffi:def-struct mysql-mysql-res
232 (row-count-high32 :unsigned-long)
233 (row-count-low32 :unsigned-long)
234 (field-count :unsigned-int)
235 (current-field :unsigned-int)
236 (fields (:struct-pointer mysql-field))
237 (data (:struct-pointer mysql-data))
238 (data-cursor (:struct-pointer mysql-rows))
239 (field-alloc (:struct mysql-mem-root))
241 (current-row mysql-row)
242 (lengths (* :unsigned-long))
243 (handle (:struct-pointer mysql-mysql))
246 ;;;; The Foreign C routines
247 (declaim (inline mysql-init))
248 (uffi:def-function "mysql_init"
249 ((mysql (* mysql-mysql)))
251 :returning (* mysql-mysql))
253 (declaim (inline mysql-connect))
254 (uffi:def-function "mysql_connect"
255 ((mysql (* mysql-mysql))
260 :returning (* mysql-mysql))
262 ;; Need to comment this out for LW 4.2.6
263 ;; ? bug in LW version
264 ;;(declaim (inline mysql-real-connect))
265 (uffi:def-function "mysql_real_connect"
266 ((mysql (* mysql-mysql))
272 (unix-socket :cstring)
273 (clientflag :unsigned-int))
275 :returning (* mysql-mysql))
277 (declaim (inline mysql-close))
278 (uffi:def-function "mysql_close"
279 ((sock (* mysql-mysql)))
283 (declaim (inline mysql-select-db))
284 (uffi:def-function "mysql_select_db"
285 ((mysql (* mysql-mysql))
290 (declaim (inline mysql-query))
291 (uffi:def-function "mysql_query"
292 ((mysql (* mysql-mysql))
297 ;;; I doubt that this function is really useful for direct Lisp usage,
298 ;;; but it is here for completeness...
300 (declaim (inline mysql-real-query))
301 (uffi:def-function "mysql_real_query"
302 ((mysql (* mysql-mysql))
304 (length :unsigned-int))
308 (declaim (inline mysql-create-db))
309 (uffi:def-function "mysql_create_db"
310 ((mysql (* mysql-mysql))
315 (declaim (inline mysql-drop-db))
316 (uffi:def-function "mysql_drop_db"
317 ((mysql (* mysql-mysql))
322 (declaim (inline mysql-shutdown))
323 (uffi:def-function "mysql_shutdown"
324 ((mysql (* mysql-mysql)))
328 (declaim (inline mysql-dump-debug-info))
329 (uffi:def-function "mysql_dump_debug_info"
330 ((mysql (* mysql-mysql)))
334 (declaim (inline mysql-refresh))
335 (uffi:def-function "mysql_refresh"
336 ((mysql (* mysql-mysql))
337 (refresh-options :unsigned-int))
341 (declaim (inline mysql-kill))
342 (uffi:def-function "mysql_kill"
343 ((mysql (* mysql-mysql))
344 (pid :unsigned-long))
348 (declaim (inline mysql-ping))
349 (uffi:def-function "mysql_ping"
350 ((mysql (* mysql-mysql)))
354 (declaim (inline mysql-stat))
355 (uffi:def-function "mysql_stat"
356 ((mysql (* mysql-mysql)))
360 (declaim (inline mysql-get-server-info))
361 (uffi:def-function "mysql_get_server_info"
362 ((mysql (* mysql-mysql)))
366 (declaim (inline mysql-get-client-info))
367 (uffi:def-function "mysql_get_client_info"
372 (declaim (inline mysql-get-host-info))
373 (uffi:def-function "mysql_get_host_info"
374 ((mysql (* mysql-mysql)))
378 (declaim (inline mysql-get-proto-info))
379 (uffi:def-function "mysql_get_proto_info"
380 ((mysql (* mysql-mysql)))
382 :returning :unsigned-int)
384 (declaim (inline mysql-list-dbs))
385 (uffi:def-function "mysql_list_dbs"
386 ((mysql (* mysql-mysql))
389 :returning (* mysql-mysql-res))
391 (declaim (inline mysql-list-tables))
392 (uffi:def-function "mysql_list_tables"
393 ((mysql (* mysql-mysql))
396 :returning (* mysql-mysql-res))
398 (declaim (inline mysql-list-fields))
399 (uffi:def-function "mysql_list_fields"
400 ((mysql (* mysql-mysql))
404 :returning (* mysql-mysql-res))
406 (declaim (inline mysql-list-processes))
407 (uffi:def-function "mysql_list_processes"
408 ((mysql (* mysql-mysql)))
410 :returning (* mysql-mysql-res))
412 (declaim (inline mysql-store-result))
413 (uffi:def-function "mysql_store_result"
414 ((mysql (* mysql-mysql)))
416 :returning (* mysql-mysql-res))
418 (declaim (inline mysql-use-result))
419 (uffi:def-function "mysql_use_result"
420 ((mysql (* mysql-mysql)))
422 :returning (* mysql-mysql-res))
424 (declaim (inline mysql-options))
425 (uffi:def-function "mysql_options"
426 ((mysql (* mysql-mysql))
427 (option mysql-option)
432 (declaim (inline mysql-free-result))
433 (uffi:def-function "mysql_free_result"
434 ((res (* mysql-mysql-res)))
438 (declaim (inline mysql-row-seek))
439 (uffi:def-function "mysql_row_seek"
440 ((res (* mysql-mysql-res))
441 (offset mysql-row-offset))
443 :returning mysql-row-offset)
445 (declaim (inline mysql-field-seek))
446 (uffi:def-function "mysql_field_seek"
447 ((res (* mysql-mysql-res))
448 (offset mysql-field-offset))
450 :returning mysql-field-offset)
452 (declaim (inline mysql-fetch-row))
453 (uffi:def-function "mysql_fetch_row"
454 ((res (* mysql-mysql-res)))
456 :returning (* (* :unsigned-char)))
458 (declaim (inline mysql-fetch-lengths))
459 (uffi:def-function "mysql_fetch_lengths"
460 ((res (* mysql-mysql-res)))
462 :returning (* :unsigned-long))
464 (declaim (inline mysql-fetch-field))
465 (uffi:def-function "mysql_fetch_field"
466 ((res (* mysql-mysql-res)))
468 :returning (* mysql-field))
470 (declaim (inline mysql-fetch-fields))
471 (uffi:def-function "mysql_fetch_fields"
472 ((res (* mysql-mysql-res)))
474 :returning (* mysql-field))
476 (declaim (inline mysql-fetch-field-direct))
477 (uffi:def-function "mysql_fetch_field_direct"
478 ((res (* mysql-mysql-res))
479 (field-num :unsigned-int))
481 :returning (* mysql-field))
483 (declaim (inline mysql-escape-string))
484 (uffi:def-function "mysql_escape_string"
487 (length :unsigned-int))
489 :returning :unsigned-int)
491 (declaim (inline mysql-debug))
492 (uffi:def-function "mysql_debug"
497 (declaim (inline clsql-mysql-num-rows))
498 (uffi:def-function "clsql_mysql_num_rows"
499 ((res (* mysql-mysql-res))
500 (p-high32 (* :unsigned-int)))
501 :module "clsql-mysql"
502 :returning :unsigned-int)
505 ;;;; Equivalents of C Macro definitions for accessing various fields
506 ;;;; in the internal MySQL Datastructures
509 (declaim (inline mysql-num-rows))
510 (defun mysql-num-rows (res)
511 (uffi:with-foreign-object (p-high32 :unsigned-int)
512 (let ((low32 (clsql-mysql-num-rows res p-high32))
513 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
516 (make-64-bit-integer high32 low32)))))
518 (uffi:def-function "clsql_mysql_affected_rows"
519 ((mysql (* mysql-mysql))
520 (p-high32 (* :unsigned-int)))
521 :returning :unsigned-int
522 :module "clsql-mysql")
524 (defun mysql-affected-rows (mysql)
525 (uffi:with-foreign-object (p-high32 :unsigned-int)
526 (let ((low32 (clsql-mysql-affected-rows mysql p-high32))
527 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
530 (make-64-bit-integer high32 low32)))))
532 (uffi:def-function "clsql_mysql_insert_id"
533 ((res (* mysql-mysql))
534 (p-high32 (* :unsigned-int)))
535 :returning :unsigned-int
536 :module "clsql-mysql")
538 (defun mysql-insert-id (mysql)
539 (uffi:with-foreign-object (p-high32 :unsigned-int)
540 (let ((low32 (clsql-mysql-insert-id mysql p-high32))
541 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
544 (make-64-bit-integer high32 low32)))))
547 (declaim (inline mysql-num-fields))
548 (uffi:def-function "mysql_num_fields"
549 ((res (* mysql-mysql-res)))
550 :returning :unsigned-int
553 (declaim (inline clsql-mysql-eof))
554 (uffi:def-function ("mysql_eof" clsql-mysql-eof)
555 ((res (* mysql-mysql-res)))
559 (declaim (inline mysql-eof))
560 (defun mysql-eof (res)
561 (if (zerop (clsql-mysql-eof res))
565 (declaim (inline mysql-error))
566 (uffi:def-function ("mysql_error" mysql-error)
567 ((mysql (* mysql-mysql)))
571 (declaim (inline mysql-error-string))
572 (defun mysql-error-string (mysql)
573 (uffi:convert-from-cstring (mysql-error mysql)))
575 (declaim (inline mysql-errno))
576 (uffi:def-function "mysql_errno"
577 ((mysql (* mysql-mysql)))
578 :returning :unsigned-int
581 (declaim (inline mysql-info))
582 (uffi:def-function ("mysql_info" mysql-info)
583 ((mysql (* mysql-mysql)))
587 (declaim (inline mysql-info-string))
588 (defun mysql-info-string (mysql)
589 (uffi:convert-from-cstring (mysql-info mysql)))
591 (declaim (inline clsql-mysql-data-seek))
592 (uffi:def-function "clsql_mysql_data_seek"
593 ((res (* mysql-mysql-res))
594 (offset-high32 :unsigned-int)
595 (offset-low32 :unsigned-int))
596 :module "clsql-mysql"
600 (defun mysql-data-seek (res offset)
601 (multiple-value-bind (high32 low32) (split-64-bit-integer offset)
602 (clsql-mysql-data-seek res high32 low32)))