/db-mysql/mysql-api.lisp
Lisp | 519 lines | 402 code | 82 blank | 35 comment | 0 complexity | ca126add0f1f1931f1fba3338638c3ad MD5 | raw file
Possible License(s): LGPL-3.0, CC-BY-SA-3.0
- ;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-
- ;;;; *************************************************************************
- ;;;; FILE IDENTIFICATION
- ;;;;
- ;;;; Name: mysql-api.lisp
- ;;;; Purpose: Low-level MySQL interface using UFFI
- ;;;; Programmers: Kevin M. Rosenberg based on
- ;;;; Original code by Pierre R. Mai
- ;;;; Date Started: Feb 2002
- ;;;;
- ;;;; This file, part of CLSQL, is Copyright (c) 2002-2009 by Kevin M. Rosenberg
- ;;;; and Copyright (c) 1999-2001 by Pierre R. Mai
- ;;;;
- ;;;; CLSQL users are granted the rights to distribute and use this software
- ;;;; as governed by the terms of the Lisp Lesser GNU Public License
- ;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL.
- ;;;; *************************************************************************
- (in-package #:mysql)
- ;;;; Modifications from original code
- ;;;; - Updated C-structures to conform to structures in MySQL 3.23.46
- ;;;; - Changed from CMUCL interface to UFFI
- ;;;; - Added and call a C-helper file to support 64-bit integers
- ;;;; that are used in a few routines.
- ;;;; - Removed all references to interiors of C-structions, this will
- ;;;; increase robustness when MySQL's internal structures change.
- ;;;; Type definitions
- ;;; Basic Types
- (uffi:def-foreign-type mysql-socket :int)
- (uffi:def-foreign-type mysql-bool :byte)
- (uffi:def-foreign-type mysql-byte :unsigned-char)
- (uffi:def-enum mysql-net-type
- (:tcp-ip
- :socket
- :named-pipe))
- (uffi:def-array-pointer mysql-row (* :unsigned-char))
- ;;; MYSQL-FIELD
- (uffi:def-enum mysql-field-types
- (:decimal
- :tiny
- :short
- :long
- :float
- :double
- :null
- :timestamp
- :longlong
- :int24
- :date
- :time
- :datetime
- :year
- :newdate
- (:enum 247)
- (:set 248)
- (:tiny-blob 249)
- (:medium-blob 250)
- (:long-blob 251)
- (:blob 252)
- (:var-string 253)
- (:string 254)
- (:geometry 255)))
- (uffi:def-enum mysql-option
- (:connect-timeout
- :compress
- :named-pipe
- :init-command
- :read-default-file
- :read-default-group))
- (uffi:def-enum mysql-status
- (:ready
- :get-result
- :use-result))
- #+(or mysql-client-v4.1 mysql-client-v5)
- (uffi:def-enum mysql-field-types
- (:ready
- :get-result
- :use-result))
- ;;; Opaque pointers to mysql C-defined structures
- (uffi:def-foreign-type mysql-mysql (* :void))
- (uffi:def-foreign-type mysql-mysql-res (* :void))
- (uffi:def-foreign-type mysql-field (* :void))
- (uffi:def-foreign-type mysql-bind (* :void))
- ;;;; The Foreign C routines
- (declaim (inline mysql-init))
- (uffi:def-function "mysql_init"
- ((mysql mysql-mysql))
- :module "mysql"
- :returning mysql-mysql)
- ;; Need to comment this out for LW 4.2.6
- ;; ? bug in LW version
- #-lispworks (declaim (inline mysql-real-connect))
- (uffi:def-function "mysql_real_connect"
- ((mysql mysql-mysql)
- (host :cstring)
- (user :cstring)
- (passwd :cstring)
- (db :cstring)
- (port :unsigned-int)
- (unix-socket :cstring)
- (clientflag :unsigned-long))
- :module "mysql"
- :returning mysql-mysql)
- (declaim (inline mysql-close))
- (uffi:def-function "mysql_close"
- ((sock mysql-mysql))
- :module "mysql"
- :returning :void)
- (declaim (inline mysql-select-db))
- (uffi:def-function "mysql_select_db"
- ((mysql mysql-mysql)
- (db :cstring))
- :module "mysql"
- :returning :int)
- (declaim (inline mysql-query))
- (uffi:def-function "mysql_query"
- ((mysql mysql-mysql)
- (query :cstring))
- :module "mysql"
- :returning :int)
- ;;; I doubt that this function is really useful for direct Lisp usage,
- ;;; but it is here for completeness...
- (declaim (inline mysql-real-query))
- (uffi:def-function "mysql_real_query"
- ((mysql mysql-mysql)
- (query :cstring)
- (length :unsigned-int))
- :module "mysql"
- :returning :int)
- (declaim (inline mysql-shutdown))
- (uffi:def-function "mysql_shutdown"
- ((mysql mysql-mysql))
- :module "mysql"
- :returning :int)
- (declaim (inline mysql-dump-debug-info))
- (uffi:def-function "mysql_dump_debug_info"
- ((mysql mysql-mysql))
- :module "mysql"
- :returning :int)
- (declaim (inline mysql-refresh))
- (uffi:def-function "mysql_refresh"
- ((mysql mysql-mysql)
- (refresh-options :unsigned-int))
- :module "mysql"
- :returning :int)
- (declaim (inline mysql-kill))
- (uffi:def-function "mysql_kill"
- ((mysql mysql-mysql)
- (pid :unsigned-long))
- :module "mysql"
- :returning :int)
- (declaim (inline mysql-ping))
- (uffi:def-function "mysql_ping"
- ((mysql mysql-mysql))
- :module "mysql"
- :returning :int)
- (declaim (inline mysql-stat))
- (uffi:def-function "mysql_stat"
- ((mysql mysql-mysql))
- :module "mysql"
- :returning :cstring)
- (declaim (inline mysql-get-server-info))
- (uffi:def-function "mysql_get_server_info"
- ((mysql mysql-mysql))
- :module "mysql"
- :returning :cstring)
- (declaim (inline mysql-get-host-info))
- (uffi:def-function "mysql_get_host_info"
- ((mysql mysql-mysql))
- :module "mysql"
- :returning :cstring)
- (declaim (inline mysql-get-proto-info))
- (uffi:def-function "mysql_get_proto_info"
- ((mysql mysql-mysql))
- :module "mysql"
- :returning :unsigned-int)
- (declaim (inline mysql-list-dbs))
- (uffi:def-function "mysql_list_dbs"
- ((mysql mysql-mysql)
- (wild :cstring))
- :module "mysql"
- :returning mysql-mysql-res)
- (declaim (inline mysql-list-tables))
- (uffi:def-function "mysql_list_tables"
- ((mysql mysql-mysql)
- (wild :cstring))
- :module "mysql"
- :returning mysql-mysql-res)
- (declaim (inline mysql-list-fields))
- (uffi:def-function "mysql_list_fields"
- ((mysql mysql-mysql)
- (table :cstring)
- (wild :cstring))
- :module "mysql"
- :returning mysql-mysql-res)
- (declaim (inline mysql-list-processes))
- (uffi:def-function "mysql_list_processes"
- ((mysql mysql-mysql))
- :module "mysql"
- :returning mysql-mysql-res)
- (declaim (inline mysql-store-result))
- (uffi:def-function "mysql_store_result"
- ((mysql mysql-mysql))
- :module "mysql"
- :returning mysql-mysql-res)
- (declaim (inline mysql-use-result))
- (uffi:def-function "mysql_use_result"
- ((mysql mysql-mysql))
- :module "mysql"
- :returning mysql-mysql-res)
- (declaim (inline mysql-options))
- (uffi:def-function "mysql_options"
- ((mysql mysql-mysql)
- (option mysql-option)
- (arg :cstring))
- :module "mysql"
- :returning :int)
- (declaim (inline mysql-free-result))
- (uffi:def-function "mysql_free_result"
- ((res mysql-mysql-res))
- :module "mysql"
- :returning :void)
- (declaim (inline mysql-fetch-row))
- (uffi:def-function "mysql_fetch_row"
- ((res mysql-mysql-res))
- :module "mysql"
- :returning (* (* :unsigned-char)))
- (declaim (inline mysql-fetch-lengths))
- (uffi:def-function "mysql_fetch_lengths"
- ((res mysql-mysql-res))
- :module "mysql"
- :returning (* :unsigned-long))
- (declaim (inline mysql-fetch-field))
- (uffi:def-function "mysql_fetch_field"
- ((res mysql-mysql-res))
- :module "mysql"
- :returning mysql-field)
- (declaim (inline mysql-field-seek))
- (uffi:def-function "mysql_field_seek"
- ((res mysql-mysql-res)
- (offset :unsigned-int))
- :module "mysql"
- :returning :unsigned-int)
- (declaim (inline mysql-fetch-fields))
- (uffi:def-function "mysql_fetch_fields"
- ((res mysql-mysql-res))
- :module "mysql"
- :returning mysql-field)
- (declaim (inline mysql-fetch-field-direct))
- (uffi:def-function "mysql_fetch_field_direct"
- ((res mysql-mysql-res)
- (field-num :unsigned-int))
- :module "mysql"
- :returning mysql-field)
- (declaim (inline mysql-escape-string))
- (uffi:def-function "mysql_escape_string"
- ((to (* :unsigned-char))
- (from (* :unsigned-char))
- (length :unsigned-int))
- :module "mysql"
- :returning :unsigned-int)
- (declaim (inline mysql-debug))
- (uffi:def-function "mysql_debug"
- ((debug :cstring))
- :module "mysql"
- :returning :void)
- (declaim (inline clsql-mysql-num-rows))
- (uffi:def-function "clsql_mysql_num_rows"
- ((res mysql-mysql-res)
- (p-high32 (* :unsigned-int)))
- :module "clsql-mysql"
- :returning :unsigned-int)
- #+(or mysql-client-v4.1 mysql-client-v5)
- (uffi:def-foreign-type mysql-stmt-ptr :pointer-void)
- #+(or mysql-client-v4.1 mysql-client-v5)
- (uffi:def-function "mysql_stmt_init"
- ((res mysql-mysql-res))
- :module "clsql-mysql"
- :returning mysql-stmt-ptr)
- #+(or mysql-client-v4.1 mysql-client-v5)
- (uffi:def-function "mysql_stmt_prepare"
- ((stmt mysql-stmt-ptr)
- (query :cstring)
- (length :unsigned-long))
- :module "clsql-mysql"
- :returning :int)
- #+(or mysql-client-v4.1 mysql-client-v5)
- (uffi:def-function "mysql_stmt_param_count"
- ((stmt mysql-stmt-ptr))
- :module "clsql-mysql"
- :returning :unsigned-int)
- #+(or mysql-client-v4.1 mysql-client-v5)
- (uffi:def-function "mysql_stmt_bind_param"
- ((stmt mysql-stmt-ptr)
- (bind mysql-bind))
- :module "clsql-mysql"
- :returning :short)
- #+(or mysql-client-v4.1 mysql-client-v5)
- (uffi:def-function "mysql_stmt_bind_result"
- ((stmt mysql-stmt-ptr)
- (bind mysql-bind))
- :module "clsql-mysql"
- :returning :short)
- #+(or mysql-client-v4.1 mysql-client-v5)
- (uffi:def-function "mysql_stmt_result_metadata"
- ((stmt mysql-stmt-ptr))
- :module "clsql-mysql"
- :returning mysql-mysql-res)
- #+(or mysql-client-v4.1 mysql-client-v5)
- (uffi:def-function "mysql_stmt_execute"
- ((stmt mysql-stmt-ptr))
- :module "clsql-mysql"
- :returning :int)
- #+(or mysql-client-v4.1 mysql-client-v5)
- (uffi:def-function "mysql_stmt_store_result"
- ((stmt mysql-stmt-ptr))
- :module "clsql-mysql"
- :returning :int)
- #+(or mysql-client-v4.1 mysql-client-v5)
- (uffi:def-function "mysql_stmt_fetch"
- ((stmt mysql-stmt-ptr))
- :module "clsql-mysql"
- :returning :int)
- #+(or mysql-client-v4.1 mysql-client-v5)
- (uffi:def-function "mysql_stmt_free_result"
- ((stmt mysql-stmt-ptr))
- :module "clsql-mysql"
- :returning :short)
- #+(or mysql-client-v4.1 mysql-client-v5)
- (uffi:def-function "mysql_stmt_close"
- ((stmt mysql-stmt-ptr))
- :module "clsql-mysql"
- :returning :short)
- #+(or mysql-client-v4.1 mysql-client-v5)
- (uffi:def-function "mysql_stmt_errno"
- ((stmt mysql-stmt-ptr))
- :module "clsql-mysql"
- :returning :unsigned-int)
- #+(or mysql-client-v4.1 mysql-client-v5)
- (uffi:def-function "mysql_stmt_error"
- ((stmt mysql-stmt-ptr))
- :module "clsql-mysql"
- :returning :cstring)
- ;;;; Equivalents of C Macro definitions for accessing various fields
- ;;;; in the internal MySQL Datastructures
- (declaim (inline mysql-num-rows))
- (defun mysql-num-rows (res)
- (uffi:with-foreign-object (p-high32 :unsigned-int)
- (let ((low32 (clsql-mysql-num-rows res p-high32))
- (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
- (if (zerop high32)
- low32
- (make-64-bit-integer high32 low32)))))
- (uffi:def-function "clsql_mysql_affected_rows"
- ((mysql mysql-mysql)
- (p-high32 (* :unsigned-int)))
- :returning :unsigned-int
- :module "clsql-mysql")
- (defun mysql-affected-rows (mysql)
- (uffi:with-foreign-object (p-high32 :unsigned-int)
- (let ((low32 (clsql-mysql-affected-rows mysql p-high32))
- (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
- (if (zerop high32)
- low32
- (make-64-bit-integer high32 low32)))))
- (uffi:def-function "clsql_mysql_insert_id"
- ((res mysql-mysql)
- (p-high32 (* :unsigned-int)))
- :returning :unsigned-int
- :module "clsql-mysql")
- (defun mysql-insert-id (mysql)
- (uffi:with-foreign-object (p-high32 :unsigned-int)
- (let ((low32 (clsql-mysql-insert-id mysql p-high32))
- (high32 (uffi:deref-pointer p-high32 :unsigned-int)))
- (if (zerop high32)
- low32
- (make-64-bit-integer high32 low32)))))
- (declaim (inline mysql-num-fields))
- (uffi:def-function "mysql_num_fields"
- ((res mysql-mysql-res))
- :returning :unsigned-int
- :module "mysql")
- (declaim (inline clsql-mysql-eof))
- (uffi:def-function ("mysql_eof" clsql-mysql-eof)
- ((res mysql-mysql-res))
- :returning :char
- :module "mysql")
- (declaim (inline mysql-eof))
- (defun mysql-eof (res)
- (if (zerop (clsql-mysql-eof res))
- nil
- t))
- (declaim (inline mysql-error))
- (uffi:def-function ("mysql_error" mysql-error)
- ((mysql mysql-mysql))
- :returning :cstring
- :module "mysql")
- (declaim (inline mysql-error-string))
- (defun mysql-error-string (mysql)
- (uffi:convert-from-cstring (mysql-error mysql)))
- (declaim (inline mysql-errno))
- (uffi:def-function "mysql_errno"
- ((mysql mysql-mysql))
- :returning :unsigned-int
- :module "mysql")
- (declaim (inline mysql-info))
- (uffi:def-function ("mysql_info" mysql-info)
- ((mysql mysql-mysql))
- :returning :cstring
- :module "mysql")
- (declaim (inline mysql-info-string))
- (defun mysql-info-string (mysql)
- (uffi:convert-from-cstring (mysql-info mysql)))
- (declaim (inline clsql-mysql-data-seek))
- (uffi:def-function "clsql_mysql_data_seek"
- ((res mysql-mysql-res)
- (offset-high32 :unsigned-int)
- (offset-low32 :unsigned-int))
- :module "clsql-mysql"
- :returning :void)
- (declaim (inline clsql-mysql-field-name))
- (uffi:def-function "clsql_mysql_field_name"
- ((res mysql-field))
- :module "clsql-mysql"
- :returning :cstring)
- (declaim (inline clsql-mysql-field-flags))
- (uffi:def-function "clsql_mysql_field_flags"
- ((res mysql-field))
- :module "clsql-mysql"
- :returning :unsigned-int)
- (declaim (inline clsql-mysql-field-type))
- (uffi:def-function "clsql_mysql_field_type"
- ((res mysql-field))
- :module "clsql-mysql"
- :returning :unsigned-int)
- (defun mysql-data-seek (res offset)
- (multiple-value-bind (high32 low32) (split-64-bit-integer offset)
- (clsql-mysql-data-seek res high32 low32)))