Mysql shouldn't segfault in database-query when running a command with no resultset.
authorNathan Bird <nathan@acceleration.net>
Tue, 19 Jan 2010 18:59:52 +0000 (13:59 -0500)
committerNathan Bird <nathan@acceleration.net>
Mon, 1 Feb 2010 18:36:50 +0000 (13:36 -0500)
From docs at http://dev.mysql.com/doc/refman/5.0/en/mysql-real-query.html and
http://dev.mysql.com/doc/refman/5.0/en/mysql-field-count.html after performing the query
and attempting to get a result set, the RS ptr should be checked for null and
if it is check mysql_errno to see if there actually was an error, or just no result.

This patch makes database-query return NIL if there was no resultset.

db-mysql/mysql-sql.lisp

index 849fb39e724cdd76d3c82739facdc3b334c5b0f2..8ea7f4f48bddc1ccb4e4e5e470ce8d414585bfa3 100644 (file)
 
 
 (defmethod database-query (query-expression (database mysql-database)
-                           result-types field-names)
+                          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
-                                   (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
-                                    result-types res-ptr))
-                       (values
-                        (loop for row = (mysql-fetch-row res-ptr)
-                              for lengths = (mysql-fetch-lengths res-ptr)
-                              until (uffi:null-pointer-p row)
-                              collect
-                              (do* ((rlist (make-list num-fields))
-                                    (i 0 (1+ i))
-                                    (pos rlist (cdr pos)))
-                                   ((= i num-fields) rlist)
-                                (declare (fixnum i))
-                                (setf (car pos)
-                                      (convert-raw-field
-                                       (uffi:deref-array row '(:array
-                                                               (* :unsigned-char))
-                                                         i)
-                                       result-types i
-                                       (uffi:deref-array lengths '(:array :unsigned-long)
-                                                         i)))))
-                        (when field-names
-                          (result-field-names res-ptr))))
-                  (mysql-free-result res-ptr))
-                (error 'sql-database-data-error
-                       :database database
-                       :expression query-expression
-                       :error-id (mysql-errno mysql-ptr)
-                       :message (mysql-error-string mysql-ptr))))
-          (error 'sql-database-data-error
-                 :database database
-                 :expression query-expression
-                 :error-id (mysql-errno mysql-ptr)
-                 :message (mysql-error-string mysql-ptr))))))
+                                  (expression-length query-expression)))
+         (let ((res-ptr (mysql-use-result mysql-ptr)))
+           (if (and res-ptr (not (uffi:null-pointer-p res-ptr)))
+               (unwind-protect
+                    (let ((num-fields (mysql-num-fields res-ptr)))
+                      (declare (fixnum num-fields))
+                      (setq result-types (canonicalize-types
+                                          result-types res-ptr))
+                      (values
+                        (loop for row = (mysql-fetch-row res-ptr)
+                              for lengths = (mysql-fetch-lengths res-ptr)
+                              until (uffi:null-pointer-p row)
+                              collect
+                           (do* ((rlist (make-list num-fields))
+                                 (i 0 (1+ i))
+                                 (pos rlist (cdr pos)))
+                               ((= i num-fields) rlist)
+                             (declare (fixnum i))
+                             (setf (car pos)
+                                   (convert-raw-field
+                                    (uffi:deref-array row '(:array
+                                                            (* :unsigned-char))
+                                                      i)
+                                    result-types i
+                                    (uffi:deref-array lengths '(:array :unsigned-long)
+                                                      i)))))
+                        (when field-names
+                          (result-field-names res-ptr))))
+                 (mysql-free-result res-ptr))
+               (unless (zerop (mysql-errno mysql-ptr))
+                 ;;from http://dev.mysql.com/doc/refman/5.0/en/mysql-field-count.html
+                 ;; if mysql_use_result or mysql_store_result return a null ptr,
+                 ;; we use a mysql_errno check to see if it had a problem or just
+                 ;; was a query without a result. If no error, just return nil.
+                 (error 'sql-database-data-error
+                        :database database
+                        :expression query-expression
+                        :error-id (mysql-errno mysql-ptr)
+                        :message (mysql-error-string mysql-ptr)))))
+         (error 'sql-database-data-error
+                :database database
+                :expression query-expression
+                :error-id (mysql-errno mysql-ptr)
+                :message (mysql-error-string mysql-ptr))))))
 
 (defmethod database-execute-command (sql-expression (database mysql-database))
   (uffi:with-cstring (sql-native sql-expression)