+ (case sql-type
+ ;; SQL extended datatypes
+ (#.$SQL_TINYINT (get-cast-byte data-ptr))
+ (#.$SQL_C_STINYINT (get-cast-byte data-ptr)) ;; ?
+ (#.$SQL_C_SSHORT (get-cast-short data-ptr)) ;; ?
+ (#.$SQL_SMALLINT (get-cast-short data-ptr)) ;; ??
+ (#.$SQL_INTEGER (get-cast-int data-ptr))
+ (#.$SQL_BIGINT (get-cast-big data-ptr))
+ ;; TODO: Change this to read in rationals instead of doubles
+ ((#.$SQL_DECIMAL #.$SQL_NUMERIC)
+ (let* ((*read-base* 10)
+ (*read-default-float-format* 'double-float)
+ (str (get-cast-foreign-string data-ptr)))
+ (read-from-string str)))
+ (#.$SQL_BIT (get-cast-byte data-ptr))
+ (t
+ (case c-type
+ ((#.$SQL_C_DATE #.$SQL_C_TYPE_DATE)
+ (funcall *time-conversion-function* (date-to-universal-time data-ptr)))
+ ((#.$SQL_C_TIME #.$SQL_C_TYPE_TIME)
+ (multiple-value-bind (universal-time frac) (time-to-universal-time data-ptr)
+ (funcall *time-conversion-function* universal-time frac)))
+ ((#.$SQL_C_TIMESTAMP #.$SQL_C_TYPE_TIMESTAMP)
+ (multiple-value-bind (universal-time frac) (timestamp-to-universal-time data-ptr)
+ (funcall *time-conversion-function* universal-time frac)))
+ (#.$SQL_INTEGER
+ (get-cast-int data-ptr))
+ (#.$SQL_C_FLOAT
+ (get-cast-single-float data-ptr))
+ (#.$SQL_C_DOUBLE
+ (get-cast-double-float data-ptr))
+ (#.$SQL_C_SLONG
+ (get-cast-long data-ptr))
+ #+lispworks
+ (#.$SQL_C_BIT ; encountered only in Access
+ (get-cast-byte data-ptr))
+ (#.$SQL_C_BINARY
+ (get-cast-binary data-ptr out-len *binary-format*))
+ ((#.$SQL_C_SSHORT #.$SQL_C_STINYINT) ; LMH short ints
+ (get-cast-short data-ptr)) ; LMH
+ (#.$SQL_C_SBIGINT (get-cast-big data-ptr))
+ #+ignore
+ (#.$SQL_C_CHAR
+ (code-char (get-cast-short data-ptr)))
+ (t
+ (get-cast-foreign-string data-ptr)))))))))
+
+ ;; FIXME: this could be better optimized for types which use READ-FROM-STRING above
+
+ (if (and (or (eq result-type t) (eq result-type :string))
+ value
+ (not (stringp value)))
+ (write-to-string value)
+ value)))