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
110 (uffi:def-struct mysql-field
114 (type mysql-field-types)
115 (length :unsigned-int)
116 (max-length :unsigned-int)
117 (flags :unsigned-int)
118 (decimals :unsigned-int))
120 ;; structure changed in mysql 4 client
122 (uffi:def-struct mysql-field
125 (org_table (* :char))
128 (length :unsigned-int)
129 (max-length :unsigned-int)
130 (flags :unsigned-int)
131 (decimals :unsigned-int)
132 (type mysql-field-types))
136 (uffi:def-array-pointer mysql-row (* :unsigned-char))
138 (uffi:def-array-pointer mysql-field-vector (* mysql-field))
140 (uffi:def-foreign-type mysql-field-offset :unsigned-int)
142 (uffi:def-struct mysql-rows
146 (uffi:def-foreign-type mysql-row-offset (:struct-pointer mysql-rows))
148 (uffi:def-struct mysql-data
149 (rows-high32 :unsigned-long)
150 (rows-low32 :unsigned-long)
151 (fields :unsigned-int)
152 (data (:struct-pointer mysql-rows))
153 (alloc (:struct mysql-mem-root)))
156 (uffi:def-struct mysql-options
157 (connect-timeout :unsigned-int)
158 (client-flag :unsigned-int)
159 (compress mysql-bool)
160 (named-pipe mysql-bool)
163 (init-command (* :char))
166 (unix-socket (* :char))
168 (my-cnf-file (* :char))
169 (my-cnf-group (* :char))
170 (charset-dir (* :char))
171 (charset-name (* :char))
176 (ssl-capath (* :char)))
178 (uffi:def-enum mysql-option
184 :read-default-group))
186 (uffi:def-enum mysql-status
191 (uffi:def-struct mysql-mysql
192 (net (:struct mysql-net))
193 (connected-fd (* :char))
197 (unix-socket (* :char))
198 (server-version (* :char))
199 (host-info (* :char))
203 (client-flag :unsigned-int)
204 (server-capabilities :unsigned-int)
205 (protocol-version :unsigned-int)
206 (field-count :unsigned-int)
207 (server-status :unsigned-int)
208 (thread-id :unsigned-long)
209 (affected-rows-high32 :unsigned-long)
210 (affected-rows-low32 :unsigned-long)
211 (insert-id-high32 :unsigned-long)
212 (insert-id-low32 :unsigned-long)
213 (extra-info-high32 :unsigned-long)
214 (extra-info-low32 :unsigned-long)
215 (packet-length :unsigned-long)
216 (status mysql-status)
217 (fields (:struct-pointer mysql-field))
218 (field-alloc (:struct mysql-mem-root))
220 (reconnect mysql-bool)
221 (options (:struct mysql-options))
222 (scramble-buff (:array :char 9))
223 (charset :pointer-void)
224 (server-language :unsigned-int))
228 (uffi:def-struct mysql-mysql-res
229 (row-count-high32 :unsigned-long)
230 (row-count-low32 :unsigned-long)
231 (field-count :unsigned-int)
232 (current-field :unsigned-int)
233 (fields (:struct-pointer mysql-field))
234 (data (:struct-pointer mysql-data))
235 (data-cursor (:struct-pointer mysql-rows))
236 (field-alloc (:struct mysql-mem-root))
238 (current-row mysql-row)
239 (lengths (* :unsigned-long))
240 (handle (:struct-pointer mysql-mysql))
243 ;;;; The Foreign C routines
244 (declaim (inline mysql-init))
245 (uffi:def-function "mysql_init"
246 ((mysql (* mysql-mysql)))
248 :returning (* mysql-mysql))
251 (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 #-lispworks (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))
308 (declaim (inline mysql-create-db))
310 (uffi:def-function "mysql_create_db"
311 ((mysql (* mysql-mysql))
317 (declaim (inline mysql-drop-db))
319 (uffi:def-function "mysql_drop_db"
320 ((mysql (* mysql-mysql))
325 (declaim (inline mysql-shutdown))
326 (uffi:def-function "mysql_shutdown"
327 ((mysql (* mysql-mysql)))
331 (declaim (inline mysql-dump-debug-info))
332 (uffi:def-function "mysql_dump_debug_info"
333 ((mysql (* mysql-mysql)))
337 (declaim (inline mysql-refresh))
338 (uffi:def-function "mysql_refresh"
339 ((mysql (* mysql-mysql))
340 (refresh-options :unsigned-int))
344 (declaim (inline mysql-kill))
345 (uffi:def-function "mysql_kill"
346 ((mysql (* mysql-mysql))
347 (pid :unsigned-long))
351 (declaim (inline mysql-ping))
352 (uffi:def-function "mysql_ping"
353 ((mysql (* mysql-mysql)))
357 (declaim (inline mysql-stat))
358 (uffi:def-function "mysql_stat"
359 ((mysql (* mysql-mysql)))
363 (declaim (inline mysql-get-server-info))
364 (uffi:def-function "mysql_get_server_info"
365 ((mysql (* mysql-mysql)))
369 (declaim (inline mysql-get-host-info))
370 (uffi:def-function "mysql_get_host_info"
371 ((mysql (* mysql-mysql)))
375 (declaim (inline mysql-get-proto-info))
376 (uffi:def-function "mysql_get_proto_info"
377 ((mysql (* mysql-mysql)))
379 :returning :unsigned-int)
381 (declaim (inline mysql-list-dbs))
382 (uffi:def-function "mysql_list_dbs"
383 ((mysql (* mysql-mysql))
386 :returning (* mysql-mysql-res))
388 (declaim (inline mysql-list-tables))
389 (uffi:def-function "mysql_list_tables"
390 ((mysql (* mysql-mysql))
393 :returning (* mysql-mysql-res))
395 (declaim (inline mysql-list-fields))
396 (uffi:def-function "mysql_list_fields"
397 ((mysql (* mysql-mysql))
401 :returning (* mysql-mysql-res))
403 (declaim (inline mysql-list-processes))
404 (uffi:def-function "mysql_list_processes"
405 ((mysql (* mysql-mysql)))
407 :returning (* mysql-mysql-res))
409 (declaim (inline mysql-store-result))
410 (uffi:def-function "mysql_store_result"
411 ((mysql (* mysql-mysql)))
413 :returning (* mysql-mysql-res))
415 (declaim (inline mysql-use-result))
416 (uffi:def-function "mysql_use_result"
417 ((mysql (* mysql-mysql)))
419 :returning (* mysql-mysql-res))
421 (declaim (inline mysql-options))
422 (uffi:def-function "mysql_options"
423 ((mysql (* mysql-mysql))
424 (option mysql-option)
429 (declaim (inline mysql-free-result))
430 (uffi:def-function "mysql_free_result"
431 ((res (* mysql-mysql-res)))
435 (declaim (inline mysql-row-seek))
436 (uffi:def-function "mysql_row_seek"
437 ((res (* mysql-mysql-res))
438 (offset mysql-row-offset))
440 :returning mysql-row-offset)
442 (declaim (inline mysql-field-seek))
443 (uffi:def-function "mysql_field_seek"
444 ((res (* mysql-mysql-res))
445 (offset mysql-field-offset))
447 :returning mysql-field-offset)
449 (declaim (inline mysql-fetch-row))
450 (uffi:def-function "mysql_fetch_row"
451 ((res (* mysql-mysql-res)))
453 :returning (* (* :unsigned-char)))
455 (declaim (inline mysql-fetch-lengths))
456 (uffi:def-function "mysql_fetch_lengths"
457 ((res (* mysql-mysql-res)))
459 :returning (* :unsigned-long))
461 (declaim (inline mysql-fetch-field))
462 (uffi:def-function "mysql_fetch_field"
463 ((res (* mysql-mysql-res)))
465 :returning (* mysql-field))
467 (declaim (inline mysql-fetch-fields))
468 (uffi:def-function "mysql_fetch_fields"
469 ((res (* mysql-mysql-res)))
471 :returning (* mysql-field))
473 (declaim (inline mysql-fetch-field-direct))
474 (uffi:def-function "mysql_fetch_field_direct"
475 ((res (* mysql-mysql-res))
476 (field-num :unsigned-int))
478 :returning (* mysql-field))
480 (declaim (inline mysql-escape-string))
481 (uffi:def-function "mysql_escape_string"
484 (length :unsigned-int))
486 :returning :unsigned-int)
488 (declaim (inline mysql-debug))
489 (uffi:def-function "mysql_debug"
494 (declaim (inline clsql-mysql-num-rows))
495 (uffi:def-function "clsql_mysql_num_rows"
496 ((res (* mysql-mysql-res))
497 (p-high32 (* :unsigned-int)))
498 :module "clsql-mysql"
499 :returning :unsigned-int)
502 ;;;; Equivalents of C Macro definitions for accessing various fields
503 ;;;; in the internal MySQL Datastructures
506 (declaim (inline mysql-num-rows))
507 (defun mysql-num-rows (res)
508 (uffi:with-foreign-object (p-high32 :unsigned-int)
509 (let ((low32 (clsql-mysql-num-rows res p-high32))
510 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
513 (make-64-bit-integer high32 low32)))))
515 (uffi:def-function "clsql_mysql_affected_rows"
516 ((mysql (* mysql-mysql))
517 (p-high32 (* :unsigned-int)))
518 :returning :unsigned-int
519 :module "clsql-mysql")
521 (defun mysql-affected-rows (mysql)
522 (uffi:with-foreign-object (p-high32 :unsigned-int)
523 (let ((low32 (clsql-mysql-affected-rows mysql p-high32))
524 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
527 (make-64-bit-integer high32 low32)))))
529 (uffi:def-function "clsql_mysql_insert_id"
530 ((res (* mysql-mysql))
531 (p-high32 (* :unsigned-int)))
532 :returning :unsigned-int
533 :module "clsql-mysql")
535 (defun mysql-insert-id (mysql)
536 (uffi:with-foreign-object (p-high32 :unsigned-int)
537 (let ((low32 (clsql-mysql-insert-id mysql p-high32))
538 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
541 (make-64-bit-integer high32 low32)))))
544 (declaim (inline mysql-num-fields))
545 (uffi:def-function "mysql_num_fields"
546 ((res (* mysql-mysql-res)))
547 :returning :unsigned-int
550 (declaim (inline clsql-mysql-eof))
551 (uffi:def-function ("mysql_eof" clsql-mysql-eof)
552 ((res (* mysql-mysql-res)))
556 (declaim (inline mysql-eof))
557 (defun mysql-eof (res)
558 (if (zerop (clsql-mysql-eof res))
562 (declaim (inline mysql-error))
563 (uffi:def-function ("mysql_error" mysql-error)
564 ((mysql (* mysql-mysql)))
568 (declaim (inline mysql-error-string))
569 (defun mysql-error-string (mysql)
570 (uffi:convert-from-cstring (mysql-error mysql)))
572 (declaim (inline mysql-errno))
573 (uffi:def-function "mysql_errno"
574 ((mysql (* mysql-mysql)))
575 :returning :unsigned-int
578 (declaim (inline mysql-info))
579 (uffi:def-function ("mysql_info" mysql-info)
580 ((mysql (* mysql-mysql)))
584 (declaim (inline mysql-info-string))
585 (defun mysql-info-string (mysql)
586 (uffi:convert-from-cstring (mysql-info mysql)))
588 (declaim (inline clsql-mysql-data-seek))
589 (uffi:def-function "clsql_mysql_data_seek"
590 ((res (* mysql-mysql-res))
591 (offset-high32 :unsigned-int)
592 (offset-low32 :unsigned-int))
593 :module "clsql-mysql"
597 (defun mysql-data-seek (res offset)
598 (multiple-value-bind (high32 low32) (split-64-bit-integer offset)
599 (clsql-mysql-data-seek res high32 low32)))