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-fetch-row))
294 (uffi:def-function "mysql_fetch_row"
295 ((res mysql-mysql-res))
297 :returning (* (* :unsigned-char)))
299 (declaim (inline mysql-fetch-lengths))
300 (uffi:def-function "mysql_fetch_lengths"
301 ((res mysql-mysql-res))
303 :returning (* :unsigned-long))
305 (declaim (inline mysql-fetch-field))
306 (uffi:def-function "mysql_fetch_field"
307 ((res mysql-mysql-res))
309 :returning mysql-field)
311 (declaim (inline mysql-field-seek))
312 (uffi:def-function "mysql_field_seek"
313 ((res mysql-mysql-res)
314 (offset :unsigned-int))
316 :returning :unsigned-int)
318 (declaim (inline mysql-fetch-fields))
319 (uffi:def-function "mysql_fetch_fields"
320 ((res mysql-mysql-res))
322 :returning mysql-field)
324 (declaim (inline mysql-fetch-field-direct))
325 (uffi:def-function "mysql_fetch_field_direct"
326 ((res mysql-mysql-res)
327 (field-num :unsigned-int))
329 :returning mysql-field)
331 (declaim (inline mysql-escape-string))
332 (uffi:def-function "mysql_escape_string"
333 ((to (* :unsigned-char))
334 (from (* :unsigned-char))
335 (length :unsigned-int))
337 :returning :unsigned-int)
339 (declaim (inline mysql-debug))
340 (uffi:def-function "mysql_debug"
345 (declaim (inline clsql-mysql-num-rows))
346 (uffi:def-function "clsql_mysql_num_rows"
347 ((res mysql-mysql-res)
348 (p-high32 (* :unsigned-int)))
349 :module "clsql-mysql"
350 :returning :unsigned-int)
352 #+(or mysql-client-v4.1 mysql-client-v5)
353 (uffi:def-foreign-type mysql-stmt-ptr :pointer-void)
355 #+(or mysql-client-v4.1 mysql-client-v5)
356 (uffi:def-function "mysql_stmt_init"
357 ((res mysql-mysql-res))
358 :module "clsql-mysql"
359 :returning mysql-stmt-ptr)
361 #+(or mysql-client-v4.1 mysql-client-v5)
362 (uffi:def-function "mysql_stmt_prepare"
363 ((stmt mysql-stmt-ptr)
365 (length :unsigned-long))
366 :module "clsql-mysql"
369 #+(or mysql-client-v4.1 mysql-client-v5)
370 (uffi:def-function "mysql_stmt_param_count"
371 ((stmt mysql-stmt-ptr))
372 :module "clsql-mysql"
373 :returning :unsigned-int)
375 #+(or mysql-client-v4.1 mysql-client-v5)
376 (uffi:def-function "mysql_stmt_bind_param"
377 ((stmt mysql-stmt-ptr)
379 :module "clsql-mysql"
382 #+(or mysql-client-v4.1 mysql-client-v5)
383 (uffi:def-function "mysql_stmt_bind_result"
384 ((stmt mysql-stmt-ptr)
386 :module "clsql-mysql"
389 #+(or mysql-client-v4.1 mysql-client-v5)
390 (uffi:def-function "mysql_stmt_result_metadata"
391 ((stmt mysql-stmt-ptr))
392 :module "clsql-mysql"
393 :returning mysql-mysql-res)
396 #+(or mysql-client-v4.1 mysql-client-v5)
397 (uffi:def-function "mysql_stmt_execute"
398 ((stmt mysql-stmt-ptr))
399 :module "clsql-mysql"
402 #+(or mysql-client-v4.1 mysql-client-v5)
403 (uffi:def-function "mysql_stmt_store_result"
404 ((stmt mysql-stmt-ptr))
405 :module "clsql-mysql"
408 #+(or mysql-client-v4.1 mysql-client-v5)
409 (uffi:def-function "mysql_stmt_fetch"
410 ((stmt mysql-stmt-ptr))
411 :module "clsql-mysql"
414 #+(or mysql-client-v4.1 mysql-client-v5)
415 (uffi:def-function "mysql_stmt_free_result"
416 ((stmt mysql-stmt-ptr))
417 :module "clsql-mysql"
420 #+(or mysql-client-v4.1 mysql-client-v5)
421 (uffi:def-function "mysql_stmt_close"
422 ((stmt mysql-stmt-ptr))
423 :module "clsql-mysql"
426 #+(or mysql-client-v4.1 mysql-client-v5)
427 (uffi:def-function "mysql_stmt_errno"
428 ((stmt mysql-stmt-ptr))
429 :module "clsql-mysql"
430 :returning :unsigned-int)
432 #+(or mysql-client-v4.1 mysql-client-v5)
433 (uffi:def-function "mysql_stmt_error"
434 ((stmt mysql-stmt-ptr))
435 :module "clsql-mysql"
439 ;;;; Equivalents of C Macro definitions for accessing various fields
440 ;;;; in the internal MySQL Datastructures
443 (declaim (inline mysql-num-rows))
444 (defun mysql-num-rows (res)
445 (uffi:with-foreign-object (p-high32 :unsigned-int)
446 (let ((low32 (clsql-mysql-num-rows res p-high32))
447 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
450 (make-64-bit-integer high32 low32)))))
452 (uffi:def-function "clsql_mysql_affected_rows"
454 (p-high32 (* :unsigned-int)))
455 :returning :unsigned-int
456 :module "clsql-mysql")
458 (defun mysql-affected-rows (mysql)
459 (uffi:with-foreign-object (p-high32 :unsigned-int)
460 (let ((low32 (clsql-mysql-affected-rows mysql p-high32))
461 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
464 (make-64-bit-integer high32 low32)))))
466 (uffi:def-function "clsql_mysql_insert_id"
468 (p-high32 (* :unsigned-int)))
469 :returning :unsigned-int
470 :module "clsql-mysql")
472 (defun mysql-insert-id (mysql)
473 (uffi:with-foreign-object (p-high32 :unsigned-int)
474 (let ((low32 (clsql-mysql-insert-id mysql p-high32))
475 (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
478 (make-64-bit-integer high32 low32)))))
481 (declaim (inline mysql-num-fields))
482 (uffi:def-function "mysql_num_fields"
483 ((res mysql-mysql-res))
484 :returning :unsigned-int
487 (declaim (inline clsql-mysql-eof))
488 (uffi:def-function ("mysql_eof" clsql-mysql-eof)
489 ((res mysql-mysql-res))
493 (declaim (inline mysql-eof))
494 (defun mysql-eof (res)
495 (if (zerop (clsql-mysql-eof res))
499 (declaim (inline mysql-error))
500 (uffi:def-function ("mysql_error" mysql-error)
501 ((mysql mysql-mysql))
505 (declaim (inline mysql-error-string))
506 (defun mysql-error-string (mysql)
507 (uffi:convert-from-cstring (mysql-error mysql)))
509 (declaim (inline mysql-errno))
510 (uffi:def-function "mysql_errno"
511 ((mysql mysql-mysql))
512 :returning :unsigned-int
515 (declaim (inline mysql-info))
516 (uffi:def-function ("mysql_info" mysql-info)
517 ((mysql mysql-mysql))
521 (declaim (inline mysql-info-string))
522 (defun mysql-info-string (mysql)
523 (uffi:convert-from-cstring (mysql-info mysql)))
525 (declaim (inline clsql-mysql-data-seek))
526 (uffi:def-function "clsql_mysql_data_seek"
527 ((res mysql-mysql-res)
528 (offset-high32 :unsigned-int)
529 (offset-low32 :unsigned-int))
530 :module "clsql-mysql"
533 (declaim (inline clsql-mysql-field-name))
534 (uffi:def-function "clsql_mysql_field_name"
536 :module "clsql-mysql"
539 (declaim (inline clsql-mysql-field-flags))
540 (uffi:def-function "clsql_mysql_field_flags"
542 :module "clsql-mysql"
543 :returning :unsigned-int)
545 (declaim (inline clsql-mysql-field-type))
546 (uffi:def-function "clsql_mysql_field_type"
548 :module "clsql-mysql"
549 :returning :unsigned-int)
551 (defun mysql-data-seek (res offset)
552 (multiple-value-bind (high32 low32) (split-64-bit-integer offset)
553 (clsql-mysql-data-seek res high32 low32)))