X-Git-Url: http://git.kpe.io/?p=clsql.git;a=blobdiff_plain;f=db-oracle%2Foracle-sql.lisp;h=0250a34357bbf3c017d624198e29e0c1343ff6f9;hp=dfc3a155ae59a333f8255a95b50e57ddaf2723ed;hb=8d66a64a8453c9a9b26b2959d9238b5edec03564;hpb=5c67b804b62d2970685ebd8d28c88446457be975 diff --git a/db-oracle/oracle-sql.lisp b/db-oracle/oracle-sql.lisp index dfc3a15..0250a34 100644 --- a/db-oracle/oracle-sql.lisp +++ b/db-oracle/oracle-sql.lisp @@ -37,8 +37,6 @@ likely that we'll have to worry about the CMUCL limit.")) (defmacro deref-vp (foreign-object) `(the vp-type (uffi:deref-pointer (the vpp-type ,foreign-object) :pointer-void))) -;; constants - from OCI? - (defvar +unsigned-char-null-pointer+ (uffi:make-null-pointer :unsigned-char)) (defvar +unsigned-short-null-pointer+ @@ -46,6 +44,8 @@ likely that we'll have to worry about the CMUCL limit.")) (defvar +unsigned-int-null-pointer+ (uffi:make-null-pointer :unsigned-int)) +;; constants - from OCI? + (defconstant +var-not-in-list+ 1007) (defconstant +no-data-found+ 1403) (defconstant +null-value-returned+ 1405) @@ -118,19 +118,7 @@ the length of that format.") :initarg :major-server-version :reader major-server-version :documentation - "The major version number of the Oracle server, should be 8, 9, or 10") - (client-version - :type (or null string) - :initarg :client-version - :reader client-version - :documentation - "Version string of Oracle client.") - (major-client-version - :type (or null fixnum) - :initarg :major-client-version - :reader major-client-version - :documentation - "The major version number of the Oracle client, should be 8, 9, or 10"))) + "The major version number of the Oracle server, should be 8, 9, or 10"))) ;;; Handle the messy case of return code=+oci-error+, querying the @@ -139,16 +127,15 @@ the length of that format.") (defun handle-oci-error (&key database nulls-ok) (cond (database - (with-slots (errhp) - database + (with-slots (errhp) database (uffi:with-foreign-objects ((errbuf '(:array :unsigned-char #.+errbuf-len+)) (errcode :long)) ;; ensure errbuf empty string (setf (uffi:deref-array errbuf '(:array :unsigned-char) 0) - (uffi:ensure-char-storable (code-char 0))) - + (uffi:ensure-char-storable (code-char 0))) (setf (uffi:deref-pointer errcode :long) 0) + (uffi:with-cstring (sqlstate nil) (oci-error-get (deref-vp errhp) 1 sqlstate @@ -190,42 +177,27 @@ the length of that format.") ;;; Enabling this can be handy for low-level debugging. #+nil (progn - (trace oci-initialize #+oci-8-1-5 oci-env-create oci-handle-alloc oci-logon + (trace #-oci7 oci-env-create oci-initialize oci-handle-alloc oci-logon oci-error-get oci-stmt-prepare oci-stmt-execute oci-param-get oci-logon oci-attr-get oci-define-by-pos oci-stmt-fetch) (setf debug::*debug-print-length* nil)) -;;;; the OCI library, part V: converting from OCI representations to Lisp -;;;; representations - ;; Return the INDEXth string of the OCI array, represented as Lisp ;; SIMPLE-STRING. SIZE is the size of the fixed-width fields used by ;; Oracle to store strings within the array. -;; In the wild world of databases, trailing spaces aren't generally -;; significant, since e.g. "LARRY " and "LARRY " are the same string -;; stored in different fixed-width fields. OCI drops trailing spaces -;; for us in some cases but apparently not for fields of fixed -;; character width, e.g. -;; -;; (dbi:sql "create table employees (name char(15), job char(15), city -;; char(15), rate float)" :db orcl :types :auto) -;; In order to map the "same string" property above onto Lisp equality, -;; we drop trailing spaces in all cases: - (uffi:def-type string-pointer (* :unsigned-char)) (defun deref-oci-string (arrayptr string-index size) (declare (type string-pointer arrayptr)) (declare (type (mod #.+n-buf-rows+) string-index)) (declare (type (and unsigned-byte fixnum) size)) - (let* ((raw (uffi:convert-from-foreign-string - (uffi:make-pointer - (+ (uffi:pointer-address arrayptr) (* string-index size)) - :unsigned-char))) - (trimmed (string-trim " " raw))) - (if (equal trimmed "NULL") nil trimmed))) + (let ((str (uffi:convert-from-foreign-string + (uffi:make-pointer + (+ (uffi:pointer-address arrayptr) (* string-index size)) + :unsigned-char)))) + (if (string-equal str "NULL") nil str))) ;; the OCI library, part Z: no-longer used logic to convert from ;; Oracle's binary date representation to Common Lisp's native date @@ -411,7 +383,9 @@ the length of that format.") (#.SQLT-FLT (uffi:deref-array b '(:array :double) irow)) (#.SQLT-INT - (uffi:deref-array b '(:array :int) irow)) + (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)) @@ -641,11 +615,11 @@ the length of that format.") (deref-vp errhp)) (let ((*scale (uffi:deref-pointer scale :byte)) (*precision (uffi:deref-pointer precision :byte))) - - ;; (format t "scale=~d, precision=~d~%" *scale *precision) + + ;;(format t "scale=~d, precision=~d~%" *scale *precision) (cond - ((or (and (zerop *scale) (not (zerop *precision))) - (and (minusp *scale) (< *precision 10))) + ((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)) @@ -746,75 +720,49 @@ the length of that format.") ;; error-handling mechanism themselves) so we just assert they ;; work. (setf (deref-vp envhp) +null-void-pointer+) - #+oci-8-1-5 - (progn - (oci-env-create envhp +oci-default+ +null-void-pointer+ - +null-void-pointer+ +null-void-pointer+ - +null-void-pointer+ 0 +null-void-pointer-pointer+) - (oci-handle-alloc envhp - (deref-vp errhp) - +oci-htype-error+ 0 - +null-void-pointer-pointer+)) - #-oci-8-1-5 + #-oci7 + (oci-env-create envhp +oci-default+ +null-void-pointer+ + +null-void-pointer+ +null-void-pointer+ + +null-void-pointer+ 0 +null-void-pointer-pointer+) + #+oci7 (progn (oci-initialize +oci-object+ +null-void-pointer+ +null-void-pointer+ +null-void-pointer+ +null-void-pointer-pointer+) (ignore-errors (oci-handle-alloc +null-void-pointer+ envhp +oci-htype-env+ 0 +null-void-pointer-pointer+)) ;no testing return - (oci-env-init envhp +oci-default+ 0 +null-void-pointer-pointer+) - (oci-handle-alloc (deref-vp envhp) errhp - +oci-htype-error+ 0 +null-void-pointer-pointer+) - (oci-handle-alloc (deref-vp envhp) srvhp - +oci-htype-server+ 0 +null-void-pointer-pointer+) - (uffi:with-cstring (dblink nil) - (oci-server-attach (deref-vp srvhp) - (deref-vp errhp) - dblink - 0 +oci-default+)) - (oci-handle-alloc (deref-vp envhp) svchp - +oci-htype-svcctx+ 0 +null-void-pointer-pointer+) - (oci-attr-set (deref-vp svchp) - +oci-htype-svcctx+ - (deref-vp srvhp) 0 +oci-attr-server+ - (deref-vp errhp)) - ;; oci-handle-alloc((dvoid *)encvhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, 0, 0); - ;;#+nil - ) - ;; Actually, oci-server-version returns the client version, not the server versions - ;; will use "SELECT VERSION FROM V$INSTANCE" to get actual server version. - (let (db server-version client-version) - (declare (ignorable server-version)) - (uffi:with-foreign-object (buf '(:array :unsigned-char #.+errbuf-len+)) - (oci-server-version (deref-vp svchp) - (deref-vp errhp) - (uffi:char-array-to-pointer buf) - +errbuf-len+ +oci-htype-svcctx+) - (setf client-version (uffi:convert-from-foreign-string buf)) - ;; This returns the client version, not the server version, so diable it - #+ignore - (oci-server-version (deref-vp srvhp) - (deref-vp errhp) - (uffi:char-array-to-pointer buf) - +errbuf-len+ +oci-htype-server+) - #+ignore - (setf server-version (uffi:convert-from-foreign-string buf))) - (setq db (make-instance 'oracle-database - :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 - :client-version client-version - :server-version server-version - :major-client-version (major-client-version-from-string - client-version) - :major-server-version (major-client-version-from-string - server-version))) + (oci-env-init envhp +oci-default+ 0 +null-void-pointer-pointer+)) + (oci-handle-alloc (deref-vp envhp) errhp + +oci-htype-error+ 0 +null-void-pointer-pointer+) + (oci-handle-alloc (deref-vp envhp) srvhp + +oci-htype-server+ 0 +null-void-pointer-pointer+) + + #+ignore ;; not used since CLSQL uses the OCILogon function instead + (uffi:with-cstring (dblink nil) + (oci-server-attach (deref-vp srvhp) + (deref-vp errhp) + dblink + 0 +oci-default+)) + + (oci-handle-alloc (deref-vp envhp) svchp + +oci-htype-svcctx+ 0 +null-void-pointer-pointer+) + (oci-attr-set (deref-vp svchp) + +oci-htype-svcctx+ + (deref-vp srvhp) 0 +oci-attr-server+ + (deref-vp errhp)) + ;; oci-handle-alloc((dvoid *)encvhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, 0, 0); + ;;#+nil + + (let ((db (make-instance 'oracle-database + :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 @@ -916,17 +864,17 @@ the length of that format.") ) database :auto nil))) -;; FIXME: use lock (defmethod database-set-sequence-position (name position (database oracle-database)) - (let* ((next (database-sequence-next name database)) - (incr (- position next))) - (database-execute-command - (format nil "ALTER SEQUENCE ~A INCREMENT BY ~D" name incr) - database) - (database-sequence-next name database) - (database-execute-command - (format nil "ALTER SEQUENCE ~A INCREMENT BY 1" name) - database))) + (without-interrupts + (let* ((next (database-sequence-next name database)) + (incr (- position next))) + (database-execute-command + (format nil "ALTER SEQUENCE ~A INCREMENT BY ~D" name incr) + database) + (database-sequence-next name database) + (database-execute-command + (format nil "ALTER SEQUENCE ~A INCREMENT BY 1" name) + database)))) (defmethod database-list-sequences ((database oracle-database) &key owner) (let ((query @@ -939,8 +887,8 @@ the length of that format.") (defmethod database-execute-command (sql-expression (database oracle-database)) (database-query sql-expression database nil nil) - ;; HACK HACK HACK - (database-query "commit" database nil nil) + (when (database-autocommit database) + (oracle-commit database)) t) @@ -1008,27 +956,30 @@ the length of that format.") do (setf (nth i list) (nth i row))) list))) -(defmethod clsql-sys:database-start-transaction ((database oracle-database)) +(defmethod database-start-transaction ((database oracle-database)) (call-next-method) - ) - -;;(with-slots (svchp errhp) database -;; (osucc (oci-trans-start (uffi:deref-pointer svchp) -;; (uffi:deref-pointer errhp) -;; 60 -;; +oci-trans-new+))) -;; t) - + ;; Not needed with simple transaction + #+ignore + (with-slots (svchp errhp) database + (oci-trans-start (deref-vp svchp) + (deref-vp errhp) + 60 + +oci-trans-new+)) + t) -(defmethod clsql-sys:database-commit-transaction ((database oracle-database)) - (call-next-method) + +(defun oracle-commit (database) (with-slots (svchp errhp) database - (osucc (oci-trans-commit (deref-vp svchp) - (deref-vp errhp) - 0))) + (osucc (oci-trans-commit (deref-vp svchp) + (deref-vp errhp) + 0)))) + +(defmethod database-commit-transaction ((database oracle-database)) + (call-next-method) + (oracle-commit database) t) -(defmethod clsql-sys:database-abort-transaction ((database oracle-database)) +(defmethod database-abort-transaction ((database oracle-database)) (call-next-method) (osucc (oci-trans-rollback (deref-vp (svchp database)) (deref-vp (errhp database))