X-Git-Url: http://git.kpe.io/?p=clsql.git;a=blobdiff_plain;f=db-mysql%2Fmysql-sql.lisp;h=a0e21c8b536980c9963ffb741002930c23857f9a;hp=ab8ae58883fb7ca0c1a5e66407550e3851606c01;hb=9d6ec50020109467ff766ad753a4194ee756b1b9;hpb=3fe77db54b9abecc35bddf084289e359987a5751 diff --git a/db-mysql/mysql-sql.lisp b/db-mysql/mysql-sql.lisp index ab8ae58..a0e21c8 100644 --- a/db-mysql/mysql-sql.lisp +++ b/db-mysql/mysql-sql.lisp @@ -20,6 +20,12 @@ (in-package #:clsql-mysql) +;; if we have :sb-unicode, UFFI will treat :cstring as a UTF-8 string +(defun expression-length (query-expression) + (length #+sb-unicode (sb-ext:string-to-octets query-expression + :external-format :utf8) + #-sb-unicode query-expression)) + ;;; Field conversion functions (defun result-field-names (num-fields res-ptr) @@ -41,16 +47,25 @@ (dotimes (i num-fields) (declare (fixnum i)) (let* ((field (uffi:deref-array field-vec '(:array mysql-field) i)) - (type (uffi:get-slot-value field 'mysql-field 'type))) + (flags (uffi:get-slot-value field 'mysql-field 'mysql::flags)) + (unsigned (plusp (logand flags 32))) + (type (uffi:get-slot-value field 'mysql-field 'type))) (push (case type - ((#.mysql-field-types#tiny + ((#.mysql-field-types#tiny #.mysql-field-types#short - #.mysql-field-types#int24 - #.mysql-field-types#long) - :int32) - (#.mysql-field-types#longlong - :int64) + #.mysql-field-types#int24) + (if unsigned + :uint32 + :int32)) + (#.mysql-field-types#long + (if unsigned + :uint + :int)) + (#.mysql-field-types#longlong + (if unsigned + :uint64 + :int64)) ((#.mysql-field-types#double #.mysql-field-types#float #.mysql-field-types#decimal) @@ -80,22 +95,36 @@ (defclass mysql-database (database) ((mysql-ptr :accessor database-mysql-ptr :initarg :mysql-ptr - :type mysql-mysql-ptr-def))) + :type mysql-mysql-ptr-def) + (server-info :accessor database-server-info :initarg :server-info + :type string))) (defmethod database-type ((database mysql-database)) :mysql) (defmethod database-name-from-spec (connection-spec (database-type (eql :mysql))) - (check-connection-spec connection-spec database-type (host db user password)) - (destructuring-bind (host db user password) connection-spec + (check-connection-spec connection-spec database-type + (host db user password &optional port)) + (destructuring-bind (host db user password &optional port) connection-spec (declare (ignore password)) - (concatenate 'string - (if host host "localhost") + (concatenate 'string + (etypecase host + (null "localhost") + (pathname (namestring host)) + (string host)) + (if port + (concatenate 'string + ":" + (etypecase port + (integer (write-to-string port)) + (string port))) + "") "/" db "/" user))) (defmethod database-connect (connection-spec (database-type (eql :mysql))) - (check-connection-spec connection-spec database-type (host db user password)) - (destructuring-bind (host db user password) connection-spec + (check-connection-spec connection-spec database-type + (host db user password &optional port)) + (destructuring-bind (host db user password &optional port) connection-spec (let ((mysql-ptr (mysql-init (uffi:make-null-pointer 'mysql-mysql))) (socket nil)) (if (uffi:null-pointer-p mysql-ptr) @@ -111,10 +140,15 @@ (socket-native socket)) (let ((error-occurred nil)) (unwind-protect - (if (uffi:null-pointer-p - (mysql-real-connect + (if (uffi:null-pointer-p + (mysql-real-connect mysql-ptr host-native user-native password-native - db-native 0 socket-native 0)) + db-native + (etypecase port + (null 0) + (integer port) + (string (parse-integer port))) + socket-native 0)) (progn (setq error-occurred t) (error 'sql-connection-error @@ -123,11 +157,13 @@ :error-id (mysql-errno mysql-ptr) :message (mysql-error-string mysql-ptr))) (make-instance 'mysql-database - :name (database-name-from-spec connection-spec - database-type) - :database-type :mysql - :connection-spec connection-spec - :mysql-ptr mysql-ptr)) + :name (database-name-from-spec connection-spec + database-type) + :database-type :mysql + :connection-spec connection-spec + :server-info (uffi:convert-from-cstring + (mysql:mysql-get-server-info mysql-ptr)) + :mysql-ptr mysql-ptr)) (when error-occurred (mysql-close mysql-ptr))))))))) @@ -137,19 +173,19 @@ t) -(defmethod database-query (query-expression (database mysql-database) +(defmethod database-query (query-expression (database mysql-database) result-types field-names) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0))) (let ((mysql-ptr (database-mysql-ptr database))) (uffi:with-cstring (query-native query-expression) - (if (zerop (mysql-real-query mysql-ptr query-native - (length query-expression))) + (if (zerop (mysql-real-query mysql-ptr query-native + (expression-length query-expression))) (let ((res-ptr (mysql-use-result mysql-ptr))) (if res-ptr (unwind-protect (let ((num-fields (mysql-num-fields res-ptr))) (declare (fixnum num-fields)) - (setq result-types (canonicalize-types + (setq result-types (canonicalize-types result-types num-fields res-ptr)) (values @@ -162,7 +198,7 @@ (pos rlist (cdr pos))) ((= i num-fields) rlist) (declare (fixnum i)) - (setf (car pos) + (setf (car pos) (convert-raw-field (uffi:deref-array row '(:array (* :unsigned-char)) @@ -188,8 +224,8 @@ (uffi:with-cstring (sql-native sql-expression) (let ((mysql-ptr (database-mysql-ptr database))) (declare (type mysql-mysql-ptr-def mysql-ptr)) - (if (zerop (mysql-real-query mysql-ptr sql-native - (length sql-expression))) + (if (zerop (mysql-real-query mysql-ptr sql-native + (expression-length sql-expression))) t (error 'sql-database-data-error :database database @@ -198,7 +234,7 @@ :message (mysql-error-string mysql-ptr)))))) -(defstruct mysql-result-set +(defstruct mysql-result-set (res-ptr (uffi:make-null-pointer 'mysql-mysql-res) :type mysql-mysql-res-ptr-def) (types nil :type list) (num-fields 0 :type fixnum) @@ -212,7 +248,7 @@ (let ((mysql-ptr (database-mysql-ptr database))) (declare (type mysql-mysql-ptr-def mysql-ptr)) (if (zerop (mysql-real-query mysql-ptr query-native - (length query-expression))) + (expression-length query-expression))) (let ((res-ptr (if full-set (mysql-store-result mysql-ptr) (mysql-use-result mysql-ptr)))) @@ -224,9 +260,9 @@ :num-fields num-fields :full-set full-set :types - (canonicalize-types + (canonicalize-types result-types num-fields - res-ptr)))) + res-ptr)))) (if full-set (values result-set num-fields @@ -260,7 +296,7 @@ (loop for i from 0 below (mysql-result-set-num-fields result-set) for rest on list do - (setf (car rest) + (setf (car rest) (convert-raw-field (uffi:deref-array row '(:array (* :unsigned-char)) i) types @@ -273,16 +309,29 @@ (defmethod database-list-tables ((database mysql-database) &key (owner nil)) (declare (ignore owner)) - (remove-if #'(lambda (s) - (and (>= (length s) 11) - (string-equal (subseq s 0 11) "_CLSQL_SEQ_"))) - (mapcar #'car (database-query "SHOW TABLES" database nil nil)))) - -;; MySQL 4.1 does not support views + (cond + ((eql #\5 (char (database-server-info database) 0)) + (loop for (name type) in (database-query "SHOW FULL TABLES" database nil nil) + when (and (string-equal type "base table") + (not (and (>= (length name) 11) + (string-equal (subseq name 0 11) "_CLSQL_SEQ_")))) + collect name)) + (t + (remove-if #'(lambda (s) + (and (>= (length s) 11) + (string-equal (subseq s 0 11) "_CLSQL_SEQ_"))) + (mapcar #'car (database-query "SHOW TABLES" database nil nil)))))) + (defmethod database-list-views ((database mysql-database) &key (owner nil)) (declare (ignore owner)) - nil) + (cond + ((eql #\5 (char (database-server-info database) 0)) + (loop for (name type) in (database-query "SHOW FULL TABLES" database nil nil) + when (string-equal type "view") + collect name)) + (t + nil))) (defmethod database-list-indexes ((database mysql-database) &key (owner nil)) @@ -296,7 +345,7 @@ &key (owner nil)) (declare (ignore owner)) (do ((results nil) - (rows (database-query + (rows (database-query (format nil "SHOW INDEX FROM ~A" (string-upcase table)) database nil nil) (cdr rows))) @@ -304,7 +353,7 @@ (let ((col (nth 2 (car rows)))) (unless (find col results :test #'string-equal) (push col results))))) - + (defmethod database-list-attributes ((table string) (database mysql-database) &key (owner nil)) (declare (ignore owner)) @@ -350,7 +399,7 @@ (concatenate 'string "CREATE TABLE " table-name " (id int NOT NULL PRIMARY KEY AUTO_INCREMENT)") database) - (database-execute-command + (database-execute-command (concatenate 'string "INSERT INTO " table-name " VALUES (-1)") database))) @@ -358,7 +407,7 @@ (defmethod database-drop-sequence (sequence-name (database mysql-database)) (database-execute-command - (concatenate 'string "DROP TABLE " (%sequence-name-to-table sequence-name)) + (concatenate 'string "DROP TABLE " (%sequence-name-to-table sequence-name)) database)) (defmethod database-list-sequences ((database mysql-database) @@ -380,54 +429,59 @@ (defmethod database-sequence-next (sequence-name (database mysql-database)) (without-interrupts - (database-execute-command + (database-execute-command (concatenate 'string "UPDATE " (%sequence-name-to-table sequence-name) " SET id=LAST_INSERT_ID(id+1)") database) (mysql:mysql-insert-id (clsql-mysql::database-mysql-ptr database)))) (defmethod database-sequence-last (sequence-name (database mysql-database)) - (declare (ignore sequence-name))) + (without-interrupts + (caar (database-query + (concatenate 'string "SELECT id from " + (%sequence-name-to-table sequence-name)) + database :auto nil)))) (defmethod database-create (connection-spec (type (eql :mysql))) - (destructuring-bind (host name user password) connection-spec + (destructuring-bind (host name user password &optional port) connection-spec (multiple-value-bind (output status) - (clsql-sys:command-output "mysqladmin create -u~A -p~A -h~A ~A" - user password + (clsql-sys:command-output "mysqladmin create -u~A -p~A -h~A~@[ -P~A~] ~A" + user password (if host host "localhost") + port name name) (if (or (not (eql 0 status)) (and (search "failed" output) (search "error" output))) (error 'sql-database-error - :message + :message (format nil "mysql database creation failed with connection-spec ~A." connection-spec)) t)))) (defmethod database-destroy (connection-spec (type (eql :mysql))) - (destructuring-bind (host name user password) connection-spec + (destructuring-bind (host name user password &optional port) connection-spec (multiple-value-bind (output status) - (clsql-sys:command-output "mysqladmin drop -f -u~A -p~A -h~A ~A" - user password + (clsql-sys:command-output "mysqladmin drop -f -u~A -p~A -h~A~@[ -P~A~] ~A" + user password (if host host "localhost") - name) + port name) (if (or (not (eql 0 status)) (and (search "failed" output) (search "error" output))) (error 'sql-database-error - :message + :message (format nil "mysql database deletion failed with connection-spec ~A." connection-spec)) t)))) (defmethod database-probe (connection-spec (type (eql :mysql))) (when (find (second connection-spec) (database-list connection-spec type) - :key #'car :test #'string-equal) + :test #'string-equal) t)) (defmethod database-list (connection-spec (type (eql :mysql))) - (destructuring-bind (host name user password) connection-spec + (destructuring-bind (host name user password &optional port) connection-spec (declare (ignore name)) - (let ((database (database-connect (list host "mysql" user password) type))) + (let ((database (database-connect (list host "mysql" user password port) type))) (unwind-protect (progn (setf (slot-value database 'clsql-sys::state) :open) @@ -451,7 +505,7 @@ (length-ptr :initarg :length-ptr :reader length-ptr) (is-null-ptr :initarg :is-null-ptr :reader is-null-ptr) (result-types :initarg :result-types :reader result-types))) - + (defun clsql-type->mysql-type (type) (cond ((in type :null) mysql-field-types#null) @@ -459,10 +513,11 @@ ((in type :short) mysql-field-types#short) ((in type :bigint) mysql-field-types#longlong) ((in type :float :double :number) mysql-field-types#double) - ((and (consp type) (in (car type) :char :varchar)) mysql-field-types#var-string) + ((and (consp type) (in (car type) :char :string :varchar)) mysql-field-types#var-string) + ((or (eq type :blob) (and (consp type) (in (car type) :blob))) mysql-field-types#var-string) (t - (error 'sql-user-error - :message + (error 'sql-user-error + :message (format nil "Unknown clsql type ~A." type))))) #+mysql-client-v4.1 @@ -475,90 +530,113 @@ :message (mysql-error-string mysql-ptr))) (uffi:with-cstring (native-query sql-stmt) - (unless (zerop (mysql-stmt-prepare stmt native-query (length sql-stmt))) + (unless (zerop (mysql-stmt-prepare stmt native-query (expression-length sql-stmt))) + (mysql-stmt-close stmt) (error 'sql-database-error :error-id (mysql-errno mysql-ptr) :message (mysql-error-string mysql-ptr)))) - + (unless (= (mysql-stmt-param-count stmt) (length types)) + (mysql-stmt-close stmt) (error 'sql-database-error - :message + :message (format nil "Mysql param count (~D) does not match number of types (~D)" (mysql-stmt-param-count stmt) (length types)))) (let ((rs (mysql-stmt-result-metadata stmt))) (when (uffi:null-pointer-p rs) + (warn "mysql_stmt_result_metadata returned NULL") + #+nil + (mysql-stmt-close stmt) + #+nil (error 'sql-database-error - :message "NULL result metadata")) - - (let* ((field-vec (mysql-fetch-fields rs)) - (num-fields (mysql-num-fields rs)) - (output-bind (uffi:allocate-foreign-object mysql-bind num-fields)) - (length-ptr (uffi:allocate-foreign-object :unsigned-long num-fields)) - (is-null-ptr (uffi:allocate-foreign-object :byte num-fields))) - - (dotimes (i num-fields) - (declare (fixnum i)) - (let* ((field (uffi:deref-array field-vec '(:array mysql-field) i)) - (type (uffi:get-slot-value field 'mysql-field 'type)) - (binding (uffi:deref-array output-bind '(:array mysql-bind) i))) - (setf (uffi:get-slot-value binding 'mysql-bind 'buffer-type) type) - (setf (uffi:get-slot-value binding 'mysql-bind 'buffer-length) 0) - (setf (uffi:get-slot-value binding 'mysql-bind 'is-null) - (uffi:pointer-address (uffi:deref-array is-null-ptr '(:array :byte) i))) - (setf (uffi:get-slot-value binding 'mysql-bind 'length) - (uffi:pointer-address (uffi:deref-array length-ptr '(:array :unsigned-long) i))) - - (case type - ((#.mysql-field-types#var-string #.mysql-field-types#string - #.mysql-field-types#tiny-blob #.mysql-field-types#blob - #.mysql-field-types#medium-blob #.mysql-field-types#long-blob) - (setf (uffi:get-slot-value binding 'mysql-bind 'buffer-length) 1024) - (setf (uffi:get-slot-value binding 'mysql-bind 'buffer) - (uffi:allocate-foreign-object :unsigned-char 1024))) - (#.mysql-field-types#tiny - (setf (uffi:get-slot-value binding 'mysql-bind 'buffer) - (uffi:allocate-foreign-object :byte))) - (#.mysql-field-types#short - (setf (uffi:get-slot-value binding 'mysql-bind 'buffer) - (uffi:allocate-foreign-object :short))) - (#.mysql-field-types#long - (setf (uffi:get-slot-value binding 'mysql-bind 'buffer) - (uffi:allocate-foreign-object :int))) - #+64bit - (#.mysql-field-types#longlong - (setf (uffi:get-slot-value binding 'mysql-bind 'buffer) - (uffi:allocate-foreign-object :long))) - (#.mysql-field-types#float - (setf (uffi:get-slot-value binding 'mysql-bind 'buffer) - (uffi:allocate-foreign-object :float))) - (#.mysql-field-types#double - (setf (uffi:get-slot-value binding 'mysql-bind 'buffer) - (uffi:allocate-foreign-object :double))) - ((#.mysql-field-types#time #.mysql-field-types#date - #.mysql-field-types#datetime #.mysql-field-types#timestamp) - (uffi:allocate-foreign-object 'mysql-time)) - (t - (error "mysql type ~D not supported." type))))) - - (unless (zerop (mysql-stmt-bind-result stmt output-bind)) - (error 'sql-database-error - :error-id (mysql-stmt-errno stmt) - :message (uffi:convert-from-cstring - (mysql-stmt-error stmt)))) + :message "mysql_stmt_result_metadata returned NULL")) + + (let ((input-bind (uffi:allocate-foreign-object 'mysql-bind (length types))) + (mysql-types (mapcar 'clsql-type->mysql-type types)) + field-vec num-fields is-null-ptr output-bind length-ptr) + + (print 'a) + (dotimes (i (length types)) + (let* ((binding (uffi:deref-array input-bind '(:array mysql-bind) i))) + (setf (uffi:get-slot-value binding 'mysql-bind 'mysql::buffer-type) + (nth i mysql-types)) + (setf (uffi:get-slot-value binding 'mysql-bind 'mysql::buffer-length) 0))) + + (print 'b) + (unless (uffi:null-pointer-p rs) + (setq field-vec (mysql-fetch-fields rs) + num-fields (mysql-num-fields rs) + is-null-ptr (uffi:allocate-foreign-object :byte num-fields) + output-bind (uffi:allocate-foreign-object 'mysql-bind num-fields) + length-ptr (uffi:allocate-foreign-object :unsigned-long num-fields)) + (dotimes (i num-fields) + (declare (fixnum i)) + (let* ((field (uffi:deref-array field-vec '(:array mysql-field) i)) + (type (uffi:get-slot-value field 'mysql-field 'type)) + (binding (uffi:deref-array output-bind '(:array mysql-bind) i))) + (setf (uffi:get-slot-value binding 'mysql-bind 'mysql::buffer-type) type) + + (setf (uffi:get-slot-value binding 'mysql-bind 'mysql::buffer-length) 0) + #+need-to-allocate-foreign-object-for-this + (setf (uffi:get-slot-value binding 'mysql-bind 'mysql::is-null) + (+ i (uffi:pointer-address is-null-ptr))) + #+need-to-allocate-foreign-object-for-this + (setf (uffi:get-slot-value binding 'mysql-bind 'length) + (+ (* i 8) (uffi:pointer-address length-ptr))) + + (case type + ((#.mysql-field-types#var-string #.mysql-field-types#string + #.mysql-field-types#tiny-blob #.mysql-field-types#blob + #.mysql-field-types#medium-blob #.mysql-field-types#long-blob) + (setf (uffi:get-slot-value binding 'mysql-bind 'mysql::buffer-length) 1024) + (setf (uffi:get-slot-value binding 'mysql-bind 'mysql::buffer) + (uffi:allocate-foreign-object :unsigned-char 1024))) + (#.mysql-field-types#tiny + (setf (uffi:get-slot-value binding 'mysql-bind 'mysql::buffer) + (uffi:allocate-foreign-object :byte))) + (#.mysql-field-types#short + (setf (uffi:get-slot-value binding 'mysql-bind 'mysql::buffer) + (uffi:allocate-foreign-object :short))) + (#.mysql-field-types#long + (setf (uffi:get-slot-value binding 'mysql-bind 'mysql::buffer) + ;; segfaults if supply :int on amd64 + (uffi:allocate-foreign-object :long))) + #+64bit + (#.mysql-field-types#longlong + (setf (uffi:get-slot-value binding 'mysql-bind 'mysql::buffer) + (uffi:allocate-foreign-object :long))) + (#.mysql-field-types#float + (setf (uffi:get-slot-value binding 'mysql-bind 'mysql::buffer) + (uffi:allocate-foreign-object :float))) + (#.mysql-field-types#double + (setf (uffi:get-slot-value binding 'mysql-bind 'mysql::buffer) + (uffi:allocate-foreign-object :double))) + ((#.mysql-field-types#time #.mysql-field-types#date + #.mysql-field-types#datetime #.mysql-field-types#timestamp) + (uffi:allocate-foreign-object 'mysql-time)) + (t + (error "mysql type ~D not supported." type))))) + + (unless (zerop (mysql-stmt-bind-result stmt output-bind)) + (mysql-stmt-close stmt) + (error 'sql-database-error + :error-id (mysql-stmt-errno stmt) + :message (uffi:convert-from-cstring + (mysql-stmt-error stmt))))) (make-instance 'mysql-stmt - :database database - :stmt stmt - :num-fields num-fields - :input-bind (uffi:allocate-foreign-object mysql-bind (length types)) - :output-bind output-bind - :result-set rs - :result-types result-types - :length-ptr length-ptr - :is-null-ptr is-null-ptr - :types (mapcar 'clsql-type->mysql-type types) - :field-names field-names))))) + :database database + :stmt stmt + :num-fields num-fields + :input-bind input-bind + :output-bind output-bind + :result-set rs + :result-types result-types + :length-ptr length-ptr + :is-null-ptr is-null-ptr + :types mysql-types + :field-names field-names))))) #+mysql-client-v4.1 (defmethod database-bind-parameter ((stmt mysql-stmt) position value) @@ -569,29 +647,34 @@ (setf (uffi:get-slot-value binding 'mysql-bind 'length) 0) (cond ((null value) - (setf (uffi:get-slot-value binding 'mysql-bind 'is-null) 1)) + (when (is-null-ptr stmt) + (setf (uffi:deref-array (is-null-ptr stmt) '(:array :byte) (1- position)) 1))) (t - (setf (uffi:get-slot-value binding 'mysql-bind 'is-null) 0) - (setf (uffi:get-slot-value binding 'mysql-bind 'buffer-type) type) + (when (is-null-ptr stmt) + (setf (uffi:deref-array (is-null-ptr stmt) '(:array :byte) (1- position)) 0)) (case type (#.mysql-field-types#long - (let ((ptr (uffi:allocate-foreign-object :long))) - (setf (uffi:deref-pointer ptr :long) value) - (setf (uffi:get-slot-value binding 'mysql-bind 'buffer) ptr))) + (setf (uffi:get-slot-value binding 'mysql-bind 'mysql::buffer) value)) + (t + (warn "Unknown input bind type ~D." type)) ))))) #+mysql-client-v4.1 (defmethod database-run-prepared ((stmt mysql-stmt)) - (unless (zerop (mysql-stmt-bind-param (stmt stmt) (input-bind stmt))) - (error 'sql-database-error - :error-id (mysql-stmt-errno (stmt stmt)) - :message (uffi:convert-from-cstring - (mysql-stmt-error (stmt stmt))))) + (print 'a1) + (when (input-bind stmt) + (unless (zerop (mysql-stmt-bind-param (stmt stmt) (input-bind stmt))) + (error 'sql-database-error + :error-id (mysql-stmt-errno (stmt stmt)) + :message (uffi:convert-from-cstring + (mysql-stmt-error (stmt stmt)))))) + (print 'a2) (unless (zerop (mysql-stmt-execute (stmt stmt))) (error 'sql-database-error :error-id (mysql-stmt-errno (stmt stmt)) :message (uffi:convert-from-cstring (mysql-stmt-error (stmt stmt))))) + (print 'a3) (unless (zerop (mysql-stmt-store-result (stmt stmt))) (error 'sql-database-error :error-id (mysql-stmt-errno (stmt stmt)) @@ -602,18 +685,19 @@ #+mysql-client-v4.1 (defun database-fetch-prepared-rows (stmt) (do ((rc (mysql-stmt-fetch (stmt stmt)) (mysql-stmt-fetch (stmt stmt))) + (num-fields (num-fields stmt)) (rows '())) ((not (zerop rc)) (nreverse rows)) (push - (loop for i from 0 below (num-fields stmt) + (loop for i from 0 below num-fields collect - (let ((is-null + (let ((is-null (not (zerop (uffi:ensure-char-integer (uffi:deref-array (is-null-ptr stmt) '(:array :byte) i)))))) (unless is-null (let* ((bind (uffi:deref-array (output-bind stmt) '(:array mysql-bind) i)) - (type (uffi:get-slot-value bind 'mysql-bind 'buffer-type)) - (buffer (uffi:get-slot-value bind 'mysql-bind 'buffer))) + (type (uffi:get-slot-value bind 'mysql-bind 'mysql::buffer-type)) + (buffer (uffi:get-slot-value bind 'mysql-bind 'mysql::buffer))) (case type ((#.mysql-field-types#var-string #.mysql-field-types#string #.mysql-field-types#tiny-blob #.mysql-field-types#blob @@ -640,17 +724,17 @@ (day (uffi:get-slot-value buffer 'mysql-time 'mysql::day)) (hour (uffi:get-slot-value buffer 'mysql-time 'mysql::hour)) (minute (uffi:get-slot-value buffer 'mysql-time 'mysql::minute)) - (second (uffi:get-slot-value buffer 'mysql-time 'mysql::second))) + (second (uffi:get-slot-value buffer 'mysql-time 'mysql::second))) (db-timestring (make-time :year year :month month :day day :hour hour :minute minute :second second)))) (t (list type))))))) rows))) - - - + + + #+mysql-client-v4.1 (defmethod database-free-prepared ((stmt mysql-stmt)) (with-slots (stmt) stmt @@ -664,15 +748,16 @@ t) (defmethod db-type-has-views? ((db-type (eql :mysql))) - #+mysql-client-v5.1 t - #-mysql-client-v5.1 nil) + #+mysql-client-v5 t + #-mysql-client-v5 nil) (defmethod db-type-has-subqueries? ((db-type (eql :mysql))) - #+mysql-client-v4.1 t - #-mysql-client-v4.1 nil) + #+(or mysql-client-v4.1 mysql-client-v5) t + #-(or mysql-client-v4.1 mysql-client-v5) nil) (defmethod db-type-has-boolean-where? ((db-type (eql :mysql))) - nil) + #+(or mysql-client-v4.1 mysql-client-v5) t + #-(or mysql-client-v4.1 mysql-client-v5) nil) (defmethod db-type-has-union? ((db-type (eql :mysql))) (not (eql (schar mysql::*mysql-client-info* 0) #\3))) @@ -682,8 +767,8 @@ (and tuple (string-equal "YES" (second tuple))))) (defmethod db-type-has-prepared-stmt? ((db-type (eql :mysql))) - #+mysql-client-v4.1 t - #-mysql-client-v4.1 nil) + #+(or mysql-client-v4.1 mysql-client-v5) t + #-(or mysql-client-v4.1 mysql-client-v5) nil) (when (clsql-sys:database-type-library-loaded :mysql) (clsql-sys:initialize-database-type :database-type :mysql))