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.2 2003/05/17 07:27:15 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 (declaim (optimize (debug 3) (speed 3) (safety 1) (compilation-speed 0)))
25 ;;;; Modifications from original code
26 ;;;; - Updated C-structures to conform to structures in MySQL 3.23.46
27 ;;;; - Changed from CMUCL interface to UFFI
28 ;;;; - Added and call a C-helper file to support 64-bit integers
29 ;;;; that are used in a few routines.
30 ;;;; - Removed all references to interiors of C-structions, this will
31 ;;;; increase robustness when MySQL's internal structures change.
37 (uffi:def-foreign-type mysql-socket :int)
38 (uffi:def-foreign-type mysql-bool :char)
39 (uffi:def-foreign-type mysql-byte :unsigned-char)
41 (uffi:def-enum mysql-net-type
46 (uffi:def-struct mysql-net
50 (buff (* :unsigned-char))
51 (buff-end (* :unsigned-char))
52 (write-pos (* :unsigned-char))
53 (read-pos (* :unsigned-char))
54 (last-error (:array :char 200))
55 (last-errno :unsigned-int)
56 (max-packet :unsigned-int)
57 (timeout :unsigned-int)
58 (pkt-nr :unsigned-int)
60 (return-errno mysql-bool)
62 (no-send-ok mysql-bool)
63 (remain-in-buf :unsigned-long)
64 (length :unsigned-long)
65 (buf-length :unsigned-long)
66 (where-b :unsigned-long)
67 (return-status (* :unsigned-int))
68 (reading-or-writing :unsigned-char)
72 (uffi:def-struct mysql-used-mem
77 (uffi:def-struct mysql-mem-root
78 (free (:struct-pointer mysql-used-mem))
79 (used (:struct-pointer mysql-used-mem))
80 (pre-alloc (:struct-pointer mysql-used-mem))
81 (min-alloc :unsigned-int)
82 (block-size :unsigned-int)
83 (error-handler :pointer-void))
86 (uffi:def-enum mysql-field-types
111 #-(or win32 mswindows)
112 (uffi:def-struct mysql-field
116 (type mysql-field-types)
117 (length :unsigned-int)
118 (max-length :unsigned-int)
119 (flags :unsigned-int)
120 (decimals :unsigned-int))
122 ;; structure changed in mysql 4.0.12, win32
123 #+(or win32 mswindows)
124 (uffi:def-struct mysql-field
127 (org_table (* :char))
130 (length :unsigned-int)
131 (max-length :unsigned-int)
132 (flags :unsigned-int)
133 (decimals :unsigned-int)
134 (type mysql-field-types))
138 (uffi:def-array-pointer mysql-row (* :unsigned-char))
140 (uffi:def-array-pointer mysql-field-vector (* mysql-field))
142 (uffi:def-foreign-type mysql-field-offset :unsigned-int)
144 (uffi:def-struct mysql-rows
148 (uffi:def-foreign-type mysql-row-offset (:struct-pointer mysql-rows))
150 (uffi:def-struct mysql-data
151 (rows-high32 :unsigned-long)
152 (rows-low32 :unsigned-long)
153 (fields :unsigned-int)
154 (data (:struct-pointer mysql-rows))
155 (alloc (:struct mysql-mem-root)))
158 (uffi:def-struct mysql-options
159 (connect-timeout :unsigned-int)
160 (client-flag :unsigned-int)
161 (compress mysql-bool)
162 (named-pipe mysql-bool)
165 (init-command (* :char))
168 (unix-socket (* :char))
170 (my-cnf-file (* :char))
171 (my-cnf-group (* :char))
172 (charset-dir (* :char))
173 (charset-name (* :char))
178 (ssl-capath (* :char)))
180 (uffi:def-enum mysql-option
186 :read-default-group))
188 (uffi:def-enum mysql-status
193 (uffi:def-struct mysql-mysql
194 (net (:struct mysql-net))
195 (connected-fd (* :char))
199 (unix-socket (* :char))
200 (server-version (* :char))
201 (host-info (* :char))
205 (client-flag :unsigned-int)
206 (server-capabilities :unsigned-int)
207 (protocol-version :unsigned-int)
208 (field-count :unsigned-int)
209 (server-status :unsigned-int)
210 (thread-id :unsigned-long)
211 (affected-rows-high32 :unsigned-long)
212 (affected-rows-low32 :unsigned-long)
213 (insert-id-high32 :unsigned-long)
214 (insert-id-low32 :unsigned-long)
215 (extra-info-high32 :unsigned-long)
216 (extra-info-low32 :unsigned-long)
217 (packet-length :unsigned-long)
218 (status mysql-status)
219 (fields (:struct-pointer mysql-field))
220 (field-alloc (:struct mysql-mem-root))
222 (reconnect mysql-bool)
223 (options (:struct mysql-options))
224 (scramble-buff (:array :char 9))
225 (charset :pointer-void)
226 (server-language :unsigned-int))
230 (uffi:def-struct mysql-mysql-res
231 (row-count-high32 :unsigned-long)
232 (row-count-low32 :unsigned-long)
233 (field-count :unsigned-int)
234 (current-field :unsigned-int)
235 (fields (:struct-pointer mysql-field))
236 (data (:struct-pointer mysql-data))
237 (data-cursor (:struct-pointer mysql-rows))
238 (field-alloc (:struct mysql-mem-root))
240 (current-row mysql-row)
241 (lengths (* :unsigned-long))
242 (handle (:struct-pointer mysql-mysql))
245 ;;;; The Foreign C routines
246 (declaim (inline mysql-init))
247 (uffi:def-function "mysql_init"
248 ((mysql (* mysql-mysql)))
250 :returning (* mysql-mysql))
252 (declaim (inline mysql-connect))
253 (uffi:def-function "mysql_connect"
254 ((mysql (* mysql-mysql))
259 :returning (* mysql-mysql))
261 ;; Need to comment this out for LW 4.2.6
262 ;; ? bug in LW version
263 ;;(declaim (inline mysql-real-connect))
264 (uffi:def-function "mysql_real_connect"
265 ((mysql (* mysql-mysql))
271 (unix-socket :cstring)
272 (clientflag :unsigned-int))
274 :returning (* mysql-mysql))
276 (declaim (inline mysql-close))
277 (uffi:def-function "mysql_close"
278 ((sock (* mysql-mysql)))
282 (declaim (inline mysql-select-db))
283 (uffi:def-function "mysql_select_db"
284 ((mysql (* mysql-mysql))
289 (declaim (inline mysql-query))
290 (uffi:def-function "mysql_query"
291 ((mysql (* mysql-mysql))
296 ;;; I doubt that this function is really useful for direct Lisp usage,
297 ;;; but it is here for completeness...
299 (declaim (inline mysql-real-query))
300 (uffi:def-function "mysql_real_query"
301 ((mysql (* mysql-mysql))
303 (length :unsigned-int))
307 (declaim (inline mysql-create-db))
308 (uffi:def-function "mysql_create_db"
309 ((mysql (* mysql-mysql))
314 (declaim (inline mysql-drop-db))
315 (uffi:def-function "mysql_drop_db"
316 ((mysql (* mysql-mysql))
321 (declaim (inline mysql-shutdown))
322 (uffi:def-function "mysql_shutdown"
323 ((mysql (* mysql-mysql)))
327 (declaim (inline mysql-dump-debug-info))
328 (uffi:def-function "mysql_dump_debug_info"
329 ((mysql (* mysql-mysql)))
333 (declaim (inline mysql-refresh))
334 (uffi:def-function "mysql_refresh"
335 ((mysql (* mysql-mysql))
336 (refresh-options :unsigned-int))
340 (declaim (inline mysql-kill))
341 (uffi:def-function "mysql_kill"
342 ((mysql (* mysql-mysql))
343 (pid :unsigned-long))
347 (declaim (inline mysql-ping))
348 (uffi:def-function "mysql_ping"
349 ((mysql (* mysql-mysql)))
353 (declaim (inline mysql-stat))
354 (uffi:def-function "mysql_stat"
355 ((mysql (* mysql-mysql)))
359 (declaim (inline mysql-get-server-info))
360 (uffi:def-function "mysql_get_server_info"
361 ((mysql (* mysql-mysql)))
365 (declaim (inline mysql-get-client-info))
366 (uffi:def-function "mysql_get_client_info"
371 (declaim (inline mysql-get-host-info))
372 (uffi:def-function "mysql_get_host_info"
373 ((mysql (* mysql-mysql)))
377 (declaim (inline mysql-get-proto-info))
378 (uffi:def-function "mysql_get_proto_info"
379 ((mysql (* mysql-mysql)))
381 :returning :unsigned-int)
383 (declaim (inline mysql-list-dbs))
384 (uffi:def-function "mysql_list_dbs"
385 ((mysql (* mysql-mysql))
388 :returning (* mysql-mysql-res))
390 (declaim (inline mysql-list-tables))
391 (uffi:def-function "mysql_list_tables"
392 ((mysql (* mysql-mysql))
395 :returning (* mysql-mysql-res))
397 (declaim (inline mysql-list-fields))
398 (uffi:def-function "mysql_list_fields"
399 ((mysql (* mysql-mysql))
403 :returning (* mysql-mysql-res))
405 (declaim (inline mysql-list-processes))
406 (uffi:def-function "mysql_list_processes"
407 ((mysql (* mysql-mysql)))
409 :returning (* mysql-mysql-res))
411 (declaim (inline mysql-store-result))
412 (uffi:def-function "mysql_store_result"
413 ((mysql (* mysql-mysql)))
415 :returning (* mysql-mysql-res))
417 (declaim (inline mysql-use-result))
418 (uffi:def-function "mysql_use_result"
419 ((mysql (* mysql-mysql)))
421 :returning (* mysql-mysql-res))
423 (declaim (inline mysql-options))
424 (uffi:def-function "mysql_options"
425 ((mysql (* mysql-mysql))
426 (option mysql-option)
431 (declaim (inline mysql-free-result))
432 (uffi:def-function "mysql_free_result"
433 ((res (* mysql-mysql-res)))
437 (declaim (inline mysql-row-seek))
438 (uffi:def-function "mysql_row_seek"
439 ((res (* mysql-mysql-res))
440 (offset mysql-row-offset))
442 :returning mysql-row-offset)
444 (declaim (inline mysql-field-seek))
445 (uffi:def-function "mysql_field_seek"
446 ((res (* mysql-mysql-res))
447 (offset mysql-field-offset))
449 :returning mysql-field-offset)
451 (declaim (inline mysql-fetch-row))
452 (uffi:def-function "mysql_fetch_row"
453 ((res (* mysql-mysql-res)))
455 :returning (* (* :unsigned-char)))
457 (declaim (inline mysql-fetch-lengths))
458 (uffi:def-function "mysql_fetch_lengths"
459 ((res (* mysql-mysql-res)))
461 :returning (* :unsigned-long))
463 (declaim (inline mysql-fetch-field))
464 (uffi:def-function "mysql_fetch_field"
465 ((res (* mysql-mysql-res)))
467 :returning (* mysql-field))
469 (declaim (inline mysql-fetch-fields))
470 (uffi:def-function "mysql_fetch_fields"
471 ((res (* mysql-mysql-res)))
473 :returning (* mysql-field))
475 (declaim (inline mysql-fetch-field-direct))
476 (uffi:def-function "mysql_fetch_field_direct"
477 ((res (* mysql-mysql-res))
478 (field-num :unsigned-int))
480 :returning (* mysql-field))
482 (declaim (inline mysql-escape-string))
483 (uffi:def-function "mysql_escape_string"
486 (length :unsigned-int))
488 :returning :unsigned-int)
490 (declaim (inline mysql-debug))
491 (uffi:def-function "mysql_debug"
496 (declaim (inline clsql-mysql-num-rows))
497 (uffi:def-function "clsql_mysql_num_rows"
498 ((res (* mysql-mysql-res))
499 (p-high32 (* :unsigned-int)))
500 :module "clsql-mysql"
501 :returning :unsigned-int)
504 ;;;; Equivalents of C Macro definitions for accessing various fields
505 ;;;; in the internal MySQL Datastructures
508 (declaim (inline mysql-num-rows))
509 (defun mysql-num-rows (res)
510 (uffi:with-foreign-object (p-high32 :unsigned-int)
511 (let ((low32 (clsql-mysql-num-rows res p-high32))
512 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
515 (make-64-bit-integer high32 low32)))))
517 (uffi:def-function "clsql_mysql_affected_rows"
518 ((mysql (* mysql-mysql))
519 (p-high32 (* :unsigned-int)))
520 :returning :unsigned-int
521 :module "clsql-mysql")
523 (defun mysql-affected-rows (mysql)
524 (uffi:with-foreign-object (p-high32 :unsigned-int)
525 (let ((low32 (clsql-mysql-affected-rows mysql p-high32))
526 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
529 (make-64-bit-integer high32 low32)))))
531 (uffi:def-function "clsql_mysql_insert_id"
532 ((res (* mysql-mysql))
533 (p-high32 (* :unsigned-int)))
534 :returning :unsigned-int
535 :module "clsql-mysql")
537 (defun mysql-insert-id (mysql)
538 (uffi:with-foreign-object (p-high32 :unsigned-int)
539 (let ((low32 (clsql-mysql-insert-id mysql p-high32))
540 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
543 (make-64-bit-integer high32 low32)))))
546 (declaim (inline mysql-num-fields))
547 (uffi:def-function "mysql_num_fields"
548 ((res (* mysql-mysql-res)))
549 :returning :unsigned-int
552 (declaim (inline clsql-mysql-eof))
553 (uffi:def-function ("mysql_eof" clsql-mysql-eof)
554 ((res (* mysql-mysql-res)))
558 (declaim (inline mysql-eof))
559 (defun mysql-eof (res)
560 (if (zerop (clsql-mysql-eof res))
564 (declaim (inline mysql-error))
565 (uffi:def-function ("mysql_error" mysql-error)
566 ((mysql (* mysql-mysql)))
570 (declaim (inline mysql-error-string))
571 (defun mysql-error-string (mysql)
572 (uffi:convert-from-cstring (mysql-error mysql)))
574 (declaim (inline mysql-errno))
575 (uffi:def-function "mysql_errno"
576 ((mysql (* mysql-mysql)))
577 :returning :unsigned-int
580 (declaim (inline mysql-info))
581 (uffi:def-function ("mysql_info" mysql-info)
582 ((mysql (* mysql-mysql)))
586 (declaim (inline mysql-info-string))
587 (defun mysql-info-string (mysql)
588 (uffi:convert-from-cstring (mysql-info mysql)))
590 (declaim (inline clsql-mysql-data-seek))
591 (uffi:def-function "clsql_mysql_data_seek"
592 ((res (* mysql-mysql-res))
593 (offset-high32 :unsigned-int)
594 (offset-low32 :unsigned-int))
595 :module "clsql-mysql"
599 (defun mysql-data-seek (res offset)
600 (multiple-value-bind (high32 low32) (split-64-bit-integer offset)
601 (clsql-mysql-data-seek res high32 low32)))