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
11 ;;;; This file, part of CLSQL, is Copyright (c) 2002-2009 by Kevin M. Rosenberg
12 ;;;; and Copyright (c) 1999-2001 by Pierre R. Mai
14 ;;;; CLSQL users are granted the rights to distribute and use this software
15 ;;;; as governed by the terms of the Lisp Lesser GNU Public License
16 ;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL.
17 ;;;; *************************************************************************
21 ;;;; Modifications from original code
22 ;;;; - Updated C-structures to conform to structures in MySQL 3.23.46
23 ;;;; - Changed from CMUCL interface to UFFI
24 ;;;; - Added and call a C-helper file to support 64-bit integers
25 ;;;; that are used in a few routines.
26 ;;;; - Removed all references to interiors of C-structions, this will
27 ;;;; increase robustness when MySQL's internal structures change.
33 (uffi:def-foreign-type mysql-socket :int)
34 (uffi:def-foreign-type mysql-bool :byte)
35 (uffi:def-foreign-type mysql-byte :unsigned-char)
37 (uffi:def-enum mysql-net-type
42 (uffi:def-array-pointer mysql-row (* :unsigned-char))
45 (uffi:def-enum mysql-field-types
71 (uffi:def-enum mysql-option
82 :shared-memory-base-name
86 :use-remote-connection
87 :use-embedded-connection
91 :report-data-truncation
93 :ssl-verify-server-cert))
95 (defvar +mysql-option-parameter-map+
96 '((:connect-timeout . :uint-ptr)
99 (:init-command . :char-ptr)
100 (:read-default-file . :char-ptr)
101 (:read-default-group . :char-ptr)
102 (:set-charset-dir . :char-ptr)
103 (:set-charset-name . :char-ptr)
104 (:local-infile . :uint-ptr)
105 (:protocol . :uint-ptr)
106 (:shared-memory-base-name . :char-ptr)
107 (:read-timeout . :uint-ptr)
108 (:write-timeout . :uint-ptr)
109 (:use-result . :none)
110 (:use-remote-connection . :none)
111 (:use-embedded-connection . :none)
112 (:guess-connection . :none)
113 (:set-client-ip . :char-ptr)
114 (:secure-auth . :boolean-ptr)
115 (:report-data-truncation . :boolean-ptr)
116 (:reconnect . :boolean-ptr)
117 (:ssl-verify-server-cert . :boolean-ptr)))
119 (uffi:def-enum mysql-status
124 ;;; Opaque pointers to mysql C-defined structures
125 (uffi:def-foreign-type mysql-mysql (* :void))
126 (uffi:def-foreign-type mysql-mysql-res (* :void))
127 (uffi:def-foreign-type mysql-field (* :void))
128 (uffi:def-foreign-type mysql-bind (* :void))
130 ;;;; The Foreign C routines
131 (declaim (inline mysql-init))
132 (uffi:def-function "mysql_init"
133 ((mysql mysql-mysql))
135 :returning mysql-mysql)
137 ;; Need to comment this out for LW 4.2.6
138 ;; ? bug in LW version
139 #-lispworks (declaim (inline mysql-real-connect))
140 (uffi:def-function "mysql_real_connect"
147 (unix-socket :cstring)
148 (clientflag :unsigned-long))
150 :returning mysql-mysql)
152 (declaim (inline mysql-close))
153 (uffi:def-function "mysql_close"
158 (declaim (inline mysql-select-db))
159 (uffi:def-function "mysql_select_db"
165 (declaim (inline mysql-query))
166 (uffi:def-function "mysql_query"
172 ;;; I doubt that this function is really useful for direct Lisp usage,
173 ;;; but it is here for completeness...
175 (declaim (inline mysql-real-query))
176 (uffi:def-function "mysql_real_query"
179 (length :unsigned-int))
183 (declaim (inline mysql-shutdown))
184 (uffi:def-function "mysql_shutdown"
185 ((mysql mysql-mysql))
189 (declaim (inline mysql-dump-debug-info))
190 (uffi:def-function "mysql_dump_debug_info"
191 ((mysql mysql-mysql))
195 (declaim (inline mysql-refresh))
196 (uffi:def-function "mysql_refresh"
198 (refresh-options :unsigned-int))
202 (declaim (inline mysql-kill))
203 (uffi:def-function "mysql_kill"
205 (pid :unsigned-long))
209 (declaim (inline mysql-ping))
210 (uffi:def-function "mysql_ping"
211 ((mysql mysql-mysql))
215 (declaim (inline mysql-stat))
216 (uffi:def-function "mysql_stat"
217 ((mysql mysql-mysql))
221 (declaim (inline mysql-get-server-info))
222 (uffi:def-function "mysql_get_server_info"
223 ((mysql mysql-mysql))
227 (declaim (inline mysql-get-host-info))
228 (uffi:def-function "mysql_get_host_info"
229 ((mysql mysql-mysql))
233 (declaim (inline mysql-get-proto-info))
234 (uffi:def-function "mysql_get_proto_info"
235 ((mysql mysql-mysql))
237 :returning :unsigned-int)
239 (declaim (inline mysql-list-dbs))
240 (uffi:def-function "mysql_list_dbs"
244 :returning mysql-mysql-res)
246 (declaim (inline mysql-list-tables))
247 (uffi:def-function "mysql_list_tables"
251 :returning mysql-mysql-res)
253 (declaim (inline mysql-list-fields))
254 (uffi:def-function "mysql_list_fields"
259 :returning mysql-mysql-res)
261 (declaim (inline mysql-list-processes))
262 (uffi:def-function "mysql_list_processes"
263 ((mysql mysql-mysql))
265 :returning mysql-mysql-res)
267 (declaim (inline mysql-store-result))
268 (uffi:def-function "mysql_store_result"
269 ((mysql mysql-mysql))
271 :returning mysql-mysql-res)
273 (declaim (inline mysql-use-result))
274 (uffi:def-function "mysql_use_result"
275 ((mysql mysql-mysql))
277 :returning mysql-mysql-res)
279 (declaim (inline mysql-options))
280 (uffi:def-function "mysql_options"
282 (option mysql-option)
287 (declaim (inline mysql-free-result))
288 (uffi:def-function "mysql_free_result"
289 ((res mysql-mysql-res))
293 (declaim (inline mysql-next-result))
294 (uffi:def-function "mysql_next_result"
295 ((mysql mysql-mysql))
299 (declaim (inline mysql-fetch-row))
300 (uffi:def-function "mysql_fetch_row"
301 ((res mysql-mysql-res))
303 :returning (* (* :unsigned-char)))
305 (declaim (inline mysql-fetch-lengths))
306 (uffi:def-function "mysql_fetch_lengths"
307 ((res mysql-mysql-res))
309 :returning (* :unsigned-long))
311 (declaim (inline mysql-fetch-field))
312 (uffi:def-function "mysql_fetch_field"
313 ((res mysql-mysql-res))
315 :returning mysql-field)
317 (declaim (inline mysql-field-seek))
318 (uffi:def-function "mysql_field_seek"
319 ((res mysql-mysql-res)
320 (offset :unsigned-int))
322 :returning :unsigned-int)
324 (declaim (inline mysql-fetch-fields))
325 (uffi:def-function "mysql_fetch_fields"
326 ((res mysql-mysql-res))
328 :returning mysql-field)
330 (declaim (inline mysql-fetch-field-direct))
331 (uffi:def-function "mysql_fetch_field_direct"
332 ((res mysql-mysql-res)
333 (field-num :unsigned-int))
335 :returning mysql-field)
337 (declaim (inline mysql-escape-string))
338 (uffi:def-function "mysql_escape_string"
339 ((to (* :unsigned-char))
340 (from (* :unsigned-char))
341 (length :unsigned-int))
343 :returning :unsigned-int)
345 (declaim (inline mysql-debug))
346 (uffi:def-function "mysql_debug"
351 (declaim (inline clsql-mysql-num-rows))
352 (uffi:def-function "clsql_mysql_num_rows"
353 ((res mysql-mysql-res)
354 (p-high32 (* :unsigned-int)))
355 :module "clsql-mysql"
356 :returning :unsigned-int)
358 #+(or mysql-client-v4.1 mysql-client-v5)
359 (uffi:def-foreign-type mysql-stmt-ptr :pointer-void)
361 #+(or mysql-client-v4.1 mysql-client-v5)
362 (uffi:def-function "mysql_stmt_init"
363 ((res mysql-mysql-res))
364 :module "clsql-mysql"
365 :returning mysql-stmt-ptr)
367 #+(or mysql-client-v4.1 mysql-client-v5)
368 (uffi:def-function "mysql_stmt_prepare"
369 ((stmt mysql-stmt-ptr)
371 (length :unsigned-long))
372 :module "clsql-mysql"
375 #+(or mysql-client-v4.1 mysql-client-v5)
376 (uffi:def-function "mysql_stmt_param_count"
377 ((stmt mysql-stmt-ptr))
378 :module "clsql-mysql"
379 :returning :unsigned-int)
381 #+(or mysql-client-v4.1 mysql-client-v5)
382 (uffi:def-function "mysql_stmt_bind_param"
383 ((stmt mysql-stmt-ptr)
385 :module "clsql-mysql"
388 #+(or mysql-client-v4.1 mysql-client-v5)
389 (uffi:def-function "mysql_stmt_bind_result"
390 ((stmt mysql-stmt-ptr)
392 :module "clsql-mysql"
395 #+(or mysql-client-v4.1 mysql-client-v5)
396 (uffi:def-function "mysql_stmt_result_metadata"
397 ((stmt mysql-stmt-ptr))
398 :module "clsql-mysql"
399 :returning mysql-mysql-res)
402 #+(or mysql-client-v4.1 mysql-client-v5)
403 (uffi:def-function "mysql_stmt_execute"
404 ((stmt mysql-stmt-ptr))
405 :module "clsql-mysql"
408 #+(or mysql-client-v4.1 mysql-client-v5)
409 (uffi:def-function "mysql_stmt_store_result"
410 ((stmt mysql-stmt-ptr))
411 :module "clsql-mysql"
414 #+(or mysql-client-v4.1 mysql-client-v5)
415 (uffi:def-function "mysql_stmt_fetch"
416 ((stmt mysql-stmt-ptr))
417 :module "clsql-mysql"
420 #+(or mysql-client-v4.1 mysql-client-v5)
421 (uffi:def-function "mysql_stmt_free_result"
422 ((stmt mysql-stmt-ptr))
423 :module "clsql-mysql"
426 #+(or mysql-client-v4.1 mysql-client-v5)
427 (uffi:def-function "mysql_stmt_close"
428 ((stmt mysql-stmt-ptr))
429 :module "clsql-mysql"
432 #+(or mysql-client-v4.1 mysql-client-v5)
433 (uffi:def-function "mysql_stmt_errno"
434 ((stmt mysql-stmt-ptr))
435 :module "clsql-mysql"
436 :returning :unsigned-int)
438 #+(or mysql-client-v4.1 mysql-client-v5)
439 (uffi:def-function "mysql_stmt_error"
440 ((stmt mysql-stmt-ptr))
441 :module "clsql-mysql"
445 ;;;; Equivalents of C Macro definitions for accessing various fields
446 ;;;; in the internal MySQL Datastructures
449 (declaim (inline mysql-num-rows))
450 (defun mysql-num-rows (res)
451 (uffi:with-foreign-object (p-high32 :unsigned-int)
452 (let ((low32 (clsql-mysql-num-rows res p-high32))
453 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
456 (make-64-bit-integer high32 low32)))))
458 (uffi:def-function "clsql_mysql_affected_rows"
460 (p-high32 (* :unsigned-int)))
461 :returning :unsigned-int
462 :module "clsql-mysql")
464 (defun mysql-affected-rows (mysql)
465 (uffi:with-foreign-object (p-high32 :unsigned-int)
466 (let ((low32 (clsql-mysql-affected-rows mysql p-high32))
467 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
470 (make-64-bit-integer high32 low32)))))
472 (uffi:def-function "clsql_mysql_insert_id"
474 (p-high32 (* :unsigned-int)))
475 :returning :unsigned-int
476 :module "clsql-mysql")
478 (defun mysql-insert-id (mysql)
479 (uffi:with-foreign-object (p-high32 :unsigned-int)
480 (let ((low32 (clsql-mysql-insert-id mysql p-high32))
481 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
484 (make-64-bit-integer high32 low32)))))
487 (declaim (inline mysql-num-fields))
488 (uffi:def-function "mysql_num_fields"
489 ((res mysql-mysql-res))
490 :returning :unsigned-int
493 (declaim (inline clsql-mysql-eof))
494 (uffi:def-function ("mysql_eof" clsql-mysql-eof)
495 ((res mysql-mysql-res))
499 (declaim (inline mysql-eof))
500 (defun mysql-eof (res)
501 (if (zerop (clsql-mysql-eof res))
505 (declaim (inline mysql-error))
506 (uffi:def-function ("mysql_error" mysql-error)
507 ((mysql mysql-mysql))
511 (declaim (inline mysql-error-string))
512 (defun mysql-error-string (mysql)
513 (uffi:convert-from-cstring (mysql-error mysql)))
515 (declaim (inline mysql-errno))
516 (uffi:def-function "mysql_errno"
517 ((mysql mysql-mysql))
518 :returning :unsigned-int
521 (declaim (inline mysql-info))
522 (uffi:def-function ("mysql_info" mysql-info)
523 ((mysql mysql-mysql))
527 (declaim (inline mysql-info-string))
528 (defun mysql-info-string (mysql)
529 (uffi:convert-from-cstring (mysql-info mysql)))
531 (declaim (inline clsql-mysql-data-seek))
532 (uffi:def-function "clsql_mysql_data_seek"
533 ((res mysql-mysql-res)
534 (offset-high32 :unsigned-int)
535 (offset-low32 :unsigned-int))
536 :module "clsql-mysql"
539 (declaim (inline clsql-mysql-field-name))
540 (uffi:def-function "clsql_mysql_field_name"
542 :module "clsql-mysql"
545 (declaim (inline clsql-mysql-field-flags))
546 (uffi:def-function "clsql_mysql_field_flags"
548 :module "clsql-mysql"
549 :returning :unsigned-int)
551 (declaim (inline clsql-mysql-field-type))
552 (uffi:def-function "clsql_mysql_field_type"
554 :module "clsql-mysql"
555 :returning :unsigned-int)
557 (defun mysql-data-seek (res offset)
558 (multiple-value-bind (high32 low32) (split-64-bit-integer offset)
559 (clsql-mysql-data-seek res high32 low32)))