* sql/db-interface.lisp: Add more default methods
* sql/objects.lisp: Add explicit table name to order-by parameters
in find-all when only one table to avoid selecting a duplicate row.
Fix error in FIND-ALL when using :order-by such as (([foo] :asc))
as previous logic was adding two fields (foo asc) to SELECT query.
* db-oracle/*.lisp: Much improvements, now passes 90% of test suite
14 files changed:
+19 May 2004 Kevin Rosenberg (kevin@rosenberg.net)
+ * sql/db-interface.lisp: Add more default methods
+ * sql/objects.lisp: Add explicit table name to order-by parameters
+ in find-all when only one table to avoid selecting a duplicate row.
+ Fix error in FIND-ALL when using :order-by such as (([foo] :asc))
+ as previous logic was adding two fields (foo asc) to SELECT query.
+ * db-oracle/*.lisp: Much improvements, now passes 90% of test suite
+
19 May 2004 Marcus Pearce (m.t.pearce@city.ac.uk)
* sql/recording.lisp: reworked docstrings.
* sql/syntax.lisp: reworked docstrings.
19 May 2004 Marcus Pearce (m.t.pearce@city.ac.uk)
* sql/recording.lisp: reworked docstrings.
* sql/syntax.lisp: reworked docstrings.
(defvar +null-void-pointer+ (uffi:make-null-pointer :void))
(defvar +null-void-pointer+ (uffi:make-null-pointer :void))
-(defvar +null-void-pointer-pointer+ (uffi:make-null-pointer ':pointer-void))
+(defvar +null-void-pointer-pointer+ (uffi:make-null-pointer :pointer-void))
;;; Check an OCI return code for erroricity and signal a reasonably
;;; informative condition if so.
;;; Check an OCI return code for erroricity and signal a reasonably
;;; informative condition if so.
-#+nil
-(progn
-;;; Low-level functions which don't use return checking
-;;;
-;;; KMR: These are currently unused by the backend
+
+;;; Low-level routines that don't do error checking. They are used
+;;; for setting up global environment.
(uffi:def-function "OCIInitialize"
((mode :unsigned-long) ; ub4
(uffi:def-function "OCIInitialize"
((mode :unsigned-long) ; ub4
(usermempp (* :pointer-void)))
:returning :int)
(usermempp (* :pointer-void)))
:returning :int)
-(def-oci-routine ("OCIHandleAlloc" oci-handle-alloc)
- :int
-)
(uffi:def-function "OCIHandleAlloc"
((parenth :pointer-void) ; const dvoid *
(uffi:def-function "OCIHandleAlloc"
((parenth :pointer-void) ; const dvoid *
(declare (ignore type args))
(concatenate 'string "VARCHAR2(" *oracle-default-varchar2-length* ")"))
(declare (ignore type args))
(concatenate 'string "VARCHAR2(" *oracle-default-varchar2-length* ")"))
+(defmethod database-get-type-specifier ((type (eql 'integer)) args (database oracle-database))
+ (if args
+ (format nil "NUMBER(~A,~A)"
+ (or (first args) 38) (or (second args) 0))
+ "INTEGER"))
+
(defmethod database-get-type-specifier
(defmethod database-get-type-specifier
- ((type (eql 'integer)) args (database oracle-database))
+ ((type (eql 'bigint)) args (database oracle-database))
(if args
(format nil "NUMBER(~A,~A)"
(or (first args) 38) (or (second args) 0))
(if args
(format nil "NUMBER(~A,~A)"
(or (first args) 38) (or (second args) 0))
likely that we'll have to worry about the CMUCL limit."))
likely that we'll have to worry about the CMUCL limit."))
-;;; utilities for mucking around with C-level stuff
-
-;; Return the address of ALIEN-OBJECT (like the C operator "&").
-;;
-;; The INDICES argument is useful to give the ALIEN-OBJECT the
-;; expected number of zero indices, especially when we have a bunch of
-;; 1-element arrays running around due to the workaround for the CMUCL
-;; 18b WITH-ALIEN scalar bug.
-
-(defmacro c-& (alien-object type)
- `(uffi:pointer-address (uffi:deref-pointer ,alien-object ,type)))
+(defmacro deref-vp (foreign-object)
+ `(uffi:deref-pointer ,foreign-object void-pointer))
(defconstant +field-truncated+ 1406)
(eval-when (:compile-toplevel :load-toplevel :execute)
(defconstant +field-truncated+ 1406)
(eval-when (:compile-toplevel :load-toplevel :execute)
+ (defconstant SQLT-NUMBER 2)
(defconstant SQLT-INT 3)
(defconstant SQLT-STR 5)
(defconstant SQLT-FLT 4)
(defconstant SQLT-INT 3)
(defconstant SQLT-STR 5)
(defconstant SQLT-FLT 4)
(cond (database
(with-slots (errhp)
database
(cond (database
(with-slots (errhp)
database
- (uffi:with-foreign-objects ((errbuf :unsigned-char +errbuf-len+)
+ (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)
(errcode :long))
;; ensure errbuf empty string
(setf (uffi:deref-array errbuf '(:array :unsigned-char) 0)
(+ (uffi:pointer-address arrayptr) (* string-index size))
:unsigned-char)))
(trimmed (string-trim " " raw)))
(+ (uffi:pointer-address arrayptr) (* string-index size))
:unsigned-char)))
(trimmed (string-trim " " raw)))
- (if (equal trimmed "NULL") nil trimmed)))
+ (if (equal trimmed "NULL") nil trimmed)))
;; the OCI library, part Z: no-longer used logic to convert from
;; Oracle's binary date representation to Common Lisp's native date
;; the OCI library, part Z: no-longer used logic to convert from
;; Oracle's binary date representation to Common Lisp's native date
(second (1- (ub 6))))
(encode-universal-time second minute hour day month year))))
(second (1- (ub 6))))
(encode-universal-time second minute hour day month year))))
-;; Return (VALUES ALL-TABLES COLUMN-NAMES), where ALL-TABLES is a
-;; table containing one row for each table available in DB, and
-;; COLUMN-NAMES is a list of header names for the columns in
-;; ALL-TABLES.
-;;
-;; The Allegro version also accepted a HSTMT argument.
-
-;(defmethod database-list-tables ((db oracle-database))
-; (sql:query "select '',OWNER,TABLE_NAME,TABLE_TYPE,'' from all_catalog"))
-
-
(defmethod database-list-tables ((database oracle-database) &key owner)
(mapcar #'car
(database-query "select table_name from user_tables"
(defmethod database-list-tables ((database oracle-database) &key owner)
(mapcar #'car
(database-query "select table_name from user_tables"
(mapcar #'car
(database-query
(format nil
(mapcar #'car
(database-query
(format nil
- "select user_tab_columns,column_name from user_tab_columns where user_tab_columns.table_name='~A'"
+ "select column_name from user_tab_columns where table_name='~A'"
table)
database nil nil)))
table)
database nil nil)))
+(defmethod database-attribute-type (attribute (table string)
+ (database oracle-database)
+ &key (owner nil))
+ (let ((rows
+ (database-query
+ (format nil
+ "select data_type,data_length,data_precision,data_scale,nullable from user_tab_columns where table_name='~A' and column_name='~A'"
+ table attribute)
+ database :auto nil)))
+ (destructuring-bind (type length precision scale nullable) (car rows)
+ (values (ensure-keyword type) length precision scale
+ (if (char-equal #\Y (schar nullable 0)) 1 0)))))
+
;; Return one row of the table referred to by QC, represented as a
;; list; or if there are no more rows, signal an error if EOF-ERRORP,
;; or return EOF-VALUE otherwise.
;; Return one row of the table referred to by QC, represented as a
;; list; or if there are no more rows, signal an error if EOF-ERRORP,
;; or return EOF-VALUE otherwise.
(let* ((cd (aref cds icd))
(b (foreign-resource-buffer (cd-buffer cd)))
(value
(let* ((cd (aref cds icd))
(b (foreign-resource-buffer (cd-buffer cd)))
(value
- (let ((arb (foreign-resource-buffer (cd-indicators cd))))
- (declare (type int-pointer arb))
- (unless (= (uffi:deref-array arb '(:array :int) irow) -1)
+ (let* ((arb (foreign-resource-buffer (cd-indicators cd)))
+ (indicator (uffi:deref-array arb '(:array :short) irow)))
+ (declare (type short-pointer arb))
+ (unless (= indicator -1)
(ecase (cd-oci-data-type cd)
(#.SQLT-STR
(deref-oci-string b irow (cd-sizeof cd)))
(ecase (cd-oci-data-type cd)
(#.SQLT-STR
(deref-oci-string b irow (cd-sizeof cd)))
(uffi:deref-array bi '(:array :int) irow)))
(#.SQLT-DATE
(deref-oci-string b irow (cd-sizeof cd))))))))
(uffi:deref-array bi '(: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)))))
(push value reversed-result)))
(incf (qc-n-to-dbi qc))
(nreverse reversed-result)))))
(setf (qc-n-from-oci qc) 0))
(t
(let ((oci-code (%oci-stmt-fetch
(setf (qc-n-from-oci qc) 0))
(t
(let ((oci-code (%oci-stmt-fetch
- (uffi:deref-pointer (qc-stmthp qc) void-pointer)
- (uffi:deref-pointer errhp void-pointer)
+ (deref-vp (qc-stmthp qc))
+ (deref-vp errhp)
+n-buf-rows+
+oci-fetch-next+ +oci-default+)))
(ecase oci-code
+n-buf-rows+
+oci-fetch-next+ +oci-default+)))
(ecase oci-code
(#.+oci-error+ (handle-oci-error :database (qc-db qc)
:nulls-ok t))))
(uffi:with-foreign-object (rowcount :long)
(#.+oci-error+ (handle-oci-error :database (qc-db qc)
:nulls-ok t))))
(uffi:with-foreign-object (rowcount :long)
- (oci-attr-get (uffi:deref-pointer (qc-stmthp qc) void-pointer)
+ (oci-attr-get (deref-vp (qc-stmthp qc))
+oci-htype-stmt+
rowcount
(uffi:make-null-pointer :unsigned-long)
+oci-attr-row-count+
+oci-htype-stmt+
rowcount
(uffi:make-null-pointer :unsigned-long)
+oci-attr-row-count+
- (uffi:deref-pointer errhp void-pointer))
(setf (qc-n-from-oci qc)
(- (uffi:deref-pointer rowcount :long)
(qc-total-n-from-oci qc)))
(setf (qc-n-from-oci qc)
(- (uffi:deref-pointer rowcount :long)
(qc-total-n-from-oci qc)))
;; QUERY-CURSOR, and the new QUERY-CURSOR becomes responsible for
;; freeing the STMTHP when it is no longer needed.
;; QUERY-CURSOR, and the new QUERY-CURSOR becomes responsible for
;; freeing the STMTHP when it is no longer needed.
-(defun sql-stmt-exec (sql-stmt-string db &key types)
+(defun sql-stmt-exec (sql-stmt-string db result-types field-names)
(with-slots (envhp svchp errhp)
db
(let ((stmthp (uffi:allocate-foreign-object void-pointer)))
(uffi:with-foreign-object (stmttype :unsigned-short)
(with-slots (envhp svchp errhp)
db
(let ((stmthp (uffi:allocate-foreign-object void-pointer)))
(uffi:with-foreign-object (stmttype :unsigned-short)
- (oci-handle-alloc (uffi:deref-pointer envhp void-pointer)
+ (oci-handle-alloc (deref-vp envhp)
stmthp
+oci-htype-stmt+ 0 +null-void-pointer-pointer+)
stmthp
+oci-htype-stmt+ 0 +null-void-pointer-pointer+)
- (oci-stmt-prepare (uffi:deref-pointer stmthp void-pointer)
- (uffi:deref-pointer errhp void-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)
(uffi:convert-to-cstring sql-stmt-string)
(length sql-stmt-string)
+oci-ntv-syntax+ +oci-default+ :database db)
- (oci-attr-get (uffi:deref-pointer stmthp void-pointer)
+ (oci-attr-get (deref-vp stmthp)
+oci-htype-stmt+
stmttype
(uffi:make-null-pointer :unsigned-int)
+oci-attr-stmt-type+
+oci-htype-stmt+
stmttype
(uffi:make-null-pointer :unsigned-int)
+oci-attr-stmt-type+
- (uffi:deref-pointer errhp void-pointer)
:database db)
(let* ((select-p (= (uffi:deref-pointer stmttype :unsigned-short) 1))
(iters (if select-p 0 1)))
:database db)
(let* ((select-p (= (uffi:deref-pointer stmttype :unsigned-short) 1))
(iters (if select-p 0 1)))
- (oci-stmt-execute (uffi:deref-pointer svchp void-pointer)
- (uffi:deref-pointer stmthp void-pointer)
- (uffi:deref-pointer errhp void-pointer)
+ (oci-stmt-execute (deref-vp svchp)
+ (deref-vp stmthp)
+ (deref-vp errhp)
iters 0 +null-void-pointer+ +null-void-pointer+ +oci-default+
:database db)
(cond (select-p
iters 0 +null-void-pointer+ +null-void-pointer+ +oci-default+
:database db)
(cond (select-p
- (make-query-cursor db stmthp types))
+ (make-query-cursor db stmthp result-types field-names))
- (oci-handle-free (uffi:deref-pointer stmthp void-pointer) +oci-htype-stmt+)
+ (oci-handle-free (deref-vp stmthp) +oci-htype-stmt+)
;; name from the external SQL function, controlling type conversion
;; of the returned arguments.
;; name from the external SQL function, controlling type conversion
;; of the returned arguments.
-(defun make-query-cursor (db stmthp types)
+(defun make-query-cursor (db stmthp result-types field-names)
(let ((qc (%make-query-cursor :db db
:stmthp stmthp
(let ((qc (%make-query-cursor :db db
:stmthp stmthp
- :cds (make-query-cursor-cds db stmthp types))))
+ :cds (make-query-cursor-cds db stmthp
+ result-types
+ field-names))))
(refill-qc-buffers qc)
qc))
(refill-qc-buffers qc)
qc))
-(defun make-query-cursor-cds (database stmthp types)
+(defun make-query-cursor-cds (database stmthp result-types field-names)
(declare (optimize (safety 3) #+nil (speed 3))
(type oracle-database database)
(type pointer-pointer-void stmthp))
(declare (optimize (safety 3) #+nil (speed 3))
(type oracle-database database)
(type pointer-pointer-void stmthp))
- (with-slots (errhp)
- database
- (unless (eq types :auto)
- (error "unsupported TYPES value"))
+ (with-slots (errhp) database
(uffi:with-foreign-objects ((dtype-foreign :unsigned-short)
(parmdp ':pointer-void)
(precision :byte)
(uffi:with-foreign-objects ((dtype-foreign :unsigned-short)
(parmdp ':pointer-void)
(precision :byte)
(sizeof nil))
(do ((icolumn 0 (1+ icolumn))
(cds-as-reversed-list nil))
(sizeof nil))
(do ((icolumn 0 (1+ icolumn))
(cds-as-reversed-list nil))
- ((not (eql (oci-param-get (uffi:deref-pointer stmthp void-pointer)
+ ((not (eql (oci-param-get (deref-vp stmthp)
- (uffi:deref-pointer errhp void-pointer)
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.
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 (uffi:deref-pointer parmdp void-pointer)
+ (oci-attr-get (deref-vp parmdp)
+oci-dtype-param+
dtype-foreign
+oci-dtype-param+
dtype-foreign
- (uffi:make-null-pointer :int) +oci-attr-data-type+
- (uffi:deref-pointer errhp void-pointer))
+ (uffi:make-null-pointer :int)
+ +oci-attr-data-type+
+ (deref-vp errhp))
(let ((dtype (uffi:deref-pointer dtype-foreign :unsigned-short)))
(case dtype
(#.SQLT-DATE
(let ((dtype (uffi:deref-pointer dtype-foreign :unsigned-short)))
(case dtype
(#.SQLT-DATE
- (setf buffer (acquire-foreign-resource :char (* 32 +n-buf-rows+)))
+ (setf buffer (acquire-foreign-resource :unsigned-char
+ (* 32 +n-buf-rows+)))
(setf sizeof 32 dtype #.SQLT-STR))
(setf sizeof 32 dtype #.SQLT-STR))
- (2 ;; number
- ;;(oci-attr-get parmdp +oci-dtype-param+
- ;;(addr precision) nil +oci-attr-precision+
- ;;(uffi:deref-pointer errhp))
- (oci-attr-get (uffi:deref-pointer parmdp void-pointer)
+ (#.SQLT-NUMBER
+ (oci-attr-get (deref-vp parmdp)
+ +oci-dtype-param+
+ precision
+ (uffi:make-null-pointer :int)
+ +oci-attr-precision+
+ (deref-vp errhp))
+ (oci-attr-get (deref-vp parmdp)
- (uffi:make-null-pointer :int) +oci-attr-scale+
- (uffi:deref-pointer errhp void-pointer))
- (cond
- ((zerop (uffi:deref-pointer scale :byte))
- (setf buffer (acquire-foreign-resource :init +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))))
- (t ; Default to SQL-STR
+ (uffi:make-null-pointer :int)
+ +oci-attr-scale+
+ (deref-vp errhp))
+ (let ((*scale (uffi:deref-pointer scale :byte))
+ (*precision (uffi:deref-pointer precision :byte)))
+ ;;(format t "scale=~d, precision=~d~%" *scale *precision)
+ (cond
+ ((or (zerop *scale)
+ (and (minusp *scale) (< *precision 10)))
+ (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-long) 0
dtype #.SQLT-STR)
(setf (uffi:deref-pointer colsize :unsigned-long) 0
dtype #.SQLT-STR)
- (oci-attr-get (uffi:deref-pointer parmdp void-pointer)
+ (oci-attr-get (deref-vp parmdp)
+oci-dtype-param+
colsize
(uffi:make-null-pointer :int) ;; (uffi:pointer-address colsizesize)
+oci-attr-data-size+
+oci-dtype-param+
colsize
(uffi:make-null-pointer :int) ;; (uffi:pointer-address colsizesize)
+oci-attr-data-size+
- (uffi:deref-pointer errhp void-pointer))
(let ((colsize-including-null (1+ (uffi:deref-pointer colsize :unsigned-long))))
(setf buffer (acquire-foreign-resource
:char (* +n-buf-rows+ colsize-including-null)))
(setf sizeof colsize-including-null))))
(let ((retcodes (acquire-foreign-resource :short +n-buf-rows+))
(let ((colsize-including-null (1+ (uffi:deref-pointer colsize :unsigned-long))))
(setf buffer (acquire-foreign-resource
:char (* +n-buf-rows+ colsize-including-null)))
(setf sizeof colsize-including-null))))
(let ((retcodes (acquire-foreign-resource :short +n-buf-rows+))
- (indicators (acquire-foreign-resource :short +n-buf-rows+)))
- (push (make-cd :name "col" ;(subseq colname 0 colnamelen)
+ (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 :unsigned-long))))
+ (push (make-cd :name colname-string
:sizeof sizeof
:buffer buffer
:oci-data-type dtype
:retcodes retcodes
:sizeof sizeof
:buffer buffer
:oci-data-type dtype
:retcodes retcodes
- :indicators indicators)
+ :indicators indicators
+ :result-type (cond
+ ((consp result-types)
+ (nth icolumn result-types))
+ ((null result-types)
+ :string)
+ (t
+ result-types)))
- (oci-define-by-pos (uffi:deref-pointer stmthp void-pointer)
+ (oci-define-by-pos (deref-vp stmthp)
- (uffi:deref-pointer errhp void-pointer)
(1+ icolumn) ; OCI 1-based indexing again
(foreign-resource-buffer buffer)
sizeof
(1+ icolumn) ; OCI 1-based indexing again
(foreign-resource-buffer buffer)
sizeof
;; Release the resources associated with a QUERY-CURSOR.
(defun close-query (qc)
;; Release the resources associated with a QUERY-CURSOR.
(defun close-query (qc)
- (oci-handle-free (uffi:deref-pointer (qc-stmthp qc) void-pointer) +oci-htype-stmt+)
+ (oci-handle-free (deref-vp (qc-stmthp qc)) +oci-htype-stmt+)
(let ((cds (qc-cds qc)))
(dotimes (i (length cds))
(release-cd-resources (aref cds i))))
(let ((cds (qc-cds qc)))
(dotimes (i (length cds))
(release-cd-resources (aref cds i))))
;; handle errors very gracefully (since they're part of the
;; error-handling mechanism themselves) so we just assert they
;; work.
;; handle errors very gracefully (since they're part of the
;; error-handling mechanism themselves) so we just assert they
;; work.
- (setf (uffi:deref-pointer envhp void-pointer) +null-void-pointer+)
+ (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
#+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
- (c-& errhp void-pointer) +oci-htype-error+ 0
+ (deref-vp errhp)
+ +oci-htype-error+ 0
+null-void-pointer-pointer+))
#-oci-8-1-5
(progn
+null-void-pointer-pointer+))
#-oci-8-1-5
(progn
+oci-htype-env+ 0
+null-void-pointer-pointer+)) ;no testing return
(oci-env-init envhp +oci-default+ 0 +null-void-pointer-pointer+)
+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 (uffi:deref-pointer envhp void-pointer) errhp
+ (oci-handle-alloc (deref-vp envhp) errhp
+oci-htype-error+ 0 +null-void-pointer-pointer+)
+oci-htype-error+ 0 +null-void-pointer-pointer+)
- (oci-handle-alloc (uffi:deref-pointer envhp void-pointer) srvhp
+ (oci-handle-alloc (deref-vp envhp) srvhp
+oci-htype-server+ 0 +null-void-pointer-pointer+)
+oci-htype-server+ 0 +null-void-pointer-pointer+)
- (oci-server-attach (uffi:deref-pointer srvhp void-pointer)
- (uffi:deref-pointer errhp void-pointer)
+ (oci-server-attach (deref-vp srvhp)
+ (deref-vp errhp)
(uffi:make-null-pointer :unsigned-char)
0 +oci-default+)
(uffi:make-null-pointer :unsigned-char)
0 +oci-default+)
- (oci-handle-alloc (uffi:deref-pointer envhp void-pointer) svchp
+ (oci-handle-alloc (deref-vp envhp) svchp
+oci-htype-svcctx+ 0 +null-void-pointer-pointer+)
+oci-htype-svcctx+ 0 +null-void-pointer-pointer+)
- (oci-attr-set (uffi:deref-pointer svchp void-pointer)
+ (oci-attr-set (deref-vp svchp)
- (uffi:deref-pointer srvhp void-pointer) 0 +oci-attr-server+
- (uffi:deref-pointer errhp void-pointer))
+ (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 server-version)
(uffi:with-foreign-object (buf '(:array :unsigned-char #.+errbuf-len+))
;; oci-handle-alloc((dvoid *)encvhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, 0, 0);
;;#+nil
)
(let (db server-version)
(uffi:with-foreign-object (buf '(:array :unsigned-char #.+errbuf-len+))
- (oci-server-version (uffi:deref-pointer svchp void-pointer)
- (uffi:deref-pointer errhp void-pointer)
+ (oci-server-version (deref-vp svchp)
+ (deref-vp errhp)
buf +errbuf-len+ +oci-htype-svcctx+)
(setf server-version (uffi:convert-from-foreign-string buf)))
(setq db (make-instance 'oracle-database
buf +errbuf-len+ +oci-htype-svcctx+)
(setf server-version (uffi:convert-from-foreign-string buf)))
(setq db (make-instance 'oracle-database
:major-version-number (major-version-from-string
server-version)))
:major-version-number (major-version-from-string
server-version)))
- (oci-logon (uffi:deref-pointer envhp void-pointer)
- (uffi:deref-pointer errhp void-pointer)
+ (oci-logon (deref-vp envhp)
+ (deref-vp errhp)
svchp
(uffi:convert-to-cstring user) (length user)
(uffi:convert-to-cstring password) (length password)
svchp
(uffi:convert-to-cstring user) (length user)
(uffi:convert-to-cstring password) (length password)
;; Close a database connection.
(defmethod database-disconnect ((database oracle-database))
;; Close a database connection.
(defmethod database-disconnect ((database oracle-database))
- (osucc (oci-logoff (uffi:deref-pointer (svchp database) void-pointer)
- (uffi:deref-pointer (errhp database) void-pointer)))
- (osucc (oci-handle-free (uffi:deref-pointer (envhp database) void-pointer)
- +oci-htype-env+))
+ (osucc (oci-logoff (deref-vp (svchp database))
+ (deref-vp (errhp database))))
+ (osucc (oci-handle-free (deref-vp (envhp database)) +oci-htype-env+))
;; Note: It's neither required nor allowed to explicitly deallocate the
;; ERRHP handle here, since it's owned by the ENVHP deallocated above,
;; and was therefore automatically deallocated at the same time.
;; Note: It's neither required nor allowed to explicitly deallocate the
;; ERRHP handle here, since it's owned by the ENVHP deallocated above,
;; and was therefore automatically deallocated at the same time.
;;; values for this argument, but we only support :AUTO.
(defmethod database-query (query-expression (database oracle-database) result-types field-names)
;;; values for this argument, but we only support :AUTO.
(defmethod database-query (query-expression (database oracle-database) result-types field-names)
- (let ((cursor (sql-stmt-exec query-expression database :types :auto)))
+ (let ((cursor (sql-stmt-exec query-expression database result-types field-names)))
;; (declare (type (or query-cursor null) cursor))
(if (null cursor) ; No table was returned.
(values)
;; (declare (type (or query-cursor null) cursor))
(if (null cursor) ; No table was returned.
(values)
(row (fetch-row cursor nil eof-value)))
(when (eq row eof-value)
(close-query cursor)
(row (fetch-row cursor nil eof-value)))
(when (eq row eof-value)
(close-query cursor)
- (return (nreverse reversed-result)))
+ (if field-names
+ (return (values (nreverse reversed-result)
+ (loop for cd across (qc-cds cursor)
+ collect (cd-name cd))))
+ (return (nreverse reversed-result))))
(push row reversed-result))))))
(push row reversed-result))))))
-;;; a column descriptor: metadata about the data in a table
(defstruct (cd (:constructor make-cd)
(:print-function print-cd))
(defstruct (cd (:constructor make-cd)
(:print-function print-cd))
+ "a column descriptor: metadata about the data in a table"
+
;; name of this column
(name (error "missing NAME") :type simple-string :read-only t)
;; the size in bytes of a single element
;; name of this column
(name (error "missing NAME") :type simple-string :read-only t)
;; the size in bytes of a single element
;; the OCI code for the data type of a single element
(oci-data-type (error "missing OCI-DATA-TYPE")
:type fixnum
;; the OCI code for the data type of a single element
(oci-data-type (error "missing OCI-DATA-TYPE")
:type fixnum
+ :read-only t)
+ (result-type (error "missing RESULT-TYPE")
+ :read-only t))
(defun print-cd (cd stream depth)
(defun print-cd (cd stream depth)
(defmethod database-query-result-set ((query-expression string)
(database oracle-database)
&key full-set result-types)
(defmethod database-query-result-set ((query-expression string)
(database oracle-database)
&key full-set result-types)
+ (let ((cursor (sql-stmt-exec query-expression database result-types nil)))
+ (if full-set
+ (values cursor (length (qc-cds cursor)) nil)
+ (values cursor (length (qc-cds cursor))))))
+
(defmethod database-dump-result-set (result-set (database oracle-database))
(defmethod database-dump-result-set (result-set (database oracle-database))
+ (close-query result-set))
(defmethod database-store-next-row (result-set (database oracle-database) list)
(defmethod database-store-next-row (result-set (database oracle-database) list)
- )
-
-(defmethod clsql-sys::database-start-transaction ((database oracle-database))
+ (let* ((eof-value :eof)
+ (row (fetch-row result-set nil eof-value)))
+ (unless (eq eof-value row)
+ (loop for i from 0 below (length row)
+ do (setf (nth i list) (nth i row)))
+ list)))
+
+(defmethod clsql-sys:database-start-transaction ((database oracle-database))
(call-next-method))
;;(with-slots (svchp errhp) database
(call-next-method))
;;(with-slots (svchp errhp) database
-(defmethod clsql-sys::database-commit-transaction ((database oracle-database))
+(defmethod clsql-sys:database-commit-transaction ((database oracle-database))
(call-next-method)
(with-slots (svchp errhp) database
(call-next-method)
(with-slots (svchp errhp) database
- (osucc (oci-trans-commit (uffi:deref-pointer svchp void-pointer)
- (uffi:deref-pointer errhp void-pointer)
+ (osucc (oci-trans-commit (deref-vp svchp)
+ (deref-vp errhp)
-(defmethod clsql-sys::database-abort-transaction ((database oracle-database))
+(defmethod clsql-sys:database-abort-transaction ((database oracle-database))
- (osucc (oci-trans-rollback (uffi:deref-pointer (svchp database) void-pointer)
- (uffi:deref-pointer (errhp database) void-pointer)
- 0))
+ (osucc (oci-trans-rollback (deref-vp (svchp database))
+ (deref-vp (errhp database))
+ 0))
t)
(defparameter *constraint-types*
t)
(defparameter *constraint-types*
(defmethod db-type-has-bigint? ((type (eql :oracle)))
nil)
(defmethod db-type-has-bigint? ((type (eql :oracle)))
nil)
-(defmethod db-type-has-fancy-math? ((db-type (eql :postgresql)))
+(defmethod db-type-has-fancy-math? ((db-type (eql :oracle)))
+
+(defmethod db-type-has-boolean-where? ((db-type (eql :oracle)))
+ nil)
+
+(when (clsql-sys:database-type-library-loaded :oracle)
+ (clsql-sys:initialize-database-type :database-type :oracle))
(handler-case
(sqlite:sqlite-finalize (sqlite-result-set-vm result-set))
(sqlite:sqlite-error (err)
(handler-case
(sqlite:sqlite-finalize (sqlite-result-set-vm result-set))
(sqlite:sqlite-error (err)
- (error 'clsql-simple-error
- :format-control "Error finalizing SQLite VM: ~A"
- :format-arguments (list (sqlite:sqlite-error-message err))))))
+ (error 'sql-database-error
+ :message
+ (format nil "Error finalizing SQLite VM: ~A"
+ (sqlite:sqlite-error-message err))))))
(defmethod database-store-next-row (result-set (database sqlite-database) list)
(let ((n-col (sqlite-result-set-n-col result-set))
(defmethod database-store-next-row (result-set (database sqlite-database) list)
(let ((n-col (sqlite-result-set-n-col result-set))
(return-from database-store-next-row nil)
(setf row new-row)))
(sqlite:sqlite-error (err)
(return-from database-store-next-row nil)
(setf row new-row)))
(sqlite:sqlite-error (err)
- (error 'clsql-simple-error
- :format-control "Error in sqlite-step: ~A"
- :format-arguments
- (list (sqlite:sqlite-error-message err)))))
+ (error 'sql-database-error
+ :message
+ (format nil "Error in sqlite-step: ~A"
+ (sqlite:sqlite-error-message err)))))
- ;; Use the row previously read by database-query-result-set.
+ ;; Use the row previously read by database-query-result-set.
(setf (sqlite-result-set-first-row result-set)
(sqlite:make-null-row)))
(loop for i = 0 then (1+ i)
(setf (sqlite-result-set-first-row result-set)
(sqlite:make-null-row)))
(loop for i = 0 then (1+ i)
:initform nil
:reader sql-error-database))
(:report (lambda (c stream)
:initform nil
:reader sql-error-database))
(:report (lambda (c stream)
- (format stream "A database error occurred: ~A / ~A~% ~A"
+ (format stream "A database error occurred~A: ~A / ~A~% ~A"
(if (sql-error-database c)
(format nil " on database ~A" (sql-error-database c))
"")
(if (sql-error-database c)
(format nil " on database ~A" (sql-error-database c))
"")
(defun signal-no-database-error (database)
(error 'sql-database-error
(defun signal-no-database-error (database)
(error 'sql-database-error
- :message "Not a database: ~A." database))
+ :message (format nil "Not a database: ~A." database)))
(if (or (not errorp) (= count 1))
(values (car matches) count)
(cerror "Return nil."
(if (or (not errorp) (= count 1))
(values (car matches) count)
(cerror "Return nil."
- 'clsql-simple-error
- :format-control "There exists ~A database called ~A."
- :format-arguments
- (list (if (zerop count) "no" "more than one")
- database)))))))
+ 'sql-database-error
+ :message
+ (format nil "There exists ~A database called ~A."
+ (if (zerop count) "no" "more than one")
+ database)))))))
(defun connect (connection-spec
(defun connect (connection-spec
(defgeneric database-get-type-specifier (type args database)
(:documentation "Return the type SQL type specifier as a string, for
(defgeneric database-get-type-specifier (type args database)
(:documentation "Return the type SQL type specifier as a string, for
-the given lisp type and parameters."))
+the given lisp type and parameters.")
+ (:method (type args (database t))
+ (declare (ignore type args))
+ (signal-no-database-error database)))
(defgeneric database-list-tables (database &key owner)
(defgeneric database-list-tables (database &key owner)
- (:documentation "List all tables in the given database"))
+ (:documentation "List all tables in the given database")
+ (:method ((database t) &key owner)
+ (declare (ignore owner))
+ (signal-no-database-error database)))
(defgeneric database-list-views (database &key owner)
(defgeneric database-list-views (database &key owner)
- (:documentation "List all views in the DATABASE."))
+ (:documentation "List all views in the DATABASE.")
+ (:method ((database t) &key owner)
+ (declare (ignore owner))
+ (signal-no-database-error database)))
(defgeneric database-list-indexes (database &key owner)
(defgeneric database-list-indexes (database &key owner)
- (:documentation "List all indexes in the DATABASE."))
+ (:documentation "List all indexes in the DATABASE.")
+ (:method ((database t) &key owner)
+ (declare (ignore owner))
+ (signal-no-database-error database)))
(defgeneric database-list-table-indexes (table database &key owner)
(defgeneric database-list-table-indexes (table database &key owner)
- (:documentation "List all indexes for a table in the DATABASE."))
+ (:documentation "List all indexes for a table in the DATABASE.")
+ (:method (table (database t) &key owner)
+ (declare (ignore table owner))
+ (signal-no-database-error database)))
(defgeneric database-list-attributes (table database &key owner)
(defgeneric database-list-attributes (table database &key owner)
- (:documentation "List all attributes in TABLE."))
+ (:documentation "List all attributes in TABLE.")
+ (:method (table (database t) &key owner)
+ (declare (ignore table owner))
+ (signal-no-database-error database)))
(defgeneric database-attribute-type (attribute table database &key owner)
(:documentation "Return the type of ATTRIBUTE in TABLE. Returns multiple values
(defgeneric database-attribute-type (attribute table database &key owner)
(:documentation "Return the type of ATTRIBUTE in TABLE. Returns multiple values
-of TYPE_NAME (keyword) PRECISION SCALE NULLABLE."))
+of TYPE_NAME (keyword) PRECISION SCALE NULLABLE.")
+ (:method (attribute table (database t) &key owner)
+ (declare (ignore attribute table owner))
+ (signal-no-database-error database)))
(defgeneric database-add-attribute (table attribute database)
(defgeneric database-add-attribute (table attribute database)
- (:documentation "Add the attribute to the table."))
+ (:documentation "Add the attribute to the table.")
+ (:method (table attribute (database t))
+ (declare (ignore table attribute))
+ (signal-no-database-error database)))
(defgeneric database-rename-attribute (table oldatt newname database)
(defgeneric database-rename-attribute (table oldatt newname database)
- (:documentation "Rename the attribute in the table to NEWNAME."))
+ (:documentation "Rename the attribute in the table to NEWNAME.")
+ (:method (table oldatt newname (database t))
+ (declare (ignore table oldatt newname))
+ (signal-no-database-error database)))
(defgeneric oid (object)
(:documentation "Return the unique ID of a database object."))
(defgeneric oid (object)
(:documentation "Return the unique ID of a database object."))
:operator 'in
:sub-expressions (list (sql-expression :attribute foreign-key)
keys))
:operator 'in
:sub-expressions (list (sql-expression :attribute foreign-key)
keys))
:flatp t)))
(dolist (object objects)
(when (or force-p (not (slot-boundp object slotdef-name)))
:flatp t)))
(dolist (object objects)
(when (or force-p (not (slot-boundp object slotdef-name)))
jcs))
immediate-join-classes)
sel-tables)
jcs))
immediate-join-classes)
sel-tables)
- :test #'tables-equal))))
- (dolist (ob (listify order-by))
+ :test #'tables-equal)))
+ (order-by-slots (mapcar #'(lambda (ob) (if (atom ob) ob (car ob)))
+ (listify order-by))))
+
+
+ (when (and order-by-slots (= 1 (length tables)))
+ ;; Add explicity table name if not specified and only one selected table
+ (let ((table-name (sql-output (car tables) database)))
+ (loop for i from 0 below (length order-by-slots)
+ do (when (typep (nth i order-by-slots) 'sql-ident-attribute)
+ (unless (slot-value (nth i order-by-slots) 'qualifier)
+ (setf (slot-value (nth i order-by-slots) 'qualifier) table-name))))))
+
+ (dolist (ob order-by-slots)
(when (and ob (not (member ob (mapcar #'cdr fullsels)
:test #'ref-equal)))
(setq fullsels
(when (and ob (not (member ob (mapcar #'cdr fullsels)
:test #'ref-equal)))
(setq fullsels
- (append fullsels (mapcar #'(lambda (att) (cons nil att))
- (listify ob))))))
+ (append fullsels (mapcar #'(lambda (att) (cons nil att))
+ order-by-slots)))))
(dolist (ob (listify distinct))
(when (and (typep ob 'sql-ident)
(not (member ob (mapcar #'cdr fullsels)
(dolist (ob (listify distinct))
(when (and (typep ob 'sql-ident)
(not (member ob (mapcar #'cdr fullsels)
(cond
((select-objects target-args)
(let ((caching (getf qualifier-args :caching t))
(cond
((select-objects target-args)
(let ((caching (getf qualifier-args :caching t))
+ (result-types (getf qualifier-args :result-types :auto))
(refresh (getf qualifier-args :refresh nil))
(database (or (getf qualifier-args :database) *default-database*)))
(remf qualifier-args :caching)
(remf qualifier-args :refresh)
(refresh (getf qualifier-args :refresh nil))
(database (or (getf qualifier-args :database) *default-database*)))
(remf qualifier-args :caching)
(remf qualifier-args :refresh)
+ (remf qualifier-args :result-types)
- (apply #'find-all target-args qualifier-args))
+ (apply #'find-all target-args
+ (append qualifier-args (list :result-types result-types))))
(t
(let ((cached (records-cache-results target-args qualifier-args database)))
(cond
((and cached (not refresh))
cached)
((and cached refresh)
(t
(let ((cached (records-cache-results target-args qualifier-args database)))
(cond
((and cached (not refresh))
cached)
((and cached refresh)
- (let ((results (apply #'find-all (append (list target-args) qualifier-args `(:instances ,cached)))))
+ (let ((results (apply #'find-all (append (list target-args) qualifier-args `(:instances ,cached :result-types :auto)))))
(setf (records-cache-results target-args qualifier-args database) results)
results))
(t
(setf (records-cache-results target-args qualifier-args database) results)
results))
(t
- (let ((results (apply #'find-all target-args qualifier-args)))
+ (let ((results (apply #'find-all target-args (append qualifier-args
+ '(:result-types :auto)))))
(setf (records-cache-results target-args qualifier-args database) results)
results))))))))
(t
(setf (records-cache-results target-args qualifier-args database) results)
results))))))))
(t
#:sql-error-database-message
;; CLSQL Extensions
#:sql-error-database-message
;; CLSQL Extensions
#:sql-database-warning
#:sql-warning
#:sql-condition
#:sql-database-warning
#:sql-warning
#:sql-condition
(if (or (null thing)
(eq 'null thing))
"NULL"
(if (or (null thing)
(eq 'null thing))
"NULL"
- (error 'clsql-simple-error
- :format-control
- "No type conversion to SQL for ~A is defined for DB ~A."
- :format-arguments (list (type-of thing) (type-of database)))))
+ (error 'sql-user-error
+ :message
+ (format nil
+ "No type conversion to SQL for ~A is defined for DB ~A."
+ (type-of thing) (type-of database)))))
(defmethod output-sql-hash-key ((arg vector) database)
(defmethod output-sql-hash-key ((arg vector) database)
;; Attribute types are vendor specific so need to test a range
(deftest :fddl/attributes/3
;; Attribute types are vendor specific so need to test a range
(deftest :fddl/attributes/3
- (and (member (clsql:attribute-type [emplid] [employee]) '(:int :integer :int4)) t)
+ (and (member (clsql:attribute-type [emplid] [employee]) '(:int :integer :int4 :number)) t)
t)
(deftest :fddl/attributes/4
t)
(deftest :fddl/attributes/4
*** CLSQL ~A begun at ~A
*** ~A
*** ~A on ~A
*** CLSQL ~A begun at ~A
*** ~A
*** ~A on ~A
-*** Database ~A backend~A.
+*** Database ~:@(~A~) backend~A.
******************************************************************************
"
report-type
******************************************************************************
"
report-type
(clsql:select 'employee :order-by '(([emplid] :asc))
:flatp t))
(mapcar #'(lambda (x) (slot-value x 'emplid))
(clsql:select 'employee :order-by '(([emplid] :asc))
:flatp t))
(mapcar #'(lambda (x) (slot-value x 'emplid))
- (clsql:select 'employee :order-by '(([emplid] :desc))
- :flatp t)))
+ (clsql:select 'employee :order-by '(([emplid] :desc))
+ :flatp t)))
(1 2 3 4 5 6 7 8 9 10)
(10 9 8 7 6 5 4 3 2 1))
(1 2 3 4 5 6 7 8 9 10)
(10 9 8 7 6 5 4 3 2 1))
(deftest :oodm/retrieval/8
(mapcar #'(lambda (ea) (slot-value (slot-value ea 'address) 'street-number))
(deftest :oodm/retrieval/8
(mapcar #'(lambda (ea) (slot-value (slot-value ea 'address) 'street-number))
- (select 'employee-address :flatp t :order-by [aaddressid] :caching nil))
+ (select 'employee-address :flatp t :order-by [ea_join aaddressid] :caching nil))
(10 10 nil nil nil))
(deftest :oodm/retrieval/9
(10 10 nil nil nil))
(deftest :oodm/retrieval/9