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.cl,v 1.3 2002/03/27 08:09:25 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 (* mysql-used-mem))
79 (used (* mysql-used-mem))
80 (pre-alloc (* 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 (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))
123 (uffi:def-array-pointer mysql-row (* :unsigned-char))
124 (uffi:def-array-pointer mysql-field-vector (* mysql-field))
126 (uffi:def-foreign-type mysql-field-offset :unsigned-int)
128 (uffi:def-struct mysql-rows
132 (uffi:def-foreign-type mysql-row-offset (* mysql-rows))
134 (uffi:def-struct mysql-data
135 (rows-high32 :unsigned-long)
136 (rows-low32 :unsigned-long)
137 (fields :unsigned-int)
138 (data (* mysql-rows))
139 (alloc mysql-mem-root))
142 (uffi:def-struct mysql-options
143 (connect-timeout :unsigned-int)
144 (client-flag :unsigned-int)
145 (compress mysql-bool)
146 (named-pipe mysql-bool)
149 (init-command (* :char))
152 (unix-socket (* :char))
154 (my-cnf-file (* :char))
155 (my-cnf-group (* :char))
156 (charset-dir (* :char))
157 (charset-name (* :char))
162 (ssl-capath (* :char)))
164 (uffi:def-enum mysql-option
170 :read-default-group))
172 (uffi:def-enum mysql-status
177 (uffi:def-struct mysql-mysql
179 (connected-fd (* :char))
183 (unix-socket (* :char))
184 (server-version (* :char))
185 (host-info (* :char))
189 (client-flag :unsigned-int)
190 (server-capabilities :unsigned-int)
191 (protocol-version :unsigned-int)
192 (field-count :unsigned-int)
193 (server-status :unsigned-int)
194 (thread-id :unsigned-long)
195 (affected-rows-high32 :unsigned-long)
196 (affected-rows-low32 :unsigned-long)
197 (insert-id-high32 :unsigned-long)
198 (insert-id-low32 :unsigned-long)
199 (extra-info-high32 :unsigned-long)
200 (extra-info-low32 :unsigned-long)
201 (packet-length :unsigned-long)
202 (status mysql-status)
203 (fields (* mysql-field))
204 (field-alloc mysql-mem-root)
206 (reconnect mysql-bool)
207 (options mysql-options)
208 (scramble-buff (:array :char 9))
209 (charset :pointer-void)
210 (server-language :unsigned-int))
214 (uffi:def-struct mysql-mysql-res
215 (row-count-high32 :unsigned-long)
216 (row-count-low32 :unsigned-long)
217 (field-count :unsigned-int)
218 (current-field :unsigned-int)
219 (fields (* mysql-field))
220 (data (* mysql-data))
221 (data-cursor (* mysql-rows))
222 (field-alloc mysql-mem-root)
224 (current-row mysql-row)
225 (lengths (* :unsigned-long))
226 (handle (* mysql-mysql))
229 ;;;; The Foreign C routines
230 (declaim (inline mysql-init))
231 (uffi:def-function "mysql_init"
232 ((mysql (* mysql-mysql)))
234 :returning (* mysql-mysql))
236 (declaim (inline mysql-connect))
237 (uffi:def-function "mysql_connect"
238 ((mysql (* mysql-mysql))
243 :returning (* mysql-mysql))
245 (declaim (inline mysql-real-connect))
246 (uffi:def-function "mysql_real_connect"
247 ((mysql (* mysql-mysql))
253 (unix-socket :cstring)
254 (clientflag :unsigned-int))
256 :returning (* mysql-mysql))
258 (declaim (inline mysql-close))
259 (uffi:def-function "mysql_close"
260 ((sock (* mysql-mysql)))
264 (declaim (inline mysql-select-db))
265 (uffi:def-function "mysql_select_db"
266 ((mysql (* mysql-mysql))
271 (declaim (inline mysql-query))
272 (uffi:def-function "mysql_query"
273 ((mysql (* mysql-mysql))
278 ;;; I doubt that this function is really useful for direct Lisp usage,
279 ;;; but it is here for completeness...
281 (declaim (inline mysql-real-query))
282 (uffi:def-function "mysql_real_query"
283 ((mysql (* mysql-mysql))
285 (length :unsigned-int))
289 (declaim (inline mysql-create-db))
290 (uffi:def-function "mysql_create_db"
291 ((mysql (* mysql-mysql))
296 (declaim (inline mysql-drop-db))
297 (uffi:def-function "mysql_drop_db"
298 ((mysql (* mysql-mysql))
303 (declaim (inline mysql-shutdown))
304 (uffi:def-function "mysql_shutdown"
305 ((mysql (* mysql-mysql)))
309 (declaim (inline mysql-dump-debug-info))
310 (uffi:def-function "mysql_dump_debug_info"
311 ((mysql (* mysql-mysql)))
315 (declaim (inline mysql-refresh))
316 (uffi:def-function "mysql_refresh"
317 ((mysql (* mysql-mysql))
318 (refresh-options :unsigned-int))
322 (declaim (inline mysql-kill))
323 (uffi:def-function "mysql_kill"
324 ((mysql (* mysql-mysql))
325 (pid :unsigned-long))
329 (declaim (inline mysql-ping))
330 (uffi:def-function "mysql_ping"
331 ((mysql (* mysql-mysql)))
335 (declaim (inline mysql-stat))
336 (uffi:def-function "mysql_stat"
337 ((mysql (* mysql-mysql)))
341 (declaim (inline mysql-get-server-info))
342 (uffi:def-function "mysql_get_server_info"
343 ((mysql (* mysql-mysql)))
347 (declaim (inline mysql-get-client-info))
348 (uffi:def-function "mysql_get_client_info"
353 (declaim (inline mysql-get-host-info))
354 (uffi:def-function "mysql_get_host_info"
355 ((mysql (* mysql-mysql)))
359 (declaim (inline mysql-get-proto-info))
360 (uffi:def-function "mysql_get_proto_info"
361 ((mysql (* mysql-mysql)))
363 :returning :unsigned-int)
365 (declaim (inline mysql-list-dbs))
366 (uffi:def-function "mysql_list_dbs"
367 ((mysql (* mysql-mysql))
370 :returning (* mysql-mysql-res))
372 (declaim (inline mysql-list-tables))
373 (uffi:def-function "mysql_list_tables"
374 ((mysql (* mysql-mysql))
377 :returning (* mysql-mysql-res))
379 (declaim (inline mysql-list-fields))
380 (uffi:def-function "mysql_list_fields"
381 ((mysql (* mysql-mysql))
385 :returning (* mysql-mysql-res))
387 (declaim (inline mysql-list-processes))
388 (uffi:def-function "mysql_list_processes"
389 ((mysql (* mysql-mysql)))
391 :returning (* mysql-mysql-res))
393 (declaim (inline mysql-store-result))
394 (uffi:def-function "mysql_store_result"
395 ((mysql (* mysql-mysql)))
397 :returning (* mysql-mysql-res))
399 (declaim (inline mysql-use-result))
400 (uffi:def-function "mysql_use_result"
401 ((mysql (* mysql-mysql)))
403 :returning (* mysql-mysql-res))
405 (declaim (inline mysql-options))
406 (uffi:def-function "mysql_options"
407 ((mysql (* mysql-mysql))
408 (option mysql-option)
413 (declaim (inline mysql-free-result))
414 (uffi:def-function "mysql_free_result"
415 ((res (* mysql-mysql-res)))
419 (declaim (inline mysql-row-seek))
420 (uffi:def-function "mysql_row_seek"
421 ((res (* mysql-mysql-res))
422 (offset mysql-row-offset))
424 :returning mysql-row-offset)
426 (declaim (inline mysql-field-seek))
427 (uffi:def-function "mysql_field_seek"
428 ((res (* mysql-mysql-res))
429 (offset mysql-field-offset))
431 :returning mysql-field-offset)
433 (declaim (inline mysql-fetch-row))
434 (uffi:def-function "mysql_fetch_row"
435 ((res (* mysql-mysql-res)))
437 :returning mysql-row)
439 (declaim (inline mysql-fetch-lengths))
440 (uffi:def-function "mysql_fetch_lengths"
441 ((res (* mysql-mysql-res)))
443 :returning (* :unsigned-long))
445 (declaim (inline mysql-fetch-field))
446 (uffi:def-function "mysql_fetch_field"
447 ((res (* mysql-mysql-res)))
449 :returning (* mysql-field))
451 (declaim (inline mysql-fetch-fields))
452 (uffi:def-function "mysql_fetch_fields"
453 ((res (* mysql-mysql-res)))
455 :returning mysql-field-vector)
457 (declaim (inline mysql-fetch-field-direct))
458 (uffi:def-function "mysql_fetch_field_direct"
459 ((res (* mysql-mysql-res))
460 (field-num :unsigned-int))
462 :returning (* mysql-field))
464 (declaim (inline mysql-escape-string))
465 (uffi:def-function "mysql_escape_string"
468 (length :unsigned-int))
470 :returning :unsigned-int)
472 (declaim (inline mysql-debug))
473 (uffi:def-function "mysql_debug"
478 (declaim (inline clsql-mysql-num-rows))
479 (uffi:def-function "clsql_mysql_num_rows"
480 ((res (* mysql-mysql-res))
481 (p-high32 (* :unsigned-int)))
482 :module "clsql-mysql"
483 :returning :unsigned-int)
486 ;;;; Equivalents of C Macro definitions for accessing various fields
487 ;;;; in the internal MySQL Datastructures
490 (declaim (inline mysql-num-rows))
491 (defun mysql-num-rows (res)
492 (uffi:with-foreign-object (p-high32 :unsigned-int)
493 (let ((low32 (clsql-mysql-num-rows res p-high32))
494 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
497 (make-64-bit-integer high32 low32)))))
499 (uffi:def-function "clsql_mysql_affected_rows"
500 ((mysql (* mysql-mysql))
501 (p-high32 (* :unsigned-int)))
502 :returning :unsigned-int
503 :module "clsql-mysql")
505 (defun mysql-affected-rows (mysql)
506 (uffi:with-foreign-object (p-high32 :unsigned-int)
507 (let ((low32 (clsql-mysql-affected-rows mysql p-high32))
508 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
511 (make-64-bit-integer high32 low32)))))
513 (uffi:def-function "clsql_mysql_insert_id"
514 ((res (* mysql-mysql))
515 (p-high32 (* :unsigned-int)))
516 :returning :unsigned-int
517 :module "clsql-mysql")
519 (defun mysql-insert-id (mysql)
520 (uffi:with-foreign-object (p-high32 :unsigned-int)
521 (let ((low32 (clsql-mysql-insert-id mysql p-high32))
522 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
525 (make-64-bit-integer high32 low32)))))
528 (declaim (inline mysql-num-fields))
529 (uffi:def-function "mysql_num_fields"
530 ((res (* mysql-mysql-res)))
531 :returning :unsigned-int
534 (declaim (inline clsql-mysql-eof))
535 (uffi:def-function ("mysql_eof" clsql-mysql-eof)
536 ((res (* mysql-mysql-res)))
540 (declaim (inline mysql-eof))
541 (defun mysql-eof (res)
542 (if (zerop (clsql-mysql-eof res))
546 (declaim (inline mysql-error))
547 (uffi:def-function ("mysql_error" mysql-error)
548 ((mysql (* mysql-mysql)))
552 (declaim (inline mysql-error-string))
553 (defun mysql-error-string (mysql)
554 (uffi:convert-from-cstring (mysql-error mysql)))
556 (declaim (inline mysql-errno))
557 (uffi:def-function "mysql_errno"
558 ((mysql (* mysql-mysql)))
559 :returning :unsigned-int
562 (declaim (inline mysql-info))
563 (uffi:def-function ("mysql_info" mysql-info)
564 ((mysql (* mysql-mysql)))
568 (declaim (inline mysql-info-string))
569 (defun mysql-info-string (mysql)
570 (uffi:convert-from-cstring (mysql-info mysql)))
572 (declaim (inline clsql-mysql-data-seek))
573 (uffi:def-function "clsql_mysql_data_seek"
574 ((res (* mysql-mysql-res))
575 (offset-high32 :unsigned-int)
576 (offset-low32 :unsigned-int))
577 :module "clsql-mysql"
581 (defun mysql-data-seek (res offset)
582 (multiple-value-bind (high32 low32) (split-64-bit-integer offset)
583 (clsql-mysql-data-seek res high32 low32)))