+;;; Handle a non-successful result from an OCI function.
+(defun handle-oci-result (result database nulls-ok)
+ (case result
+ (#.+oci-success+
+ +oci-success+)
+ (#.+oci-error+
+ (handle-oci-error :database database :nulls-ok nulls-ok))
+ (#.+oci-no-data+
+ (error 'sql-database-error :message "OCI No Data Found"))
+ (#.+oci-success-with-info+
+ (error 'sql-database-error :message "internal error: unexpected +oci-success-with-info"))
+ (#.+oci-invalid-handle+
+ (error 'sql-database-error :message "OCI Invalid Handle"))
+ (#.+oci-need-data+
+ (error 'sql-database-error :message "OCI Need Data"))
+ (#.+oci-still-executing+
+ (error 'sql-temporary-error :message "OCI Still Executing"))
+ (#.+oci-continue+
+ (error 'sql-database-error :message "OCI Continue"))
+ (1804
+ (error 'sql-database-error :message "Check ORACLE_HOME and NLS settings."))
+ (t
+ (error 'sql-database-error
+ :message
+ (format nil "OCI unknown error, code=~A" result)))))
- (errbuf (uffi:allocate-foreign-string #.+errbuf-len+)))
- ;; ensure errbuf empty string
- (setf (uffi:deref-array errbuf '(:array :unsigned-char) 0)
- (uffi:ensure-char-storable (code-char 0)))
- (setf (uffi:deref-pointer errcode 'sb4) 0)
-
- (uffi:with-cstring (sqlstate nil)
- (oci-error-get (deref-vp errhp) 1
- sqlstate
- errcode
- (uffi:char-array-to-pointer errbuf)
- +errbuf-len+ +oci-htype-error+))
- (let ((subcode (uffi:deref-pointer errcode 'sb4))
- (errstr (uffi:convert-from-foreign-string errbuf)))
- (uffi:free-foreign-object errcode)
- (uffi:free-foreign-object errbuf)
- (unless (and nulls-ok (= subcode +null-value-returned+))
- (error 'sql-database-error
- :database database
- :error-id subcode
- :message errstr))))))
+ (errbuf (uffi:allocate-foreign-string #.+errbuf-len+)))
+ ;; ensure errbuf empty string
+ (setf (uffi:deref-array errbuf '(:array :unsigned-char) 0)
+ (uffi:ensure-char-storable (code-char 0)))
+ (setf (uffi:deref-pointer errcode 'sb4) 0)
+
+ (uffi:with-cstring (sqlstate nil)
+ (oci-error-get (deref-vp errhp) 1
+ sqlstate
+ errcode
+ (uffi:char-array-to-pointer errbuf)
+ +errbuf-len+ +oci-htype-error+))
+ (let ((subcode (uffi:deref-pointer errcode 'sb4))
+ (errstr (uffi:convert-from-foreign-string errbuf)))
+ (uffi:free-foreign-object errcode)
+ (uffi:free-foreign-object errbuf)
+ (unless (and nulls-ok (= subcode +null-value-returned+))
+ (error 'sql-database-error
+ :database database
+ :error-id subcode
+ :message errstr))))))
- (if eof-errorp
- (error 'sql-database-error :message
- (format nil "no more rows available in ~S" qc))
- eof-value))
- ((>= (qc-n-to-dbi qc)
- (qc-n-from-oci qc))
- (refill-qc-buffers qc)
- (fetch-row qc nil eof-value))
- (t
- (let ((cds (qc-cds qc))
- (reversed-result nil)
- (irow (qc-n-to-dbi qc)))
- (dotimes (icd (length cds))
- (let* ((cd (aref cds icd))
- (b (foreign-resource-buffer (cd-buffer cd)))
- (value
- (let* ((arb (foreign-resource-buffer (cd-indicators cd)))
- (indicator (uffi:deref-array arb '(:array :short) irow)))
- ;;(declare (type short-array arb))
- (unless (= indicator -1)
- (ecase (cd-oci-data-type cd)
- (#.SQLT-STR
- (deref-oci-string b irow (cd-sizeof cd)))
- (#.SQLT-FLT
- (uffi:deref-array b '(:array :double) irow))
- (#.SQLT-INT
- (ecase (cd-sizeof cd)
- (4
- (uffi:deref-array b '(:array :int) irow))))
- (#.SQLT-DATE
- (deref-oci-string b irow (cd-sizeof cd))))))))
- (when (and (eq :string (cd-result-type cd))
- value
- (not (stringp value)))
- (setq value (write-to-string value)))
- (push value reversed-result)))
- (incf (qc-n-to-dbi qc))
- (nreverse reversed-result)))))
+ (if eof-errorp
+ (error 'sql-database-error :message
+ (format nil "no more rows available in ~S" qc))
+ eof-value))
+ ((>= (qc-n-to-dbi qc)
+ (qc-n-from-oci qc))
+ (refill-qc-buffers qc)
+ (fetch-row qc nil eof-value))
+ (t
+ (let ((cds (qc-cds qc))
+ (reversed-result nil)
+ (irow (qc-n-to-dbi qc)))
+ (dotimes (icd (length cds))
+ (let* ((cd (aref cds icd))
+ (b (foreign-resource-buffer (cd-buffer cd)))
+ (value
+ (let* ((arb (foreign-resource-buffer (cd-indicators cd)))
+ (indicator (uffi:deref-array arb '(:array :short) irow)))
+ (declare (type short-array arb))
+ (unless (= indicator -1)
+ (ecase (cd-oci-data-type cd)
+ (#.SQLT-STR
+ (deref-oci-string b irow (cd-sizeof cd)))
+ (#.SQLT-FLT
+ (locally
+ (declare (type double-array b))
+ (uffi:deref-array b '(:array :double) irow)))
+ (#.SQLT-INT
+ (ecase (cd-sizeof cd)
+ (4
+ (locally
+ (declare (type int-array b))
+ (uffi:deref-array b '(:array :int) irow)))))
+ (#.SQLT-DATE
+ (deref-oci-string b irow (cd-sizeof cd))))))))
+ (when (and (eq :string (cd-result-type cd))
+ value
+ (not (stringp value)))
+ (setq value (write-to-string value)))
+ (push value reversed-result)))
+ (incf (qc-n-to-dbi qc))
+ (nreverse reversed-result)))))
- (let ((stmthp (uffi:allocate-foreign-object :pointer-void))
- select-p)
-
- (uffi:with-foreign-object (stmttype :unsigned-short)
- (unwind-protect
- (progn
- (oci-handle-alloc (deref-vp envhp)
- stmthp
- +oci-htype-stmt+ 0 +null-void-pointer-pointer+)
- (oci-stmt-prepare (deref-vp stmthp)
- (deref-vp errhp)
- (uffi:convert-to-cstring sql-stmt-string)
- (length sql-stmt-string)
- +oci-ntv-syntax+ +oci-default+ :database db)
- (oci-attr-get (deref-vp stmthp)
- +oci-htype-stmt+
- stmttype
- +unsigned-int-null-pointer+
- +oci-attr-stmt-type+
- (deref-vp errhp)
- :database db)
-
- (setq select-p (= (uffi:deref-pointer stmttype :unsigned-short) 1))
- (let ((iters (if select-p 0 1)))
-
- (oci-stmt-execute (deref-vp svchp)
- (deref-vp stmthp)
- (deref-vp errhp)
- iters 0 +null-void-pointer+ +null-void-pointer+ +oci-default+
- :database db)))
- ;; free resources unless a query
- (unless select-p
- (oci-handle-free (deref-vp stmthp) +oci-htype-stmt+)
- (uffi:free-foreign-object stmthp))))
-
- (cond
- (select-p
- (make-query-cursor db stmthp result-types field-names))
- (t
- nil)))))
+ (uffi:with-foreign-strings ((c-stmt-string sql-stmt-string))
+ (let ((stmthp (uffi:allocate-foreign-object :pointer-void))
+ select-p)
+
+ (uffi:with-foreign-object (stmttype :unsigned-short)
+ (unwind-protect
+ (progn
+ (oci-handle-alloc (deref-vp envhp)
+ stmthp
+ +oci-htype-stmt+ 0 +null-void-pointer-pointer+)
+ (oci-stmt-prepare (deref-vp stmthp)
+ (deref-vp errhp)
+ c-stmt-string
+ (length sql-stmt-string)
+ +oci-ntv-syntax+ +oci-default+ :database db)
+ (oci-attr-get (deref-vp stmthp)
+ +oci-htype-stmt+
+ stmttype
+ +unsigned-int-null-pointer+
+ +oci-attr-stmt-type+
+ (deref-vp errhp)
+ :database db)
+
+ (setq select-p (= (uffi:deref-pointer stmttype :unsigned-short) 1))
+ (let ((iters (if select-p 0 1)))
+
+ (oci-stmt-execute (deref-vp svchp)
+ (deref-vp stmthp)
+ (deref-vp errhp)
+ iters 0 +null-void-pointer+ +null-void-pointer+ +oci-default+
+ :database db)))
+ ;; free resources unless a query
+ (unless select-p
+ (oci-handle-free (deref-vp stmthp) +oci-htype-stmt+)
+ (uffi:free-foreign-object stmthp))))
+
+ (cond
+ (select-p
+ (make-query-cursor db stmthp result-types field-names))
+ (t
+ nil))))))
- (sizeof nil))
- (do ((icolumn 0 (1+ icolumn))
- (cds-as-reversed-list nil))
- ((not (eql (oci-param-get (deref-vp stmthp)
- +oci-htype-stmt+
- (deref-vp errhp)
- parmdp
- (1+ icolumn) :database database)
- +oci-success+))
- (coerce (reverse cds-as-reversed-list) 'simple-vector))
- ;; Decode type of ICOLUMNth column into a type we're prepared to
- ;; handle in Lisp.
- (oci-attr-get (deref-vp parmdp)
- +oci-dtype-param+
- dtype-foreign
- +unsigned-int-null-pointer+
- +oci-attr-data-type+
- (deref-vp errhp))
- (let ((dtype (uffi:deref-pointer dtype-foreign :unsigned-short)))
- (declare (fixnum dtype))
- (case dtype
- (#.SQLT-DATE
- (setf buffer (acquire-foreign-resource :unsigned-char
- (* 32 +n-buf-rows+)))
- (setf sizeof 32 dtype #.SQLT-STR))
- (#.SQLT-NUMBER
- (oci-attr-get (deref-vp parmdp)
- +oci-dtype-param+
- precision
- +unsigned-int-null-pointer+
- +oci-attr-precision+
- (deref-vp errhp))
- (oci-attr-get (deref-vp parmdp)
- +oci-dtype-param+
- scale
- +unsigned-int-null-pointer+
- +oci-attr-scale+
- (deref-vp errhp))
- (let ((*scale (uffi:deref-pointer scale :byte))
- (*precision (uffi:deref-pointer precision :short)))
-
- ;;(format t "scale=~d, precision=~d~%" *scale *precision)
- (cond
- ((or (and (minusp *scale) (zerop *precision))
- (and (zerop *scale) (plusp *precision)))
- (setf buffer (acquire-foreign-resource :int +n-buf-rows+)
- sizeof 4 ;; sizeof(int)
- dtype #.SQLT-INT))
- (t
- (setf buffer (acquire-foreign-resource :double +n-buf-rows+)
- sizeof 8 ;; sizeof(double)
- dtype #.SQLT-FLT)))))
- ;; Default to SQL-STR
- (t
- (setf (uffi:deref-pointer colsize :unsigned-short) 0)
- (setf dtype #.SQLT-STR)
- (oci-attr-get (deref-vp parmdp)
- +oci-dtype-param+
- colsize
- +unsigned-int-null-pointer+
- +oci-attr-data-size+
- (deref-vp errhp))
- (let ((colsize-including-null (1+ (uffi:deref-pointer colsize :unsigned-short))))
- (setf buffer (acquire-foreign-resource
- :unsigned-char (* +n-buf-rows+ colsize-including-null)))
- (setf sizeof colsize-including-null))))
- (let ((retcodes (acquire-foreign-resource :unsigned-short +n-buf-rows+))
- (indicators (acquire-foreign-resource :short +n-buf-rows+))
- (colname-string ""))
- (when field-names
- (oci-attr-get (deref-vp parmdp)
- +oci-dtype-param+
- colname
- colnamelen
- +oci-attr-name+
- (deref-vp errhp))
- (setq colname-string (uffi:convert-from-foreign-string
- (uffi:deref-pointer colname '(* :unsigned-char))
- :length (uffi:deref-pointer colnamelen 'ub4))))
- (push (make-cd :name colname-string
- :sizeof sizeof
- :buffer buffer
- :oci-data-type dtype
- :retcodes retcodes
- :indicators indicators
- :result-type (cond
- ((consp result-types)
- (nth icolumn result-types))
- ((null result-types)
- :string)
- (t
- result-types)))
- cds-as-reversed-list)
- (oci-define-by-pos (deref-vp stmthp)
- defnp
- (deref-vp errhp)
- (1+ icolumn) ; OCI 1-based indexing again
- (foreign-resource-buffer buffer)
- sizeof
- dtype
- (foreign-resource-buffer indicators)
- +unsigned-short-null-pointer+
- (foreign-resource-buffer retcodes)
- +oci-default+))))))))
+ (sizeof nil))
+ (do ((icolumn 0 (1+ icolumn))
+ (cds-as-reversed-list nil))
+ ((not (eql (oci-param-get (deref-vp stmthp)
+ +oci-htype-stmt+
+ (deref-vp errhp)
+ parmdp
+ (1+ icolumn) :database database)
+ +oci-success+))
+ (coerce (reverse cds-as-reversed-list) 'simple-vector))
+ ;; Decode type of ICOLUMNth column into a type we're prepared to
+ ;; handle in Lisp.
+ (oci-attr-get (deref-vp parmdp)
+ +oci-dtype-param+
+ dtype-foreign
+ +unsigned-int-null-pointer+
+ +oci-attr-data-type+
+ (deref-vp errhp))
+ (let ((dtype (uffi:deref-pointer dtype-foreign :unsigned-short)))
+ (declare (fixnum dtype))
+ (case dtype
+ (#.SQLT-DATE
+ (setf buffer (acquire-foreign-resource :unsigned-char
+ (* 32 +n-buf-rows+)))
+ (setf sizeof 32 dtype #.SQLT-STR))
+ (#.SQLT-NUMBER
+ (oci-attr-get (deref-vp parmdp)
+ +oci-dtype-param+
+ precision
+ +unsigned-int-null-pointer+
+ +oci-attr-precision+
+ (deref-vp errhp))
+ (oci-attr-get (deref-vp parmdp)
+ +oci-dtype-param+
+ scale
+ +unsigned-int-null-pointer+
+ +oci-attr-scale+
+ (deref-vp errhp))
+ (let ((*scale (uffi:deref-pointer scale :byte))
+ (*precision (uffi:deref-pointer precision :short)))
+
+ ;;(format t "scale=~d, precision=~d~%" *scale *precision)
+ (cond
+ ((or (and (minusp *scale) (zerop *precision))
+ (and (zerop *scale) (plusp *precision)))
+ (setf buffer (acquire-foreign-resource :int +n-buf-rows+)
+ sizeof 4 ;; sizeof(int)
+ dtype #.SQLT-INT))
+ (t
+ (setf buffer (acquire-foreign-resource :double +n-buf-rows+)
+ sizeof 8 ;; sizeof(double)
+ dtype #.SQLT-FLT)))))
+ ;; Default to SQL-STR
+ (t
+ (setf (uffi:deref-pointer colsize :unsigned-short) 0)
+ (setf dtype #.SQLT-STR)
+ (oci-attr-get (deref-vp parmdp)
+ +oci-dtype-param+
+ colsize
+ +unsigned-int-null-pointer+
+ +oci-attr-data-size+
+ (deref-vp errhp))
+ (let ((colsize-including-null (1+ (uffi:deref-pointer colsize :unsigned-short))))
+ (setf buffer (acquire-foreign-resource
+ :unsigned-char (* +n-buf-rows+ colsize-including-null)))
+ (setf sizeof colsize-including-null))))
+ (let ((retcodes (acquire-foreign-resource :unsigned-short +n-buf-rows+))
+ (indicators (acquire-foreign-resource :short +n-buf-rows+))
+ (colname-string ""))
+ (when field-names
+ (oci-attr-get (deref-vp parmdp)
+ +oci-dtype-param+
+ colname
+ colnamelen
+ +oci-attr-name+
+ (deref-vp errhp))
+ (setq colname-string (uffi:convert-from-foreign-string
+ (uffi:deref-pointer colname '(* :unsigned-char))
+ :length (uffi:deref-pointer colnamelen 'ub4))))
+ (push (make-cd :name colname-string
+ :sizeof sizeof
+ :buffer buffer
+ :oci-data-type dtype
+ :retcodes retcodes
+ :indicators indicators
+ :result-type (cond
+ ((consp result-types)
+ (nth icolumn result-types))
+ ((null result-types)
+ :string)
+ (t
+ result-types)))
+ cds-as-reversed-list)
+ (oci-define-by-pos (deref-vp stmthp)
+ defnp
+ (deref-vp errhp)
+ (1+ icolumn) ; OCI 1-based indexing again
+ (foreign-resource-buffer buffer)
+ sizeof
+ dtype
+ (foreign-resource-buffer indicators)
+ +unsigned-short-null-pointer+
+ (foreign-resource-buffer retcodes)
+ +oci-default+))))))))
- :name (database-name-from-spec connection-spec
- database-type)
- :connection-spec connection-spec
- :envhp envhp
- :errhp errhp
- :database-type :oracle
- :svchp svchp
- :dsn data-source-name
- :user user)))
- (oci-logon (deref-vp envhp)
- (deref-vp errhp)
- svchp
- (uffi:convert-to-cstring user) (length user)
- (uffi:convert-to-cstring password) (length password)
- (uffi:convert-to-cstring data-source-name) (length data-source-name)
- :database db)
- ;; :date-format-length (1+ (length date-format)))))
- (setf (slot-value db 'clsql-sys::state) :open)
+ :name (database-name-from-spec connection-spec
+ database-type)
+ :connection-spec connection-spec
+ :envhp envhp
+ :errhp errhp
+ :database-type :oracle
+ :svchp svchp
+ :dsn data-source-name
+ :user user)))
+ (uffi:with-foreign-strings ((c-user user)
+ (c-password password)
+ (c-data-source-name data-source-name))
+ (oci-logon (deref-vp envhp)
+ (deref-vp errhp)
+ svchp
+ c-user (length user)
+ c-password (length password)
+ c-data-source-name (length data-source-name)
+ :database db))
+ ;; :date-format-length (1+ (length date-format)))))
+ (setf (slot-value db 'clsql-sys::state) :open)