Adding versions to the Changelog
[clsql.git] / db-mysql / mysql-api.lisp
1 ;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-
2 ;;;; *************************************************************************
3 ;;;; FILE IDENTIFICATION
4 ;;;;
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
10 ;;;;
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
13 ;;;;
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 ;;;; *************************************************************************
18
19 (in-package #:mysql)
20
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.
28
29 ;;;; Type definitions
30
31 ;;; Basic Types
32
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)
36
37 (uffi:def-enum mysql-net-type
38     (:tcp-ip
39      :socket
40      :named-pipe))
41
42 (uffi:def-array-pointer mysql-row (* :unsigned-char))
43
44 ;;; MYSQL-FIELD
45 (uffi:def-enum mysql-field-types
46     (:decimal
47      :tiny
48      :short
49      :long
50      :float
51      :double
52      :null
53      :timestamp
54      :longlong
55      :int24
56      :date
57      :time
58      :datetime
59      :year
60      :newdate
61      (:enum 247)
62      (:set 248)
63      (:tiny-blob 249)
64      (:medium-blob 250)
65      (:long-blob 251)
66      (:blob 252)
67      (:var-string 253)
68      (:string 254)
69      (:geometry 255)))
70
71 (uffi:def-enum mysql-option
72     (:connect-timeout
73      :compress
74      :named-pipe
75      :init-command
76      :read-default-file
77      :read-default-group
78      :set-charset-dir
79      :set-charset-name
80      :local-infile
81      :protocol
82      :shared-memory-base-name
83      :read-timeout
84      :write-timeout
85      :use-result
86      :use-remote-connection
87      :use-embedded-connection
88      :guess-connection
89      :set-client-ip
90      :secure-auth
91      :report-data-truncation
92      :reconnect
93      :ssl-verify-server-cert))
94
95 (defvar +mysql-option-parameter-map+
96   '((:connect-timeout . :uint-ptr)
97     (:compress . :none)
98     (:named-pipe . :none)
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)))
118
119 (uffi:def-enum mysql-status
120     (:ready
121      :get-result
122      :use-result))
123
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))
129
130 ;;;; The Foreign C routines
131 (declaim (inline mysql-init))
132 (uffi:def-function "mysql_init"
133   ((mysql mysql-mysql))
134   :module "mysql"
135   :returning mysql-mysql)
136
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"
141     ((mysql mysql-mysql)
142      (host :cstring)
143      (user :cstring)
144      (passwd :cstring)
145      (db :cstring)
146      (port :unsigned-int)
147      (unix-socket :cstring)
148      (clientflag :unsigned-long))
149   :module "mysql"
150   :returning mysql-mysql)
151
152 (declaim (inline mysql-close))
153 (uffi:def-function "mysql_close"
154     ((sock mysql-mysql))
155   :module "mysql"
156   :returning :void)
157
158 (declaim (inline mysql-select-db))
159 (uffi:def-function "mysql_select_db"
160   ((mysql mysql-mysql)
161    (db :cstring))
162   :module "mysql"
163   :returning :int)
164
165 (declaim (inline mysql-query))
166 (uffi:def-function "mysql_query"
167     ((mysql mysql-mysql)
168      (query :cstring))
169   :module "mysql"
170   :returning :int)
171
172  ;;; I doubt that this function is really useful for direct Lisp usage,
173 ;;; but it is here for completeness...
174
175 (declaim (inline mysql-real-query))
176 (uffi:def-function "mysql_real_query"
177     ((mysql mysql-mysql)
178      (query :cstring)
179      (length :unsigned-int))
180   :module "mysql"
181   :returning :int)
182
183 (declaim (inline mysql-shutdown))
184 (uffi:def-function "mysql_shutdown"
185   ((mysql mysql-mysql))
186   :module "mysql"
187   :returning :int)
188
189 (declaim (inline mysql-dump-debug-info))
190 (uffi:def-function "mysql_dump_debug_info"
191   ((mysql mysql-mysql))
192   :module "mysql"
193   :returning :int)
194
195 (declaim (inline mysql-refresh))
196 (uffi:def-function "mysql_refresh"
197   ((mysql mysql-mysql)
198    (refresh-options :unsigned-int))
199   :module "mysql"
200   :returning :int)
201
202 (declaim (inline mysql-kill))
203 (uffi:def-function "mysql_kill"
204     ((mysql mysql-mysql)
205      (pid :unsigned-long))
206   :module "mysql"
207   :returning :int)
208
209 (declaim (inline mysql-ping))
210 (uffi:def-function "mysql_ping"
211     ((mysql mysql-mysql))
212   :module "mysql"
213   :returning :int)
214
215 (declaim (inline mysql-stat))
216 (uffi:def-function "mysql_stat"
217   ((mysql mysql-mysql))
218   :module "mysql"
219   :returning :cstring)
220
221 (declaim (inline mysql-get-server-info))
222 (uffi:def-function "mysql_get_server_info"
223     ((mysql mysql-mysql))
224   :module "mysql"
225   :returning :cstring)
226
227 (declaim (inline mysql-get-host-info))
228 (uffi:def-function "mysql_get_host_info"
229     ((mysql mysql-mysql))
230   :module "mysql"
231   :returning :cstring)
232
233 (declaim (inline mysql-get-proto-info))
234 (uffi:def-function "mysql_get_proto_info"
235   ((mysql mysql-mysql))
236   :module "mysql"
237   :returning :unsigned-int)
238
239 (declaim (inline mysql-list-dbs))
240 (uffi:def-function "mysql_list_dbs"
241   ((mysql mysql-mysql)
242    (wild :cstring))
243   :module "mysql"
244   :returning mysql-mysql-res)
245
246 (declaim (inline mysql-list-tables))
247 (uffi:def-function "mysql_list_tables"
248   ((mysql mysql-mysql)
249    (wild :cstring))
250   :module "mysql"
251   :returning mysql-mysql-res)
252
253 (declaim (inline mysql-list-fields))
254 (uffi:def-function "mysql_list_fields"
255   ((mysql mysql-mysql)
256    (table :cstring)
257    (wild :cstring))
258   :module "mysql"
259   :returning mysql-mysql-res)
260
261 (declaim (inline mysql-list-processes))
262 (uffi:def-function "mysql_list_processes"
263   ((mysql mysql-mysql))
264   :module "mysql"
265   :returning mysql-mysql-res)
266
267 (declaim (inline mysql-store-result))
268 (uffi:def-function "mysql_store_result"
269   ((mysql mysql-mysql))
270   :module "mysql"
271   :returning mysql-mysql-res)
272
273 (declaim (inline mysql-use-result))
274 (uffi:def-function "mysql_use_result"
275   ((mysql mysql-mysql))
276   :module "mysql"
277   :returning mysql-mysql-res)
278
279 (declaim (inline mysql-options))
280 (uffi:def-function "mysql_options"
281   ((mysql mysql-mysql)
282    (option mysql-option)
283    (arg :pointer-void))
284   :module "mysql"
285   :returning :int)
286
287 (declaim (inline mysql-free-result))
288 (uffi:def-function "mysql_free_result"
289     ((res mysql-mysql-res))
290   :module "mysql"
291   :returning :void)
292
293 (declaim (inline mysql-fetch-row))
294 (uffi:def-function "mysql_fetch_row"
295     ((res mysql-mysql-res))
296   :module "mysql"
297   :returning (* (* :unsigned-char)))
298
299 (declaim (inline mysql-fetch-lengths))
300 (uffi:def-function "mysql_fetch_lengths"
301   ((res mysql-mysql-res))
302   :module "mysql"
303   :returning (* :unsigned-long))
304
305 (declaim (inline mysql-fetch-field))
306 (uffi:def-function "mysql_fetch_field"
307   ((res mysql-mysql-res))
308   :module "mysql"
309   :returning mysql-field)
310
311 (declaim (inline mysql-field-seek))
312 (uffi:def-function "mysql_field_seek"
313   ((res mysql-mysql-res)
314    (offset :unsigned-int))
315   :module "mysql"
316   :returning :unsigned-int)
317
318 (declaim (inline mysql-fetch-fields))
319 (uffi:def-function "mysql_fetch_fields"
320   ((res mysql-mysql-res))
321   :module "mysql"
322   :returning mysql-field)
323
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))
328   :module "mysql"
329   :returning mysql-field)
330
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))
336   :module "mysql"
337   :returning :unsigned-int)
338
339 (declaim (inline mysql-debug))
340 (uffi:def-function "mysql_debug"
341     ((debug :cstring))
342   :module "mysql"
343   :returning :void)
344
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)
351
352 #+(or mysql-client-v4.1 mysql-client-v5)
353 (uffi:def-foreign-type mysql-stmt-ptr :pointer-void)
354
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)
360
361 #+(or mysql-client-v4.1 mysql-client-v5)
362 (uffi:def-function "mysql_stmt_prepare"
363     ((stmt mysql-stmt-ptr)
364      (query :cstring)
365      (length :unsigned-long))
366   :module "clsql-mysql"
367   :returning :int)
368
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)
374
375 #+(or mysql-client-v4.1 mysql-client-v5)
376 (uffi:def-function "mysql_stmt_bind_param"
377     ((stmt mysql-stmt-ptr)
378      (bind mysql-bind))
379   :module "clsql-mysql"
380   :returning :short)
381
382 #+(or mysql-client-v4.1 mysql-client-v5)
383 (uffi:def-function "mysql_stmt_bind_result"
384     ((stmt mysql-stmt-ptr)
385      (bind mysql-bind))
386   :module "clsql-mysql"
387   :returning :short)
388
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)
394
395
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"
400   :returning :int)
401
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"
406   :returning :int)
407
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"
412   :returning :int)
413
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"
418   :returning :short)
419
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"
424   :returning :short)
425
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)
431
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"
436   :returning :cstring)
437
438
439 ;;;; Equivalents of C Macro definitions for accessing various fields
440 ;;;; in the internal MySQL Datastructures
441
442
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)))
448       (if (zerop high32)
449           low32
450         (make-64-bit-integer high32 low32)))))
451
452 (uffi:def-function "clsql_mysql_affected_rows"
453     ((mysql mysql-mysql)
454      (p-high32 (* :unsigned-int)))
455   :returning :unsigned-int
456   :module "clsql-mysql")
457
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)))
462       (if (zerop high32)
463           low32
464         (make-64-bit-integer high32 low32)))))
465
466 (uffi:def-function "clsql_mysql_insert_id"
467     ((res mysql-mysql)
468      (p-high32 (* :unsigned-int)))
469   :returning :unsigned-int
470   :module "clsql-mysql")
471
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)))
476     (if (zerop high32)
477         low32
478       (make-64-bit-integer high32 low32)))))
479
480
481 (declaim (inline mysql-num-fields))
482 (uffi:def-function "mysql_num_fields"
483   ((res mysql-mysql-res))
484   :returning :unsigned-int
485   :module "mysql")
486
487 (declaim (inline clsql-mysql-eof))
488 (uffi:def-function ("mysql_eof" clsql-mysql-eof)
489   ((res mysql-mysql-res))
490   :returning :char
491   :module "mysql")
492
493 (declaim (inline mysql-eof))
494 (defun mysql-eof (res)
495   (if (zerop (clsql-mysql-eof res))
496       nil
497     t))
498
499 (declaim (inline mysql-error))
500 (uffi:def-function ("mysql_error" mysql-error)
501   ((mysql mysql-mysql))
502   :returning :cstring
503   :module "mysql")
504
505 (declaim (inline mysql-error-string))
506 (defun mysql-error-string (mysql)
507   (uffi:convert-from-cstring (mysql-error mysql)))
508
509 (declaim (inline mysql-errno))
510 (uffi:def-function "mysql_errno"
511   ((mysql mysql-mysql))
512   :returning :unsigned-int
513   :module "mysql")
514
515 (declaim (inline mysql-info))
516 (uffi:def-function ("mysql_info" mysql-info)
517   ((mysql mysql-mysql))
518   :returning :cstring
519   :module "mysql")
520
521 (declaim (inline mysql-info-string))
522 (defun mysql-info-string (mysql)
523   (uffi:convert-from-cstring (mysql-info mysql)))
524
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"
531   :returning :void)
532
533 (declaim (inline clsql-mysql-field-name))
534 (uffi:def-function "clsql_mysql_field_name"
535   ((res mysql-field))
536   :module "clsql-mysql"
537   :returning :cstring)
538
539 (declaim (inline clsql-mysql-field-flags))
540 (uffi:def-function "clsql_mysql_field_flags"
541   ((res mysql-field))
542   :module "clsql-mysql"
543   :returning :unsigned-int)
544
545 (declaim (inline clsql-mysql-field-type))
546 (uffi:def-function "clsql_mysql_field_type"
547   ((res mysql-field))
548   :module "clsql-mysql"
549   :returning :unsigned-int)
550
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)))