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
121 #+(and mysql-client-v4 (not mysql-client-v4.1))
122 (uffi:def-struct mysql-field
125 (org_table (* :char))
128 (length :unsigned-long)
129 (max-length :unsigned-long)
130 (flags :unsigned-int)
131 (decimals :unsigned-int)
132 (type mysql-field-types))
135 (uffi:def-struct mysql-field
137 (org_table (* :char))
139 (org_table (* :char))
141 (catalog_db (* :char))
143 (length :unsigned-long)
144 (max-length :unsigned-long)
145 (name-length :unsigned-int)
146 (org-name-length :unsigned-int)
147 (table-length :unsigned-int)
148 (org-table-length :unsigned-int)
149 (db-length :unsigned-int)
150 (catalog-length :unsigned-int)
151 (def-length :unsigned-int)
152 (flags :unsigned-int)
153 (decimals :unsigned-int)
154 (charsetnr :unsigned-int)
155 (type mysql-field-types))
159 (uffi:def-array-pointer mysql-row (* :unsigned-char))
161 (uffi:def-array-pointer mysql-field-vector (* mysql-field))
163 (uffi:def-foreign-type mysql-field-offset :unsigned-int)
165 (uffi:def-struct mysql-rows
169 (uffi:def-foreign-type mysql-row-offset (:struct-pointer mysql-rows))
171 (uffi:def-struct mysql-data
172 (rows-high32 :unsigned-long)
173 (rows-low32 :unsigned-long)
174 (fields :unsigned-int)
175 (data (:struct-pointer mysql-rows))
176 (alloc (:struct mysql-mem-root)))
179 (uffi:def-struct mysql-options
180 (connect-timeout :unsigned-int)
181 (client-flag :unsigned-int)
182 (compress mysql-bool)
183 (named-pipe mysql-bool)
186 (init-command (* :char))
189 (unix-socket (* :char))
191 (my-cnf-file (* :char))
192 (my-cnf-group (* :char))
193 (charset-dir (* :char))
194 (charset-name (* :char))
199 (ssl-capath (* :char)))
201 (uffi:def-enum mysql-option
207 :read-default-group))
209 (uffi:def-enum mysql-status
214 (uffi:def-struct mysql-mysql
215 (net (:struct mysql-net))
216 (connected-fd (* :char))
220 (unix-socket (* :char))
221 (server-version (* :char))
222 (host-info (* :char))
226 (client-flag :unsigned-int)
227 (server-capabilities :unsigned-int)
228 (protocol-version :unsigned-int)
229 (field-count :unsigned-int)
230 (server-status :unsigned-int)
231 (thread-id :unsigned-long)
232 (affected-rows-high32 :unsigned-long)
233 (affected-rows-low32 :unsigned-long)
234 (insert-id-high32 :unsigned-long)
235 (insert-id-low32 :unsigned-long)
236 (extra-info-high32 :unsigned-long)
237 (extra-info-low32 :unsigned-long)
238 (packet-length :unsigned-long)
239 (status mysql-status)
240 (fields (:struct-pointer mysql-field))
241 (field-alloc (:struct mysql-mem-root))
243 (reconnect mysql-bool)
244 (options (:struct mysql-options))
245 (scramble-buff (:array :char 9))
246 (charset :pointer-void)
247 (server-language :unsigned-int))
251 (uffi:def-struct mysql-mysql-res
252 (row-count-high32 :unsigned-long)
253 (row-count-low32 :unsigned-long)
254 (field-count :unsigned-int)
255 (current-field :unsigned-int)
256 (fields (:struct-pointer mysql-field))
257 (data (:struct-pointer mysql-data))
258 (data-cursor (:struct-pointer mysql-rows))
259 (field-alloc (:struct mysql-mem-root))
261 (current-row mysql-row)
262 (lengths (* :unsigned-long))
263 (handle (:struct-pointer mysql-mysql))
266 ;;;; The Foreign C routines
267 (declaim (inline mysql-init))
268 (uffi:def-function "mysql_init"
269 ((mysql (* mysql-mysql)))
271 :returning (* mysql-mysql))
274 (declaim (inline mysql-connect))
276 (uffi:def-function "mysql_connect"
277 ((mysql (* mysql-mysql))
282 :returning (* mysql-mysql))
284 ;; Need to comment this out for LW 4.2.6
285 ;; ? bug in LW version
286 #-lispworks (declaim (inline mysql-real-connect))
287 (uffi:def-function "mysql_real_connect"
288 ((mysql (* mysql-mysql))
294 (unix-socket :cstring)
295 (clientflag :unsigned-long))
297 :returning (* mysql-mysql))
299 (declaim (inline mysql-close))
300 (uffi:def-function "mysql_close"
301 ((sock (* mysql-mysql)))
305 (declaim (inline mysql-select-db))
306 (uffi:def-function "mysql_select_db"
307 ((mysql (* mysql-mysql))
312 (declaim (inline mysql-query))
313 (uffi:def-function "mysql_query"
314 ((mysql (* mysql-mysql))
319 ;;; I doubt that this function is really useful for direct Lisp usage,
320 ;;; but it is here for completeness...
322 (declaim (inline mysql-real-query))
323 (uffi:def-function "mysql_real_query"
324 ((mysql (* mysql-mysql))
326 (length :unsigned-int))
331 (declaim (inline mysql-create-db))
333 (uffi:def-function "mysql_create_db"
334 ((mysql (* mysql-mysql))
340 (declaim (inline mysql-drop-db))
342 (uffi:def-function "mysql_drop_db"
343 ((mysql (* mysql-mysql))
348 (declaim (inline mysql-shutdown))
349 (uffi:def-function "mysql_shutdown"
350 ((mysql (* mysql-mysql)))
354 (declaim (inline mysql-dump-debug-info))
355 (uffi:def-function "mysql_dump_debug_info"
356 ((mysql (* mysql-mysql)))
360 (declaim (inline mysql-refresh))
361 (uffi:def-function "mysql_refresh"
362 ((mysql (* mysql-mysql))
363 (refresh-options :unsigned-int))
367 (declaim (inline mysql-kill))
368 (uffi:def-function "mysql_kill"
369 ((mysql (* mysql-mysql))
370 (pid :unsigned-long))
374 (declaim (inline mysql-ping))
375 (uffi:def-function "mysql_ping"
376 ((mysql (* mysql-mysql)))
380 (declaim (inline mysql-stat))
381 (uffi:def-function "mysql_stat"
382 ((mysql (* mysql-mysql)))
386 (declaim (inline mysql-get-server-info))
387 (uffi:def-function "mysql_get_server_info"
388 ((mysql (* mysql-mysql)))
392 (declaim (inline mysql-get-host-info))
393 (uffi:def-function "mysql_get_host_info"
394 ((mysql (* mysql-mysql)))
398 (declaim (inline mysql-get-proto-info))
399 (uffi:def-function "mysql_get_proto_info"
400 ((mysql (* mysql-mysql)))
402 :returning :unsigned-int)
404 (declaim (inline mysql-list-dbs))
405 (uffi:def-function "mysql_list_dbs"
406 ((mysql (* mysql-mysql))
409 :returning (* mysql-mysql-res))
411 (declaim (inline mysql-list-tables))
412 (uffi:def-function "mysql_list_tables"
413 ((mysql (* mysql-mysql))
416 :returning (* mysql-mysql-res))
418 (declaim (inline mysql-list-fields))
419 (uffi:def-function "mysql_list_fields"
420 ((mysql (* mysql-mysql))
424 :returning (* mysql-mysql-res))
426 (declaim (inline mysql-list-processes))
427 (uffi:def-function "mysql_list_processes"
428 ((mysql (* mysql-mysql)))
430 :returning (* mysql-mysql-res))
432 (declaim (inline mysql-store-result))
433 (uffi:def-function "mysql_store_result"
434 ((mysql (* mysql-mysql)))
436 :returning (* mysql-mysql-res))
438 (declaim (inline mysql-use-result))
439 (uffi:def-function "mysql_use_result"
440 ((mysql (* mysql-mysql)))
442 :returning (* mysql-mysql-res))
444 (declaim (inline mysql-options))
445 (uffi:def-function "mysql_options"
446 ((mysql (* mysql-mysql))
447 (option mysql-option)
452 (declaim (inline mysql-free-result))
453 (uffi:def-function "mysql_free_result"
454 ((res (* mysql-mysql-res)))
458 (declaim (inline mysql-row-seek))
459 (uffi:def-function "mysql_row_seek"
460 ((res (* mysql-mysql-res))
461 (offset mysql-row-offset))
463 :returning mysql-row-offset)
465 (declaim (inline mysql-field-seek))
466 (uffi:def-function "mysql_field_seek"
467 ((res (* mysql-mysql-res))
468 (offset mysql-field-offset))
470 :returning mysql-field-offset)
472 (declaim (inline mysql-fetch-row))
473 (uffi:def-function "mysql_fetch_row"
474 ((res (* mysql-mysql-res)))
476 :returning (* (* :unsigned-char)))
478 (declaim (inline mysql-fetch-lengths))
479 (uffi:def-function "mysql_fetch_lengths"
480 ((res (* mysql-mysql-res)))
482 :returning (* :unsigned-long))
484 (declaim (inline mysql-fetch-field))
485 (uffi:def-function "mysql_fetch_field"
486 ((res (* mysql-mysql-res)))
488 :returning (* mysql-field))
490 (declaim (inline mysql-fetch-fields))
491 (uffi:def-function "mysql_fetch_fields"
492 ((res (* mysql-mysql-res)))
494 :returning (* mysql-field))
496 (declaim (inline mysql-fetch-field-direct))
497 (uffi:def-function "mysql_fetch_field_direct"
498 ((res (* mysql-mysql-res))
499 (field-num :unsigned-int))
501 :returning (* mysql-field))
503 (declaim (inline mysql-escape-string))
504 (uffi:def-function "mysql_escape_string"
507 (length :unsigned-int))
509 :returning :unsigned-int)
511 (declaim (inline mysql-debug))
512 (uffi:def-function "mysql_debug"
517 (declaim (inline clsql-mysql-num-rows))
518 (uffi:def-function "clsql_mysql_num_rows"
519 ((res (* mysql-mysql-res))
520 (p-high32 (* :unsigned-int)))
521 :module "clsql-mysql"
522 :returning :unsigned-int)
525 ;;;; Equivalents of C Macro definitions for accessing various fields
526 ;;;; in the internal MySQL Datastructures
529 (declaim (inline mysql-num-rows))
530 (defun mysql-num-rows (res)
531 (uffi:with-foreign-object (p-high32 :unsigned-int)
532 (let ((low32 (clsql-mysql-num-rows res p-high32))
533 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
536 (make-64-bit-integer high32 low32)))))
538 (uffi:def-function "clsql_mysql_affected_rows"
539 ((mysql (* mysql-mysql))
540 (p-high32 (* :unsigned-int)))
541 :returning :unsigned-int
542 :module "clsql-mysql")
544 (defun mysql-affected-rows (mysql)
545 (uffi:with-foreign-object (p-high32 :unsigned-int)
546 (let ((low32 (clsql-mysql-affected-rows mysql p-high32))
547 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
550 (make-64-bit-integer high32 low32)))))
552 (uffi:def-function "clsql_mysql_insert_id"
553 ((res (* mysql-mysql))
554 (p-high32 (* :unsigned-int)))
555 :returning :unsigned-int
556 :module "clsql-mysql")
558 (defun mysql-insert-id (mysql)
559 (uffi:with-foreign-object (p-high32 :unsigned-int)
560 (let ((low32 (clsql-mysql-insert-id mysql p-high32))
561 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
564 (make-64-bit-integer high32 low32)))))
567 (declaim (inline mysql-num-fields))
568 (uffi:def-function "mysql_num_fields"
569 ((res (* mysql-mysql-res)))
570 :returning :unsigned-int
573 (declaim (inline clsql-mysql-eof))
574 (uffi:def-function ("mysql_eof" clsql-mysql-eof)
575 ((res (* mysql-mysql-res)))
579 (declaim (inline mysql-eof))
580 (defun mysql-eof (res)
581 (if (zerop (clsql-mysql-eof res))
585 (declaim (inline mysql-error))
586 (uffi:def-function ("mysql_error" mysql-error)
587 ((mysql (* mysql-mysql)))
591 (declaim (inline mysql-error-string))
592 (defun mysql-error-string (mysql)
593 (uffi:convert-from-cstring (mysql-error mysql)))
595 (declaim (inline mysql-errno))
596 (uffi:def-function "mysql_errno"
597 ((mysql (* mysql-mysql)))
598 :returning :unsigned-int
601 (declaim (inline mysql-info))
602 (uffi:def-function ("mysql_info" mysql-info)
603 ((mysql (* mysql-mysql)))
607 (declaim (inline mysql-info-string))
608 (defun mysql-info-string (mysql)
609 (uffi:convert-from-cstring (mysql-info mysql)))
611 (declaim (inline clsql-mysql-data-seek))
612 (uffi:def-function "clsql_mysql_data_seek"
613 ((res (* mysql-mysql-res))
614 (offset-high32 :unsigned-int)
615 (offset-low32 :unsigned-int))
616 :module "clsql-mysql"
620 (defun mysql-data-seek (res offset)
621 (multiple-value-bind (high32 low32) (split-64-bit-integer offset)
622 (clsql-mysql-data-seek res high32 low32)))