From 2359c743fa126e65514454a7996e025f139a8241 Mon Sep 17 00:00:00 2001 From: "Kevin M. Rosenberg" Date: Mon, 1 Apr 2002 05:27:55 +0000 Subject: [PATCH] r1713: *** empty log message *** --- ChangeLog | 3 + clsql-aodbc.system | 2 +- clsql-mysql.system | 5 +- clsql-postgresql-socket.system | 2 +- clsql-postgresql.system | 5 +- clsql-uffi.system | 2 +- clsql.system | 5 +- interfaces/clsql-uffi/Makefile | 28 +- interfaces/mysql/Makefile | 33 +- interfaces/mysql/mysql-loader.cl | 39 +- interfaces/mysql/mysql-usql.cl | 111 +++ interfaces/oracle/Makefile | 6 + interfaces/oracle/README | 74 ++ interfaces/oracle/alien-resources.lisp | 58 ++ interfaces/oracle/alloc.c | 39 + interfaces/oracle/oracle-constants.lisp | 530 +++++++++++++ interfaces/oracle/oracle-loader.lisp | 119 +++ interfaces/oracle/oracle-objects.lisp | 91 +++ interfaces/oracle/oracle-package.lisp | 18 + interfaces/oracle/oracle-sql.lisp | 856 +++++++++++++++++++++ interfaces/oracle/oracle.lisp | 318 ++++++++ interfaces/oracle/system.lisp | 43 ++ interfaces/postgresql/postgresql-loader.cl | 14 +- interfaces/postgresql/postgresql-usql.cl | 109 +++ sql/db-interface.cl | 52 +- sql/package.cl | 22 +- sql/usql.cl | 136 ++++ 27 files changed, 2666 insertions(+), 54 deletions(-) create mode 100644 interfaces/mysql/mysql-usql.cl create mode 100644 interfaces/oracle/Makefile create mode 100644 interfaces/oracle/README create mode 100644 interfaces/oracle/alien-resources.lisp create mode 100644 interfaces/oracle/alloc.c create mode 100644 interfaces/oracle/oracle-constants.lisp create mode 100644 interfaces/oracle/oracle-loader.lisp create mode 100644 interfaces/oracle/oracle-objects.lisp create mode 100644 interfaces/oracle/oracle-package.lisp create mode 100644 interfaces/oracle/oracle-sql.lisp create mode 100644 interfaces/oracle/oracle.lisp create mode 100644 interfaces/oracle/system.lisp create mode 100644 interfaces/postgresql/postgresql-usql.cl create mode 100644 sql/usql.cl diff --git a/ChangeLog b/ChangeLog index 13fa209..101319e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +31 Mar 2002 Kevin Rosenberg (kevin@rosenberg.net) + * Added interface to support USQL high-level rouines + 29 Mar 2002 Kevin Rosenberg (kevin@rosenberg.net) * Separated db-interface and conditions from sql/sql.cl diff --git a/clsql-aodbc.system b/clsql-aodbc.system index a540a70..985a7ca 100644 --- a/clsql-aodbc.system +++ b/clsql-aodbc.system @@ -7,7 +7,7 @@ ;;;; Programmer: Kevin M. Rosenberg ;;;; Date Started: Feb 2002 ;;;; -;;;; $Id: clsql-aodbc.system,v 1.2 2002/03/29 08:23:38 kevin Exp $ +;;;; $Id: clsql-aodbc.system,v 1.3 2002/04/01 05:27:54 kevin Exp $ ;;;; ;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg ;;;; diff --git a/clsql-mysql.system b/clsql-mysql.system index 812b120..e3068e7 100644 --- a/clsql-mysql.system +++ b/clsql-mysql.system @@ -7,7 +7,7 @@ ;;;; Programmer: Kevin M. Rosenberg ;;;; Date Started: Feb 2002 ;;;; -;;;; $Id: clsql-mysql.system,v 1.4 2002/03/27 08:09:25 kevin Exp $ +;;;; $Id: clsql-mysql.system,v 1.5 2002/04/01 05:27:54 kevin Exp $ ;;;; ;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg ;;;; @@ -29,7 +29,8 @@ :components ((:file "mysql-package") (:file "mysql-loader" :depends-on ("mysql-package")) (:file "mysql-api" :depends-on ("mysql-loader")) - (:file "mysql-sql" :depends-on ("mysql-api"))) + (:file "mysql-sql" :depends-on ("mysql-api")) + (:file "mysql-usql" :depends-on ("mysql-sql"))) :depends-on (:uffi :clsql :clsql-uffi) :finally-do (when (clsql-sys:database-type-library-loaded :mysql) diff --git a/clsql-postgresql-socket.system b/clsql-postgresql-socket.system index 7a89a85..dbcb481 100644 --- a/clsql-postgresql-socket.system +++ b/clsql-postgresql-socket.system @@ -7,7 +7,7 @@ ;;;; Programmer: Kevin M. Rosenberg ;;;; Date Started: Feb 2002 ;;;; -;;;; $Id: clsql-postgresql-socket.system,v 1.3 2002/03/29 08:28:14 kevin Exp $ +;;;; $Id: clsql-postgresql-socket.system,v 1.4 2002/04/01 05:27:55 kevin Exp $ ;;;; ;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg ;;;; diff --git a/clsql-postgresql.system b/clsql-postgresql.system index 64874cb..9b1cabd 100644 --- a/clsql-postgresql.system +++ b/clsql-postgresql.system @@ -7,7 +7,7 @@ ;;;; Programmer: Kevin M. Rosenberg ;;;; Date Started: Feb 2002 ;;;; -;;;; $Id: clsql-postgresql.system,v 1.4 2002/03/27 08:09:25 kevin Exp $ +;;;; $Id: clsql-postgresql.system,v 1.5 2002/04/01 05:27:55 kevin Exp $ ;;;; ;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg ;;;; @@ -27,7 +27,8 @@ :components ((:file "postgresql-package") (:file "postgresql-loader" :depends-on ("postgresql-package")) (:file "postgresql-api" :depends-on ("postgresql-loader")) - (:file "postgresql-sql" :depends-on ("postgresql-api"))) + (:file "postgresql-sql" :depends-on ("postgresql-api")) + (:file "postgresql-usql" :depends-on ("postgresql-sql"))) :depends-on (:uffi :clsql :clsql-uffi) :finally-do (when (clsql-sys:database-type-library-loaded :postgresql) diff --git a/clsql-uffi.system b/clsql-uffi.system index 2133f6b..ce012a0 100644 --- a/clsql-uffi.system +++ b/clsql-uffi.system @@ -7,7 +7,7 @@ ;;;; Programmer: Kevin M. Rosenberg ;;;; Date Started: Feb 2002 ;;;; -;;;; $Id: clsql-uffi.system,v 1.1 2002/03/27 08:09:25 kevin Exp $ +;;;; $Id: clsql-uffi.system,v 1.2 2002/04/01 05:27:55 kevin Exp $ ;;;; ;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg ;;;; diff --git a/clsql.system b/clsql.system index 867d69b..41ba9f2 100644 --- a/clsql.system +++ b/clsql.system @@ -7,7 +7,7 @@ ;;;; Programmer: Kevin M. Rosenberg ;;;; Date Started: Feb 2002 ;;;; -;;;; $Id: clsql.system,v 1.4 2002/03/29 08:12:15 kevin Exp $ +;;;; $Id: clsql.system,v 1.5 2002/04/01 05:27:55 kevin Exp $ ;;;; ;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg ;;;; @@ -42,7 +42,8 @@ (:file "db-interface" :depends-on ("conditions")) (:file "sql" :depends-on ("db-interface")) (:file "utils" :depends-on ("package")) - (:file "functional" :depends-on ("sql"))) + (:file "functional" :depends-on ("sql")) + (:file "usql" :depends-on ("sql"))) :depends-on (:cmucl-compat) :finally-do (pushnew :clsql cl:*features*) diff --git a/interfaces/clsql-uffi/Makefile b/interfaces/clsql-uffi/Makefile index 8bc8436..897001d 100644 --- a/interfaces/clsql-uffi/Makefile +++ b/interfaces/clsql-uffi/Makefile @@ -7,7 +7,7 @@ # Programer: Kevin M. Rosenberg # Date Started: Mar 2002 # -# CVS Id: $Id: Makefile,v 1.1 2002/03/27 07:58:42 kevin Exp $ +# CVS Id: $Id: Makefile,v 1.2 2002/04/01 05:27:55 kevin Exp $ # # This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg # @@ -16,6 +16,7 @@ # (http://opensource.franz.com/preamble.html), also known as the LLGPL. ########################################################################### +AR=ar # These variables are correct for GCC # you'll need to modify these for other compilers @@ -32,20 +33,27 @@ SHARED_LD_OPT=-shared # Nothing to configure beyond this point BASE=clsql-uffi -SRC=${BASE}.c -OBJECT=${BASE}.o -LIB=${BASE}.so +SRC=$(BASE).c +OBJECT=$(BASE).o +SHARED=$(BASE).so +STATIC=$(BASE).a -all: ${LIB} +all: $(SHARED) $(STATIC) -${LIB}: ${SRC} - ${CC} ${SHARED_CC_OPT} -c ${SRC} -o ${OBJECT} - ld ${SHARED_LD_OPT} ${OBJECT} -o ${LIB} - @rm ${OBJECT} +$(SHARED): $(SRC) + $(CC) $(SHARED_CC_OPT) -c $(SRC) -o $(OBJECT) + ld $(SHARED_LD_OPT) $(OBJECT) -o $(SHARED) + @rm $(OBJECT) + +$(STATIC): $(SRC) + $(CC) -c $(SRC) -o $(OBJECT) + $(AR) r $(STATIC) $(OBJECT) + @rm $(OBJECT) clean: - rm -f ${LIB} + rm -f $(SHARED) $(STATIC) realclean: clean rm -f *~ + diff --git a/interfaces/mysql/Makefile b/interfaces/mysql/Makefile index 8452ef6..d805efc 100644 --- a/interfaces/mysql/Makefile +++ b/interfaces/mysql/Makefile @@ -7,7 +7,7 @@ # Programer: Kevin M. Rosenberg # Date Started: Mar 2002 # -# CVS Id: $Id: Makefile,v 1.1 2002/03/23 14:04:52 kevin Exp $ +# CVS Id: $Id: Makefile,v 1.2 2002/04/01 05:27:55 kevin Exp $ # # This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg # @@ -16,6 +16,7 @@ # (http://opensource.franz.com/preamble.html), also known as the LLGPL. ########################################################################### +AR=ar # These variables are correct for GCC # you'll need to modify these for other compilers @@ -33,26 +34,32 @@ SHARED_LD_OPT=-shared #MYSQL_DIR=/usr MYSQL_DIR=/opt/mysql -MYSQL_LIB=${MYSQL_DIR}/lib/mysql -MYSQL_LIB_FILE=${MYSQL_LIB}/libmysqlclient.so -MYSQL_INCLUDE=${MYSQL_DIR}/include/mysql +MYSQL_LIB=$(MYSQL_DIR)/lib/mysql +MYSQL_LIB_FILE=$(MYSQL_LIB)/libmysqlclient.so +MYSQL_INCLUDE=$(MYSQL_DIR)/include/mysql # Nothing to configure beyond this point BASE=clsql-mysql -SRC=${BASE}.c -OBJECT=${BASE}.o -LIB=${BASE}.so +SRC=$(BASE).c +OBJECT=$(BASE).o +SHARED=$(BASE).so +STATIC=$(BASE).a -all: ${LIB} +all: $(SHARED) $(STATIC) -${LIB}: ${SRC} ${MYSQL_LIB_FILE} - ${CC} ${SHARED_CC_OPT} -I ${MYSQL_INCLUDE} -c ${SRC} -o ${OBJECT} - ld ${SHARED_LD_OPT} ${OBJECT} ${MYSQL_LIB_FILE} -o ${LIB} - @rm ${OBJECT} +$(SHARED): $(SRC) $(MYSQL_LIB_FILE) + $(CC) $(SHARED_CC_OPT) -I $(MYSQL_INCLUDE) -c $(SRC) -o $(OBJECT) + ld $(SHARED_LD_OPT) $(OBJECT) $(MYSQL_LIB_FILE) -o $(SHARED) + @rm $(OBJECT) + +$(STATIC): $(SRC) $(MYSQL_LIB_FILE) + $(CC) -I $(MYSQL_INCLUDE) -c $(SRC) -o $(OBJECT) + $(AR) r $(STATIC) $(OBJECT) + @rm $(OBJECT) clean: - rm -f ${LIB} + rm -f $(SHARED) $(STATIC) realclean: clean rm -f *~ diff --git a/interfaces/mysql/mysql-loader.cl b/interfaces/mysql/mysql-loader.cl index caa8c55..d12fadd 100644 --- a/interfaces/mysql/mysql-loader.cl +++ b/interfaces/mysql/mysql-loader.cl @@ -7,7 +7,7 @@ ;;;; Programmers: Kevin M. Rosenberg ;;;; Date Started: Feb 2002 ;;;; -;;;; $Id: mysql-loader.cl,v 1.3 2002/03/24 04:37:09 kevin Exp $ +;;;; $Id: mysql-loader.cl,v 1.4 2002/04/01 05:27:55 kevin Exp $ ;;;; ;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg ;;;; @@ -31,7 +31,7 @@ #+(or mswindows win32) "CLSQL:interfaces;mysql;clsql-mysql.dll" )) -(defvar *mysql-library-filename* +(defvar *mysql-library-filename* (cond ((probe-file "/opt/mysql/lib/mysql/libmysqlclient.so") "/opt/mysql/lib/mysql/libmysqlclient.so") @@ -46,6 +46,14 @@ (warn "Can't find MySQL client library to load."))) "Location where the MySQL client library is to be found.") +(defvar *mysql-library-candidate-names* + '("libmysqlclient" "libmysql")) + +(defvar *mysql-library-candidate-directories* + '("/opt/mysql/lib/mysql/" "/usr/local/lib/" "/usr/lib/" "/mysql/lib/opt/")) + +(defvar *mysql-library-candidate-drive-letters* '("C" "D" "E")) + (defvar *mysql-supporting-libraries* '("c") "Used only by CMU. List of library flags needed to be passed to ld to load the MySQL client library succesfully. If this differs at your site, @@ -58,17 +66,22 @@ set to the right path before compiling or loading the system.") *mysql-library-loaded*) (defmethod clsql-sys:database-type-load-foreign ((database-type (eql :mysql))) - (when - (and - (uffi:load-foreign-library *mysql-library-filename* - :module "mysql" - :supporting-libraries - *mysql-supporting-libraries*) - (uffi:load-foreign-library *clsql-mysql-library-filename* - :module "clsql-mysql" - :supporting-libraries - (append *mysql-supporting-libraries*))) - (setq *mysql-library-loaded* t))) + (let ((mysql-path + (uffi:find-foreign-library *mysql-library-candidate-names* + *mysql-library-candidate-directories* + :drive-letters + *mysql-library-candidate-drive-letters*))) + (when + (and + (uffi:load-foreign-library mysql-path + :module "mysql" + :supporting-libraries + *mysql-supporting-libraries*) + (uffi:load-foreign-library *clsql-mysql-library-filename* + :module "clsql-mysql" + :supporting-libraries + (append *mysql-supporting-libraries*))) + (setq *mysql-library-loaded* t)))) (clsql-sys:database-type-load-foreign :mysql) diff --git a/interfaces/mysql/mysql-usql.cl b/interfaces/mysql/mysql-usql.cl new file mode 100644 index 0000000..64e16cb --- /dev/null +++ b/interfaces/mysql/mysql-usql.cl @@ -0,0 +1,111 @@ +;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*- +;;;; ************************************************************************* +;;;; FILE IDENTIFICATION +;;;; +;;;; Name: mysql-usql.cl +;;;; Purpose: MySQL interface functions to support UncommonSQL +;;;; Programmers: Kevin M. Rosenberg and onShore Development Inc +;;;; Date Started: Mar 2002 +;;;; +;;;; $Id: mysql-usql.cl,v 1.1 2002/04/01 05:27:55 kevin Exp $ +;;;; +;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg +;;;; and by onShore Development Inc. +;;;; +;;;; CLSQL users are granted the rights to distribute and use this software +;;;; as governed by the terms of the Lisp Lesser GNU Public License +;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL. +;;;; ************************************************************************* + +(declaim (optimize (debug 3) (speed 3) (safety 1) (compilation-speed 0))) +(in-package :clsql-mysql) + +(defmethod database-list-tables ((database mysql-database) + &key (system-tables nil)) + (declare (ignore system-tables)) + (mapcar #'car (database-query "show tables" database :auto))) + + +(defmethod database-list-attributes (table (database mysql-database)) + (let* ((relname (etypecase table + (clsql::sql-ident + (string-downcase + (symbol-name (slot-value table 'clsql::name)))) + (string table))) + (result + (mapcar #'car + (database-query + (format nil + "SHOW COLUMNS FROM ~A" relname) + database nil)))) + result)) ;; MySQL returns columns in reverse order defined + +(defmethod database-attribute-type (attribute table + (database mysql-database)) + (let* ((relname (etypecase table + (clsql::sql-ident + (string-downcase + (symbol-name (slot-value table 'clsql::name)))) + (string table))) + (result + (mapcar #'cadr + (database-query + (format nil + "SHOW COLUMNS FROM ~A LIKE '~A'" relname attribute) + database nil)))) + (let* ((str (car result)) + (end-str (position #\( str)) + (substr (subseq str 0 end-str))) + (if substr + (intern (string-upcase substr) :keyword) nil)))) + + +(defun %sequence-name-to-table (sequence-name) + (concatenate 'string "_usql_seq_" (sql-escape sequence-name))) + +(defmethod database-create-sequence (sequence-name + (database mysql-database)) + (let ((table-name (%sequence-name-to-table sequence-name))) + (database-execute-command + (concatenate 'string "CREATE TABLE " table-name + " (id int NOT NULL PRIMARY KEY AUTO_INCREMENT)") + database) + (database-execute-command + (concatenate 'string "INSERT INTO " table-name + " VALUES (0)") + database))) + +(defmethod database-drop-sequence (sequence-name + (database mysql-database)) + (database-execute-command + (concatenate 'string "DROP TABLE " (%sequence-name-to-table sequence-name)) + database)) + +(defmethod database-sequence-next (sequence-name (database mysql-database)) + (database-execute-command + (concatenate 'string "UPDATE " (%sequence-name-to-table sequence-name) + " SET id=LAST_INSERT_ID(id+1)") + database) + (mysql:mysql-insert-id (mysql::database-mysql-ptr database))) + +#+ignore +(defmethod database-output-sql ((expr clsql-sys::sql-typecast-exp) + (database mysql-database)) + (with-slots (clsql-sys::modifier clsql-sys::components) + expr + (if clsql-sys::modifier + (progn + (clsql-sys::output-sql clsql-sys::components database) + (write-char #\: sql-sys::*sql-stream*) + (write-char #\: sql-sys::*sql-stream*) + (write-string (symbol-name clsql-sys::modifier) + clsql-sys::*sql-stream*))))) + +#+ignore +(defmethod database-output-sql-as-type ((type (eql 'integer)) val + (database mysql-database)) + ;; typecast it so it uses the indexes + (when val + (make-instance 'clsql-sys::sql-typecast-exp + :modifier 'int8 + :components val))) diff --git a/interfaces/oracle/Makefile b/interfaces/oracle/Makefile new file mode 100644 index 0000000..ce6118b --- /dev/null +++ b/interfaces/oracle/Makefile @@ -0,0 +1,6 @@ +SUBDIRS := + +include ../../Makefile.common + +.PHONY: distclean +distclean: clean diff --git a/interfaces/oracle/README b/interfaces/oracle/README new file mode 100644 index 0000000..3164ad4 --- /dev/null +++ b/interfaces/oracle/README @@ -0,0 +1,74 @@ +This is the header of the cadabra source file. + + +;;;; a CMUCL/OCI implementation of a subset of the DBI interface +;;;; +;;;; The original version of this code was copyright (c) 1999-2000 Cadabra Inc. +;;;; It was placed in the public domain by Cadabra in January 2000. +;;;; +;;;; The implementors of the original version were Winton Davies +;;;; and William Newman . +;;;; The code will be maintained by Winton Davies. + +;;;; known issues: +;;;; * The code will leak C resources if errors occur in the the wrong +;;;; places, since it doesn't wrap its allocation/deallocation +;;;; logic in the necessary EVAL-WHENs to prevent this. (This could be +;;;; easily be an issue for long-running processes which recover from +;;;; database errors instead of simply terminating when they occur. It's +;;;; not an issue for programs which consider database errors so abnormal +;;;; that they die immediately when they encounter one.) +;;;; * Instead of reading Oracle header files automatically, this code +;;;; uses constants, types, and function signatures manually transcribed +;;;; from the Oracle header files. Thus, changes in the header files +;;;; may require manual maintenance of the code. (This version was written +;;;; for Oracle 8.1.5.) +;;;; * various KLUDGEs noted in the code + +;;;; log: +;;;; 6. * moved test suite to separate file +;;;; * removed trailing spaces from all strings returned from database +;;;; * fixed error in LIST-ALL-DATABASE-TABLES interface: DB should be +;;;; a &KEY argument, not an &OPTIONAL argument +;;;; 7. * merged Winton's code to allow the SQL function to ask OCI +;;;; whether an operation returns a table, and not to worry about +;;;; the TYPE keyword argument if no table is returned +;;;; * reduced +N-BUF-ROWS+ from 1000 to reduce probability of +;;;; hitting CMUCL 18b 8Mb-of-C-data limit +;;;; * changed NOT-USED argument of FETCH-ROW to EOF-ERRORP, to +;;;; conform to Allegro interface +;;;; * found apparent bug in OCI (wrong size of value returned for the +;;;; +oci-attr-data-size+ attribute); added workaround +;;;; * found and documented the unnecessariness of "workaround" for +;;;; "WITH-ALIEN not working" (which was actually a conceptual error +;;;; on WHN's part, expecting WITH-ALIEN to work the same way as +;;;; MAKE-ALIEN, not expecting one less level of indirection) +;;;; * cleaned up NULLS-OK-USE-THIS-ERRHP weirdness and inflexibility, +;;;; splitting the one argument into separate NULLS-OK and ERRHP +;;;; arguments +;;;; * added :ERRHP optional arguments to various OERR expressions, +;;;; so that now failures are more likely to generate informative +;;;; error messages instead of just "OCI Error (and no ERRHP +;;;; available to find subcode)" +;;;; 8. * added code to deallocate C resources +;;;; 9. * Added in an extra field for DATE-FORMAT and DATE-FORMAT-LENGTH +;;;; Munged the code for datatype and colsize. Winton Davies. +;;;; 10. * cleaned up remnants of old date-is-fixed-length-field design +;;;; assumption, getting rid of +OCi-date-bytes+ +;;;; * reduced consing in FETCH-ROW and associated functions +;;;; * replaced WARN with IWARN for implementor-only warnings +;;;; 11. * fixed bad (THE (ALIEN (* FLOAT)) B) declaration for +;;;; SQLT_FLT buffers (should be (ALIEN (* DOUBLE)) instead; +;;;; and for some reason fell through the cracks of CMUCL's +;;;; "declarations are assertions" principle) +;;;; * deleted various FIXME notes a la "does this code ever get +;;;; exercised?" and "are these really all the cases we need?" +;;;; * changed the IWARN call to a KLUDGE comment, deleted IWARN +;;;; * tidied up comments +;;;; * changed page breaks from lots-of-semicolons Cadabra style +;;;; to ^L CMUCL style +;;;; * declared DBI-ERROR to be INLINE +;;;; * fixed definition of +oci-htype-env+ +;;;; * reviewed and corrected C resource deallocation code +;;;; 12. * Made load-foreign depend on ORACLE-HOME for more portability. + diff --git a/interfaces/oracle/alien-resources.lisp b/interfaces/oracle/alien-resources.lisp new file mode 100644 index 0000000..f47fc4b --- /dev/null +++ b/interfaces/oracle/alien-resources.lisp @@ -0,0 +1,58 @@ +;;; -*- Mode: Lisp -*- +;;; $Id: alien-resources.lisp,v 1.1 2002/04/01 05:27:55 kevin Exp $ + +;;; MaiSQL --- Common Lisp Interface Layer to SQL Databases +;;; This is copyrighted software. See documentation for terms. +;;; +;;; oracle-sql.lisp --- SQL-Interface implementation for Oracle +;;; +;;; derived from postgresql.lisp + +(in-package :MAISQL-ORACLE) + +(declaim (optimize (speed 3) + (debug 1))) + +(defparameter *alien-resource-hash* (make-hash-table :test #'equal)) + +(defun %get-resource (type sizeof) + (let ((resources (gethash type *alien-resource-hash*))) + (car (member-if + #'(lambda (res) + (and (= (alien-resource-sizeof res) sizeof) + (not (alien-resource-in-use res)))) + resources)))) + +(defun %insert-alien-resource (type res) + (let ((resource (gethash type *alien-resource-hash*))) + (setf (gethash type *alien-resource-hash*) + (cons res (gethash type *alien-resource-hash*))))) + +(defmacro acquire-alien-resource (type &optional size) + `(let ((res (%get-resource ',type ,size))) + (unless res + (setf res (make-alien-resource + :type ',type :sizeof ,size + :buffer (make-alien ,type ,size))) + (%insert-alien-resource ',type res)) + (claim-alien-resource res))) + +(defstruct (alien-resource) + (type (error "Missing TYPE.") + :read-only t) + (sizeof (error "Missing SIZEOF.") + :read-only t) + (buffer (error "Missing BUFFER.") + :read-only t) + (in-use nil :type boolean)) + +(defun free-alien-resource (ares) + (setf (alien-resource-in-use ares) nil) + ares) + +(defun claim-alien-resource (ares) + (setf (alien-resource-in-use ares) t) + ares) + + + diff --git a/interfaces/oracle/alloc.c b/interfaces/oracle/alloc.c new file mode 100644 index 0000000..860c334 --- /dev/null +++ b/interfaces/oracle/alloc.c @@ -0,0 +1,39 @@ +void homtscb_ShutdownCallback() {} + +/* +void ASNAccessConstructedOctet() {} +void ASNAccessElement() {} +void ASNEncodeDER() {} +void ASNOBJECT_IDENTIFIERToOIDValue() {} +void AllocateBuffer() { + printf(0, "Called AllocateBuffer"); +} +void FreeBuffer() { + printf(0, "Called FreeBuffer"); +} + +void X509CompareDN() {} +void X509FreeCertificate() {} +void X509ParseCertificateData() {} + +void PKCSCheckSignature() {} +void nauzaoss() {} +void nnfhboot() {} +void nnfoboot() {} +void nnfotrv1() {} +void nnftboot() {} + + +void ntpini() { + printf(0, "Called ntpini"); +} +void nttini() { + printf(0, "Called ntini"); +} +void ntusini() { + printf(0, "Called ntusini"); +} +void ntzini() { + printf(0, "Called ntzini"); +} +*/ diff --git a/interfaces/oracle/oracle-constants.lisp b/interfaces/oracle/oracle-constants.lisp new file mode 100644 index 0000000..f680d24 --- /dev/null +++ b/interfaces/oracle/oracle-constants.lisp @@ -0,0 +1,530 @@ +;;; -*- Mode: Lisp -*- +;;; $Id: oracle-constants.lisp,v 1.1 2002/04/01 05:27:55 kevin Exp $ + +(in-package :MAISQL-ORACLE) + +(defconstant +oci-default+ #x00) ; default value for parameters and attributes +(defconstant +oci-threaded+ #x01) ; application is in threaded environment +(defconstant +oci-object+ #x02) ; the application is in object environment +(defconstant +oci-non-blocking+ #x04) ; non blocking mode of operation +(defconstant +oci-env-no-mutex+ #x08) ; the environment handle will not be protected by a mutex internally + +;; Handle types + +(defconstant +oci-htype-env+ 1) ; environment handle +(defconstant +oci-htype-error+ 2) ; error handle +(defconstant +oci-htype-svcctx+ 3) ; service handle +(defconstant +oci-htype-stmt+ 4) ; statement handle +(defconstant +oci-htype-bind+ 5) ; bind handle +(defconstant +oci-htype-define+ 6) ; define handle +(defconstant +oci-htype-describe+ 7) ; describe handle +(defconstant +oci-htype-server+ 8) ; server handle +(defconstant +oci-htype-session+ 9) ; authentication handle +(defconstant +oci-htype-trans+ 10) ; transaction handle +(defconstant +oci-htype-complexobject+ 11) ; complex object retrieval handle +(defconstant +oci-htype-security+ 12) ; security handle + +;; Descriptor types + +(defconstant +oci-dtype-lob+ 50) ; lob locator +(defconstant +oci-dtype-snap+ 51) ; snapshot +(defconstant +oci-dtype-rset+ 52) ; result set +(defconstant +oci-dtype-param+ 53) ; parameter descriptor obtained from ocigparm +(defconstant +oci-dtype-rowid+ 54) ; rowid +(defconstant +oci-dtype-complexobjectcomp+ 55) ; complex object retrieval descriptor +(defconstant +oci-dtype-file+ 56) ; File Lob locator +(defconstant +oci-dtype-aqenq-options+ 57) ; enqueue options +(defconstant +oci-dtype-aqdeq-options+ 58) ; dequeue options +(defconstant +oci-dtype-aqmsg-properties+ 59) ; message properties +(defconstant +oci-dtype-aqagent+ 60) ; aq agent + +;; Objectr pointer types + +(defconstant +oci-otype-name+ 1) ; object name +(defconstant +oci-otype-ref+ 2) ; REF to TDO +(defconstant +oci-otype-ptr+ 3) ; PTR to TDO + +;; Attribute types + +(defconstant +oci-attr-fncode+ 1) ; the OCI function code +(defconstant +oci-attr-object+ 2) ; is the environment initialized in object mode +(defconstant +oci-attr-nonblocking-mode+ 3) ; non blocking mode +(defconstant +oci-attr-sqlcode+ 4) ; the SQL verb +(defconstant +oci-attr-env+ 5) ; the environment handle +(defconstant +oci-attr-server+ 6) ; the server handle +(defconstant +oci-attr-session+ 7) ; the user session handle +(defconstant +oci-attr-trans+ 8) ; the transaction handle +(defconstant +oci-attr-row-count+ 9) ; the rows processed so far +(defconstant +oci-attr-sqlfncode+ 10) ; the SQL verb of the statement +(defconstant +oci-attr-prefetch-rows+ 11) ; sets the number of rows to prefetch +(defconstant +oci-attr-nested-prefetch-rows+ 12) ; the prefetch rows of nested table +(defconstant +oci-attr-prefetch-memory+ 13) ; memory limit for rows fetched +(defconstant +oci-attr-nested-prefetch-memory+ 14) ; memory limit for nested rows +(defconstant +oci-attr-char-count+ 15) ; this specifies the bind and define size in characters +(defconstant +oci-attr-pdscl+ 16) ; packed decimal scale +(defconstant +oci-attr-pdfmt+ 17) ; packed decimal format +(defconstant +oci-attr-param-count+ 18) ; number of column in the select list +(defconstant +oci-attr-rowid+ 19) ; the rowid +(defconstant +oci-attr-charset+ 20) ; the character set value +(defconstant +oci-attr-nchar+ 21) ; NCHAR type +(defconstant +oci-attr-username+ 22) ; username attribute +(defconstant +oci-attr-password+ 23) ; password attribute +(defconstant +oci-attr-stmt-type+ 24) ; statement type +(defconstant +oci-attr-internal-name+ 25) ; user friendly global name +(defconstant +oci-attr-external-name+ 26) ; the internal name for global txn +(defconstant +oci-attr-xid+ 27) ; XOPEN defined global transaction id +(defconstant +oci-attr-trans-lock+ 28) ; +(defconstant +oci-attr-trans-name+ 29) ; string to identify a global transaction +(defconstant +oci-attr-heapalloc+ 30) ; memory allocated on the heap +(defconstant +oci-attr-charset-id+ 31) ; Character Set ID +(defconstant +oci-attr-charset-form+ 32) ; Character Set Form +(defconstant +oci-attr-maxdata-size+ 33) ; Maximumsize of data on the server +(defconstant +oci-attr-cache-opt-size+ 34) ; object cache optimal size +(defconstant +oci-attr-cache-max-size+ 35) ; object cache maximum size percentage +(defconstant +oci-attr-pinoption+ 36) ; object cache default pin option +(defconstant +oci-attr-alloc-duration+ 37) ; object cache default allocation duration +(defconstant +oci-attr-pin-duration+ 38) ; object cache default pin duration +(defconstant +oci-attr-fdo+ 39) ; Format Descriptor object attribute +(defconstant +oci-attr-postprocessing-callback+ 40) ; Callback to process outbind data +(defconstant +oci-attr-postprocessing-context+ 41) ; Callback context to process outbind data +(defconstant +oci-attr-rows-returned+ 42) ; Number of rows returned in current iter - for Bind handles +(defconstant +oci-attr-focbk+ 43) ; Failover Callback attribute +(defconstant +oci-attr-in-v8-mode+ 44) ; is the server/service context in V8 mode +(defconstant +oci-attr-lobempty+ 45) ; empty lob ? +(defconstant +oci-attr-sesslang+ 46) ; session language handle + +;; AQ Attribute Types +;; Enqueue Options + +(defconstant +oci-attr-visibility+ 47) ; visibility +(defconstant +oci-attr-relative-msgid+ 48) ; relative message id +(defconstant +oci-attr-sequence-deviation+ 49) ; sequence deviation + +; - Dequeue Options - + ; consumer name +;#define OCI-ATTR-DEQ-MODE 50 +;(defconstant +OCI-ATTR-CONSUMER-NAME 50 + 51) ; dequeue mode +;#define OCI-ATTR-NAVIGATION 52 ; navigation +;#define OCI-ATTR-WAIT 53 ; wait +;#define OCI-ATTR-DEQ-MSGID 54 ; dequeue message id + +; - Message Properties - +(defconstant +OCI-ATTR-PRIORITY+ 55) ; priority +(defconstant +OCI-ATTR-DELAY+ 56) ; delay +(defconstant +OCI-ATTR-EXPIRATION+ 57) ; expiration +(defconstant +OCI-ATTR-CORRELATION+ 58) ; correlation id +(defconstant +OCI-ATTR-ATTEMPTS+ 59) ; # of attempts +(defconstant +OCI-ATTR-RECIPIENT-LIST+ 60) ; recipient list +(defconstant +OCI-ATTR-EXCEPTION-QUEUE+ 61) ; exception queue name +(defconstant +OCI-ATTR-ENQ-TIME+ 62) ; enqueue time (only OCIAttrGet) +(defconstant +OCI-ATTR-MSG-STATE+ 63) ; message state (only OCIAttrGet) + +;; AQ Agent +(defconstant +OCI-ATTR-AGENT-NAME+ 64) ; agent name +(defconstant +OCI-ATTR-AGENT-ADDRESS+ 65) ; agent address +(defconstant +OCI-ATTR-AGENT-PROTOCOL+ 66) ; agent protocol + +;- Server handle - +(defconstant +OCI-ATTR-NATIVE-FDES+ 67) ; native cncxn file desc + +;-Parameter Attribute Types- + +(defconstant +OCI-ATTR-UNK+ 101) ; unknown attribute +(defconstant +OCI-ATTR-NUM-COLS+ 102) ; number of columns +(defconstant +OCI-ATTR-LIST-COLUMNS+ 103) ; parameter of the column list +(defconstant +OCI-ATTR-RDBA+ 104) ; DBA of the segment header +(defconstant +OCI-ATTR-CLUSTERED+ 105) ; whether the table is clustered +(defconstant +OCI-ATTR-PARTITIONED+ 106) ; whether the table is partitioned +(defconstant +OCI-ATTR-INDEX-ONLY+ 107) ; whether the table is index only +(defconstant +OCI-ATTR-LIST-ARGUMENTS+ 108) ; parameter of the argument list +(defconstant +OCI-ATTR-LIST-SUBPROGRAMS+ 109) ; parameter of the subprogram list +(defconstant +OCI-ATTR-REF-TDO+ 110) ; REF to the type descriptor +(defconstant +OCI-ATTR-LINK+ 111) ; the database link name +(defconstant +OCI-ATTR-MIN+ 112) ; minimum value +(defconstant +OCI-ATTR-MAX+ 113) ; maximum value +(defconstant +OCI-ATTR-INCR+ 114) ; increment value +(defconstant +OCI-ATTR-CACHE+ 115) ; number of sequence numbers cached +(defconstant +OCI-ATTR-ORDER+ 116) ; whether the sequence is ordered +(defconstant +OCI-ATTR-HW-MARK+ 117) ; high-water mark +(defconstant +OCI-ATTR-TYPE-SCHEMA+ 118) ; type's schema name +(defconstant +OCI-ATTR-TIMESTAMP+ 119) ; timestamp of the object +(defconstant +OCI-ATTR-NUM-ATTRS+ 120) ; number of sttributes +(defconstant +OCI-ATTR-NUM-PARAMS+ 121) ; number of parameters +(defconstant +OCI-ATTR-OBJID+ 122) ; object id for a table or view +(defconstant +OCI-ATTR-PTYPE+ 123) ; type of info described by +(defconstant +OCI-ATTR-PARAM+ 124) ; parameter descriptor +(defconstant +OCI-ATTR-OVERLOAD-ID+ 125) ; overload ID for funcs and procs +(defconstant +OCI-ATTR-TABLESPACE+ 126) ; table name space +(defconstant +OCI-ATTR-TDO+ 127) ; TDO of a type +(defconstant +OCI-ATTR-PARSE-ERROR-OFFSET+ 128) ; Parse Error offset +;-Credential Types- +(defconstant +OCI-CRED-RDBMS+ 1) ; database username/password +(defconstant +OCI-CRED-EXT+ 2) ; externally provided credentials + +;; Error Return Values- + +(defconstant +oci-continue+ -24200) ; Continue with the body of the OCI function +(defconstant +oci-still-executing+ -3123) ; OCI would block error +(defconstant +oci-invalid-handle+ -2) ; maps to SQL-INVALID-HANDLE +(defconstant +oci-error+ -1) ; maps to SQL-ERROR +(defconstant +oci-success+ 0) ; maps to SQL-SUCCESS of SAG CLI +(defconstant +oci-success-with-info+ 1) ; maps to SQL-SUCCESS-WITH-INFO +(defconstant +oci-need-data+ 99) ; maps to SQL-NEED-DATA +(defconstant +oci-no-data+ 100) ; maps to SQL-NO-DATA + +;; Parsing Syntax Types- + +(defconstant +oci-ntv-syntax+ 1) ; Use what so ever is the native lang of server +(defconstant +oci-v7-syntax+ 2) ; V7 language +(defconstant +oci-v8-syntax+ 3) ; V8 language + +;-Scrollable Cursor Options- + +(defconstant +oci-fetch-next+ #x02) ; next row +(defconstant +oci-fetch-first+ #x04) ; first row of the result set +(defconstant +oci-fetch-last+ #x08) ; the last row of the result set +(defconstant +oci-fetch-prior+ #x10) ; the previous row relative to current +(defconstant +oci-fetch-absolute+ #x20) ; absolute offset from first +(defconstant +oci-fetch-relative+ #x40) ; offset relative to current + +;-Bind and Define Options- + +(defconstant +OCI-SB2-IND-PTR+ #x01) ; unused +(defconstant +OCI-DATA-AT-EXEC+ #x02) ; data at execute time +(defconstant +OCI-DYNAMIC-FETCH+ #x02) ; fetch dynamically +(defconstant +OCI-PIECEWISE+ #x04) ; piecewise DMLs or fetch +;- + +;-Execution Modes- +(defconstant +OCI-BATCH-MODE+ #x01) ; batch the oci statement for execution +(defconstant +OCI-EXACT-FETCH+ #x02) ; fetch the exact rows specified +(defconstant +OCI-KEEP-FETCH-STATE+ #x04) ; unused +(defconstant +OCI-SCROLLABLE-CURSOR+ #x08) ; cursor scrollable +(defconstant +OCI-DESCRIBE-ONLY+ #x10) ; only describe the statement +(defconstant +OCI-COMMIT-ON-SUCCESS+ #x20) ; commit, if successful execution +;- + +;-Authentication Modes- +(defconstant +OCI-MIGRATE+ #x0001) ; migratable auth context +(defconstant +OCI-SYSDBA+ #x0002) ; for SYSDBA authorization +(defconstant +OCI-SYSOPER+ #x0004) ; for SYSOPER authorization +(defconstant +OCI-PRELIM-AUTH+ #x0008) ; for preliminary authorization +;- + +;-Piece Information- +(defconstant +OCI-PARAM-IN+ #x01) ; in parameter +(defconstant +OCI-PARAM-OUT+ #x02) ; out parameter +;- + +;- Transaction Start Flags - +; NOTE: OCI-TRANS-JOIN and OCI-TRANS-NOMIGRATE not supported in 8.0.X +(defconstant +OCI-TRANS-NEW+ #x00000001) ; starts a new transaction branch +(defconstant +OCI-TRANS-JOIN+ #x00000002) ; join an existing transaction +(defconstant +OCI-TRANS-RESUME+ #x00000004) ; resume this transaction +(defconstant +OCI-TRANS-STARTMASK+ #x000000ff) + + +(defconstant +OCI-TRANS-READONLY+ #x00000100) ; starts a readonly transaction +(defconstant +OCI-TRANS-READWRITE+ #x00000200) ; starts a read-write transaction +(defconstant +OCI-TRANS-SERIALIZABLE+ #x00000400) + ; starts a serializable transaction +(defconstant +OCI-TRANS-ISOLMASK+ #x0000ff00) + +(defconstant +OCI-TRANS-LOOSE+ #x00010000) ; a loosely coupled branch +(defconstant +OCI-TRANS-TIGHT+ #x00020000) ; a tightly coupled branch +(defconstant +OCI-TRANS-TYPEMASK+ #x000f0000) ; + +(defconstant +OCI-TRANS-NOMIGRATE+ #x00100000) ; non migratable transaction + +;- + +;- Transaction End Flags - +(defconstant +OCI-TRANS-TWOPHASE+ #x01000000) ; use two phase commit +;- + +;; AQ Constants +;; NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE +;; The following constants must match the PL/SQL dbms-aq constants +;; NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE + +; - Visibility flags - +(defconstant +OCI-ENQ-IMMEDIATE+ 1) ; enqueue is an independent transaction +(defconstant +OCI-ENQ-ON-COMMIT+ 2) ; enqueue is part of current transaction + +; - Dequeue mode flags - +(defconstant +OCI-DEQ-BROWSE+ 1) ; read message without acquiring a lock +(defconstant +OCI-DEQ-LOCKED+ 2) ; read and obtain write lock on message +(defconstant +OCI-DEQ-REMOVE+ 3) ; read the message and delete it + +; - Dequeue navigation flags - +(defconstant +OCI-DEQ-FIRST-MSG+ 1) ; get first message at head of queue +(defconstant +OCI-DEQ-NEXT-MSG+ 3) ; next message that is available +(defconstant +OCI-DEQ-NEXT-TRANSACTION+ 2) ; get first message of next txn group + +; - Message states - +(defconstant +OCI-MSG-WAITING+ 1) ; the message delay has not yet completed +(defconstant +OCI-MSG-READY+ 0) ; the message is ready to be processed +(defconstant +OCI-MSG-PROCESSED+ 2) ; the message has been processed +(defconstant +OCI-MSG-EXPIRED+ 3) ; message has moved to exception queue + +; - Sequence deviation - +(defconstant +OCI-ENQ-BEFORE+ 2) ; enqueue message before another message +(defconstant +OCI-ENQ-TOP+ 3) ; enqueue message before all messages + +; - Visibility flags - +(defconstant +OCI-DEQ-IMMEDIATE+ 1) ; dequeue is an independent transaction +(defconstant +OCI-DEQ-ON-COMMIT+ 2) ; dequeue is part of current transaction + +; - Wait - +(defconstant +OCI-DEQ-WAIT-FOREVER+ -1) ; wait forever if no message available +(defconstant +OCI-DEQ-NO-WAIT+ 0) ; do not wait if no message is available + +; - Delay - +(defconstant +OCI-MSG-NO-DELAY+ 0) ; message is available immediately + +;; Expiration +(defconstant +OCI-MSG-NO-EXPIRATION+ -1) ; message will never expire + +;; Describe Handle Parameter Attributes +;; Attributes common to Columns and Stored Procs + +(defconstant +oci-attr-data-size+ 1) ; maximum size of the data +(defconstant +oci-attr-data-type+ 2) ; the sql type of the column/argument +(defconstant +oci-attr-disp-size+ 3) ; the display size +(defconstant +oci-attr-name+ 4) ; the name of the column/argument +(defconstant +oci-attr-precision+ 5) ; precision if number type +(defconstant +oci-attr-scale+ 6) ; scale if number type +(defconstant +oci-attr-is-null+ 7) ; is it null ? +(defconstant +oci-attr-type-name+ 8) + +;; name of the named data type or a package name for package private types + +(defconstant +OCI-ATTR-SCHEMA-NAME+ 9) ; the schema name +(defconstant +OCI-ATTR-SUB-NAME+ 10) ; type name if package private type +(defconstant +OCI-ATTR-POSITION+ 11) ; relative position of col/arg in the list of cols/args + +; complex object retrieval parameter attributes +(defconstant +OCI-ATTR-COMPLEXOBJECTCOMP-TYPE+ 50) ; +(defconstant +OCI-ATTR-COMPLEXOBJECTCOMP-TYPE-LEVEL+ 51) ; +(defconstant +OCI-ATTR-COMPLEXOBJECT-LEVEL+ 52) ; +(defconstant +OCI-ATTR-COMPLEXOBJECT-COLL-OUTOFLINE+ 53) ; + +; Only Columns +(defconstant +OCI-ATTR-DISP-NAME+ 100) ; the display name + +;; stored procs + +(defconstant +OCI-ATTR-OVERLOAD+ 210) ; is this position overloaded +(defconstant +OCI-ATTR-LEVEL+ 211) ; level for structured types +(defconstant +OCI-ATTR-HAS-DEFAULT+ 212) ; has a default value +(defconstant +OCI-ATTR-IOMODE+ 213) ; in, out inout +(defconstant +OCI-ATTR-RADIX+ 214) ; returns a radix +(defconstant +OCI-ATTR-NUM-ARGS+ 215) ; total number of arguments + +;; named type attributes + +(defconstant +oci-attr-typecode+ 216) ; lobject or collection +(defconstant +oci-attr-collection-typecode+ 217) ; varray or nested table +(defconstant +oci-attr-version+ 218) ; user assigned version +(defconstant +oci-attr-is-incomplete-type+ 219) ; is this an incomplete type +(defconstant +oci-attr-is-system-type+ 220) ; a system type +(defconstant +oci-attr-is-predefined-type+ 221) ; a predefined type +(defconstant +oci-attr-is-transient-type+ 222) ; a transient type +(defconstant +oci-attr-is-system-generated-type+ 223) ; system generated type +(defconstant +oci-attr-has-nested-table+ 224) ; contains nested table attr +(defconstant +oci-attr-has-lob+ 225) ; has a lob attribute +(defconstant +oci-attr-has-file+ 226) ; has a file attribute +(defconstant +oci-attr-collection-element+ 227) ; has a collection attribute +(defconstant +oci-attr-num-type-attrs+ 228) ; number of attribute types +(defconstant +oci-attr-list-type-attrs+ 229) ; list of type attributes +(defconstant +oci-attr-num-type-methods+ 230) ; number of type methods +(defconstant +oci-attr-list-type-methods+ 231) ; list of type methods +(defconstant +oci-attr-map-method+ 232) ; map method of type +(defconstant +oci-attr-order-method+ 233) ; order method of type + +; only collection element +(defconstant +OCI-ATTR-NUM-ELEMS+ 234) ; number of elements + +; only type methods +(defconstant +OCI-ATTR-ENCAPSULATION+ 235) ; encapsulation level +(defconstant +OCI-ATTR-IS-SELFISH+ 236) ; method selfish +(defconstant +OCI-ATTR-IS-VIRTUAL+ 237) ; virtual +(defconstant +OCI-ATTR-IS-INLINE+ 238) ; inline +(defconstant +OCI-ATTR-IS-CONSTANT+ 239) ; constant +(defconstant +OCI-ATTR-HAS-RESULT+ 240) ; has result +(defconstant +OCI-ATTR-IS-CONSTRUCTOR+ 241) ; constructor +(defconstant +OCI-ATTR-IS-DESTRUCTOR+ 242) ; destructor +(defconstant +OCI-ATTR-IS-OPERATOR+ 243) ; operator +(defconstant +OCI-ATTR-IS-MAP+ 244) ; a map method +(defconstant +OCI-ATTR-IS-ORDER+ 245) ; order method +(defconstant +OCI-ATTR-IS-RNDS+ 246) ; read no data state method +(defconstant +OCI-ATTR-IS-RNPS+ 247) ; read no process state +(defconstant +OCI-ATTR-IS-WNDS+ 248) ; write no data state method +(defconstant +OCI-ATTR-IS-WNPS+ 249) ; write no process state + +; describing public objects +(defconstant +OCI-ATTR-DESC-PUBLIC+ 250) ; public object +;- + +;-OCIPasswordChange- +(defconstant +OCI-AUTH+ #x08) ; Change the password but do not login + + +;-Other Constants- +(defconstant +OCI-MAX-FNS+ 100) ; max number of OCI Functions +(defconstant +OCI-SQLSTATE-SIZE+ 5) ; +(defconstant +OCI-ERROR-MAXMSG-SIZE+ 1024) ; max size of an error message +;; (defconstant +OCI-LOBMAXSIZE+ 4MAXVAL) ; maximum lob data size +(defconstant +OCI-ROWID-LEN+ 23) ; +;- + +;- Fail Over Events - +(defconstant +OCI-FO-END+ #x00000001) ; +(defconstant +OCI-FO-ABORT+ #x00000002) ; +(defconstant +OCI-FO-REAUTH+ #x00000004) ; +(defconstant +OCI-FO-BEGIN+ #x00000008) ; +(defconstant +OCI-FO-ERROR+ #x00000010) ; +;- + +;- Fail Over Types - +(defconstant +OCI-FO-NONE+ #x00000001) ; +(defconstant +OCI-FO-SESSION+ #x00000002) ; +(defconstant +OCI-FO-SELECT+ #x00000004) ; +(defconstant +OCI-FO-TXNAL+ #x00000008) ; +;- + +;-Function Codes- +(defconstant +OCI-FNCODE-INITIALIZE+ 1) ; OCIInitialize +(defconstant +OCI-FNCODE-HANDLEALLOC+ 2) ; OCIHandleAlloc +(defconstant +OCI-FNCODE-HANDLEFREE+ 3) ; OCIHandleFree +(defconstant +OCI-FNCODE-DESCRIPTORALLOC+ 4) ; OCIDescriptorAlloc +(defconstant +OCI-FNCODE-DESCRIPTORFREE+ 5) ; OCIDescriptorFree +(defconstant +OCI-FNCODE-ENVINIT+ 6) ; OCIEnvInit +(defconstant +OCI-FNCODE-SERVERATTACH+ 7) ; OCIServerAttach +(defconstant +OCI-FNCODE-SERVERDETACH+ 8) ; OCIServerDetach +; unused 9 +(defconstant +OCI-FNCODE-SESSIONBEGIN+ 10) ; OCISessionBegin +(defconstant +OCI-FNCODE-SESSIONEND+ 11) ; OCISessionEnd +(defconstant +OCI-FNCODE-PASSWORDCHANGE+ 12) ; OCIPasswordChange +(defconstant +OCI-FNCODE-STMTPREPARE+ 13) ; OCIStmtPrepare + ; unused 14- 16 +(defconstant +OCI-FNCODE-BINDDYNAMIC+ 17) ; OCIBindDynamic +(defconstant +OCI-FNCODE-BINDOBJECT+ 18) ; OCIBindObject + ; 19 unused +(defconstant +OCI-FNCODE-BINDARRAYOFSTRUCT+ 20) ; OCIBindArrayOfStruct +(defconstant +OCI-FNCODE-STMTEXECUTE+ 21) ; OCIStmtExecute + ; unused 22-24 +(defconstant +OCI-FNCODE-DEFINEOBJECT+ 25) ; OCIDefineObject +(defconstant +OCI-FNCODE-DEFINEDYNAMIC+ 26) ; OCIDefineDynamic +(defconstant +OCI-FNCODE-DEFINEARRAYOFSTRUCT+ 27) ; OCIDefineArrayOfStruct +(defconstant +OCI-FNCODE-STMTFETCH+ 28) ; OCIStmtFetch +(defconstant +OCI-FNCODE-STMTGETBIND+ 29) ; OCIStmtGetBindInfo + ; 30, 31 unused +(defconstant +OCI-FNCODE-DESCRIBEANY+ 32) ; OCIDescribeAny +(defconstant +OCI-FNCODE-TRANSSTART+ 33) ; OCITransStart +(defconstant +OCI-FNCODE-TRANSDETACH+ 34) ; OCITransDetach +(defconstant +OCI-FNCODE-TRANSCOMMIT+ 35) ; OCITransCommit + ; 36 unused +(defconstant +OCI-FNCODE-ERRORGET+ 37) ; OCIErrorGet +(defconstant +OCI-FNCODE-LOBOPENFILE+ 38) ; OCILobFileOpen +(defconstant +OCI-FNCODE-LOBCLOSEFILE+ 39) ; OCILobFileClose + ; 40 was LOBCREATEFILE, unused + ; 41 was OCILobFileDelete, unused +(defconstant +OCI-FNCODE-LOBCOPY+ 42) ; OCILobCopy +(defconstant +OCI-FNCODE-LOBAPPEND+ 43) ; OCILobAppend +(defconstant +OCI-FNCODE-LOBERASE+ 44) ; OCILobErase +(defconstant +OCI-FNCODE-LOBLENGTH+ 45) ; OCILobGetLength +(defconstant +OCI-FNCODE-LOBTRIM+ 46) ; OCILobTrim +(defconstant +OCI-FNCODE-LOBREAD+ 47) ; OCILobRead +(defconstant +OCI-FNCODE-LOBWRITE+ 48) ; OCILobWrite + ; 49 unused +(defconstant +OCI-FNCODE-SVCCTXBREAK+ 50) ; OCIBreak +(defconstant +OCI-FNCODE-SERVERVERSION+ 51) ; OCIServerVersion +; unused 52, 53 +(defconstant +OCI-FNCODE-ATTRGET+ 54) ; OCIAttrGet +(defconstant +OCI-FNCODE-ATTRSET+ 55) ; OCIAttrSet +(defconstant +OCI-FNCODE-PARAMSET+ 56) ; OCIParamSet +(defconstant +OCI-FNCODE-PARAMGET+ 57) ; OCIParamGet +(defconstant +OCI-FNCODE-STMTGETPIECEINFO+ 58) ; OCIStmtGetPieceInfo +(defconstant +OCI-FNCODE-LDATOSVCCTX+ 59) ; OCILdaToSvcCtx + ; 60 unused +(defconstant +OCI-FNCODE-STMTSETPIECEINFO+ 61) ; OCIStmtSetPieceInfo +(defconstant +OCI-FNCODE-TRANSFORGET+ 62) ; OCITransForget +(defconstant +OCI-FNCODE-TRANSPREPARE+ 63) ; OCITransPrepare +(defconstant +OCI-FNCODE-TRANSROLLBACK+ 64) ; OCITransRollback +(defconstant +OCI-FNCODE-DEFINEBYPOS+ 65) ; OCIDefineByPos +(defconstant +OCI-FNCODE-BINDBYPOS+ 66) ; OCIBindByPos +(defconstant +OCI-FNCODE-BINDBYNAME+ 67) ; OCIBindByName +(defconstant +OCI-FNCODE-LOBASSIGN+ 68) ; OCILobAssign +(defconstant +OCI-FNCODE-LOBISEQUAL+ 69) ; OCILobIsEqual +(defconstant +OCI-FNCODE-LOBISINIT+ 70) ; OCILobLocatorIsInit +; 71 was lob locator size in beta2 +(defconstant +OCI-FNCODE-LOBENABLEBUFFERING+ 71) ; OCILobEnableBuffering +(defconstant +OCI-FNCODE-LOBCHARSETID+ 72) ; OCILobCharSetID +(defconstant +OCI-FNCODE-LOBCHARSETFORM+ 73) ; OCILobCharSetForm +(defconstant +OCI-FNCODE-LOBFILESETNAME+ 74) ; OCILobFileSetName +(defconstant +OCI-FNCODE-LOBFILEGETNAME+ 75) ; OCILobFileGetName +(defconstant +OCI-FNCODE-LOGON+ 76) ; OCILogon +(defconstant +OCI-FNCODE-LOGOFF+ 77) ; OCILogoff +(defconstant +OCI-FNCODE-LOBDISABLEBUFFERING+ 78) ; OCILobDisableBuffering +(defconstant +OCI-FNCODE-LOBFLUSHBUFFER+ 79) ; OCILobFlushBuffer +(defconstant +OCI-FNCODE-LOBLOADFROMFILE+ 80) ; OCILobLoadFromFile + + +;- + +;- FILE open modes - +(defconstant +OCI-FILE-READONLY+ 1) ; readonly mode open for FILE types +;- + +;- LOB Buffering Flush Flags - +(defconstant +OCI-LOB-BUFFER-FREE+ 1) ; +(defconstant +OCI-LOB-BUFFER-NOFREE+ 2) ; +;- + +;- OCI Statement Types - + +(defconstant +oci-stmt-select+ 1) ; select statement +(defconstant +oci-stmt-update+ 2) ; update statement +(defconstant +oci-stmt-delete+ 3) ; delete statement +(defconstant +oci-stmt-insert+ 4) ; insert statement +(defconstant +oci-stmt-create+ 5) ; create statement +(defconstant +oci-stmt-drop+ 6) ; drop statement +(defconstant +oci-stmt-alter+ 7) ; alter statement +(defconstant +oci-stmt-begin+ 8) ; begin ... (pl/sql statement) +(defconstant +oci-stmt-declare+ 9) ; declare .. (pl/sql statement ) +;- + +;- OCI Parameter Types - +(defconstant +OCI-PTYPE-UNK+ 0) ; unknown +(defconstant +OCI-PTYPE-TABLE+ 1) ; table +(defconstant +OCI-PTYPE-VIEW+ 2) ; view +(defconstant +OCI-PTYPE-PROC+ 3) ; procedure +(defconstant +OCI-PTYPE-FUNC+ 4) ; function +(defconstant +OCI-PTYPE-PKG+ 5) ; package +(defconstant +OCI-PTYPE-TYPE+ 6) ; user-defined type +(defconstant +OCI-PTYPE-SYN+ 7) ; synonym +(defconstant +OCI-PTYPE-SEQ+ 8) ; sequence +(defconstant +OCI-PTYPE-COL+ 9) ; column +(defconstant +OCI-PTYPE-ARG+ 10) ; argument +(defconstant +OCI-PTYPE-LIST+ 11) ; list +(defconstant +OCI-PTYPE-TYPE-ATTR+ 12) ; user-defined type's attribute +(defconstant +OCI-PTYPE-TYPE-COLL+ 13) ; collection type's element +(defconstant +OCI-PTYPE-TYPE-METHOD+ 14) ; user-defined type's method +(defconstant +OCI-PTYPE-TYPE-ARG+ 15) ; user-defined type method's argument +(defconstant +OCI-PTYPE-TYPE-RESULT+ 16) ; user-defined type method's result +;- + +;- OCI List Types - +(defconstant +OCI-LTYPE-UNK+ 0) ; unknown +(defconstant +OCI-LTYPE-COLUMN+ 1) ; column list +(defconstant +OCI-LTYPE-ARG-PROC+ 2) ; procedure argument list +(defconstant +OCI-LTYPE-ARG-FUNC+ 3) ; function argument list +(defconstant +OCI-LTYPE-SUBPRG+ 4) ; subprogram list +(defconstant +OCI-LTYPE-TYPE-ATTR+ 5) ; type attribute +(defconstant +OCI-LTYPE-TYPE-METHOD+ 6) ; type method +(defconstant +OCI-LTYPE-TYPE-ARG-PROC+ 7) ; type method w/o result argument list +(defconstant +OCI-LTYPE-TYPE-ARG-FUNC+ 8) ; type method w/result argument list + +;; typecodes + diff --git a/interfaces/oracle/oracle-loader.lisp b/interfaces/oracle/oracle-loader.lisp new file mode 100644 index 0000000..f3d1791 --- /dev/null +++ b/interfaces/oracle/oracle-loader.lisp @@ -0,0 +1,119 @@ +;;; -*- Mode: Lisp -*- +;;; $Id: oracle-loader.lisp,v 1.1 2002/04/01 05:27:55 kevin Exp $ +;;; +;;; MaiSQL --- Common Lisp Interface Layer to SQL Databases +;;; This is copyrighted software. See documentation for terms. +;;; +;;; oracle-loader.cl --- Foreign Object Loader for Oracle + +(in-package :MAISQL-ORACLE) + +;; Load the foreign library + +(eval-when (:load-toplevel :compile-toplevel) + (defvar *oracle-home* + nil + "The root of the Oracle installation, usually $ORACLE_HOME is set to this.") + (unless *oracle-home* + (setf *oracle-home* + (cdr (assoc ':ORACLE_HOME ext:*environment-list* :test #'eq))))) + +(defparameter *oracle-libs* + '(#-oracle-9i "rdbms/lib/ssdbaed.o" + "rdbms/lib/defopt.o" + #-oracle-9i "rdbms/lib/homts.o" + "lib/nautab.o" + "lib/naeet.o" + "lib/naect.o" + "lib/naedhs.o" + #-oracle-9i"lib/libnsslb8.a" + #+oracle-9i "lib/homts.o" + ) + "Oracle client libraries, relative to ORACLE_HOME.") + +(defun make-oracle-load-path () + (mapcar (lambda (x) + (concatenate 'string *oracle-home* "/" x)) + *oracle-libs*)) + + +; ;(defparameter *oracle-so-libraries* +; ;; `(,(concatenate 'string "-L" *oracle-home* "/lib/") +; '( +; "-lclntsh" +; "-lnetv2" +; "-lnttcp" +; "-lnetwork" +; "-lncr" +; "-lclient" +; "-lvsn" +; "-lcommon" +; "-lgeneric" +; "-lmm" +; "-lnlsrtl3" +; "-lcore4" +; "-lnlsrtl3" +; "-lepc" +; "-ldl" +; "-lm") +; "List of library flags needed to be passed to ld to load the +; Oracle client library succesfully. If this differs at your site, +; set *oracle-so-libraries* to the right path before compiling or +; loading the system.") + + +#-oracle-9i +(defun oracle-libraries () + `(,(concatenate 'string + "-L" *oracle-home* "/lib") + "-lagtsh" +;; "-locijdbc8" + "-lclntsh" + "-lclient8" + "-lvsn8" + "-lcommon8" + "-lskgxp8" + "-lmm" + "-lnls8" + "-lcore8" + "-lgeneric8" + "-ltrace8" + "-ldl" + "-lm")) + +;; "List of library flags needed to be passed to ld to load the +;;Oracle client library succesfully. If this differs at your site, +;;set *oracle-so-libraries* to the right path before compiling or +;;loading the system.") + +#+oracle-9i +(defun oracle-libraries () + `(,(concatenate 'string + "-L" *oracle-home* "/lib") + "-lagent9" + "-lagtsh" +;; "-locijdbc8" + "-lclntsh" + "-lclntst9" + "-lclient9" + "-lvsn9" + "-lcommon9" + "-lskgxp9" + "-lmm" + "-lnls9" + "-lcore9" + "-lgeneric9" + "-ltrace9" + "-ldl" + #+redhat-linux "-L/usr/lib/gcc-lib/i386-redhat-linux/2.96" + "-lgcc" + "-lm")) + +(defmethod database-type-load-foreign ((database-type (eql :oracle))) + (progv '(sys::*dso-linker*) + '("/usr/bin/ld") + (ext:load-foreign (make-oracle-load-path) + :libraries (oracle-libraries)))) + + +(database-type-load-foreign :oracle) diff --git a/interfaces/oracle/oracle-objects.lisp b/interfaces/oracle/oracle-objects.lisp new file mode 100644 index 0000000..14ecad2 --- /dev/null +++ b/interfaces/oracle/oracle-objects.lisp @@ -0,0 +1,91 @@ +(in-package :maisql-oracle) + +(defparameter *oracle-default-varchar2-length* "512") + +(defmethod database-get-type-specifier + (type args (database oracle-database)) + (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)) + "NUMBER(38,0)")) + +(defmethod database-get-type-specifier + ((type (eql 'simple-base-string)) args (database oracle-database)) + (if args + (format nil "VARCHAR2(~A)" (car args)) + (concatenate 'string "VARCHAR2(" *oracle-default-varchar2-length* ")"))) + +(defmethod database-get-type-specifier + ((type (eql 'simple-string)) args (database oracle-database)) + (if args + (format nil "VARCHAR2(~A)" (car args)) + (concatenate 'string "VARCHAR2(" *oracle-default-varchar2-length* ")"))) + +(defmethod database-get-type-specifier + ((type (eql 'string)) args (database oracle-database)) + (if args + (format nil "VARCHAR2(~A)" (car args)) + (concatenate 'string "VARCHAR2(" *oracle-default-varchar2-length* ")")) + "VARCHAR2(512)") + +(defmethod database-get-type-specifier + ((type (eql 'raw-string)) args (database oracle-database)) + (if args + (format nil "VARCHAR2(~A)" (car args)) + (concatenate 'string "VARCHAR2(" *oracle-default-varchar2-length* ")")) + "VARCHAR2(256)") + +(defmethod database-get-type-specifier + ((type (eql 'float)) args (database oracle-database)) + (if args + (format nil "NUMBER(~A,~A)" + (or (first args) 38) (or (second args) 38)) + "NUMBER")) + +(defmethod database-get-type-specifier + ((type (eql 'long-float)) args (database oracle-database)) + (if args + (format nil "NUMBER(~A,~A)" + (or (first args) 38) (or (second args) 38)) + "NUMBER")) + +(defmethod read-sql-value (val type (database oracle-database)) + (declare (ignore type database)) + ;;(format t "value is \"~A\" of type ~A~%" val (type-of val)) + (etypecase val + (string + (read-from-string val)) + (symbol + nil))) + +(defmethod read-sql-value (val (type (eql 'string)) database) + (declare (ignore database)) + val) + +(defmethod read-sql-value + (val (type (eql 'integer)) (database oracle-database)) + (declare (ignore database)) + val) + +(defmethod read-sql-value (val (type (eql 'float)) (database oracle-database)) + val) + +;;; LOCAL-TIME stuff that needs to go into hooks +#+local-time +(defmethod maisql-sys::database-get-type-specifier + ((type (eql 'local-time::local-time)) args (database oracle-database)) + (declare (ignore args)) + "DATE") + +#+local-time +(defmethod maisql-sys::database-get-type-specifier + ((type (eql 'local-time::duration)) + args + (database oracle-database)) + (declare (ignore args)) + "NUMBER(38)") diff --git a/interfaces/oracle/oracle-package.lisp b/interfaces/oracle/oracle-package.lisp new file mode 100644 index 0000000..27a93f3 --- /dev/null +++ b/interfaces/oracle/oracle-package.lisp @@ -0,0 +1,18 @@ +;;; -*- Mode: Lisp -*- +;;; $Id: oracle-package.lisp,v 1.1 2002/04/01 05:27:55 kevin Exp $ +;;; +;;; MaiSQL --- Common Lisp Interface Layer to SQL Databases +;;; This is copyrighted software. See documentation for terms. +;;; +;;; oracle-package.lisp --- Package definition for the Oracle interface +;;; + +(in-package :cl-user) + +(defpackage "MAISQL-ORACLE" + (:nicknames "ORACLE") + (:use "COMMON-LISP" "MAISQL-SYS" "ALIEN" "C-CALL" "SYSTEM") + (:export "ORACLE-DATABASE" + "*ORACLE-SO-LOAD-PATH*" + "*ORACLE-SO-LIBRARIES*") + (:documentation "This is the MaiSQL interface to Oracle.")) diff --git a/interfaces/oracle/oracle-sql.lisp b/interfaces/oracle/oracle-sql.lisp new file mode 100644 index 0000000..30cbbba --- /dev/null +++ b/interfaces/oracle/oracle-sql.lisp @@ -0,0 +1,856 @@ +;;; -*- Mode: Lisp -*- +;;; $Id: oracle-sql.lisp,v 1.1 2002/04/01 05:27:55 kevin Exp $ + +;;; MaiSQL --- Common Lisp Interface Layer to SQL Databases +;;; This is copyrighted software. See documentation for terms. +;;; +;;; oracle-sql.lisp --- SQL-Interface implementation for Oracle +;;; +;;; derived from postgresql.lisp + +(in-package :MAISQL-ORACLE) + +(defmethod database-initialize-database-type + ((database-type (eql :oracle))) + t) + +;;;; KLUDGE: The original prototype of this code was implemented using +;;;; lots of special variables holding MAKE-ALIEN values. When I was +;;;; first converting it to use WITH-ALIEN variables, I was confused +;;;; about the behavior of MAKE-ALIEN and WITH-ALIEN; I thought that +;;;; (MAKE-ALIEN TYPEFOO) returned the same type of object as is bound +;;;; to the name BAR by (WITH-ALIEN ((BAR TYPEFOO)) ..). In fact the +;;;; value returned by MAKE-ALIEN has an extra level of indirection +;;;; relative to the value bound by WITH-ALIEN, i.e. (DEREF +;;;; (MAKE-ALIEN TYPEFOO)) has the same type as the value bound to the +;;;; name BAR by (WITH-ALIEN ((BAR TYPEFOO)) ..). Laboring under my +;;;; misunderstanding, I was unable to use ordinary scalars bound by +;;;; WITH-ALIEN, and I ended up giving up and deciding to work around +;;;; this apparent bug in CMUCL by using 1-element arrays instead. +;;;; This "workaround" for my misunderstanding is obviously unnecessary +;;;; and confusing, but still remains in the code. -- WHN 20000106 + + +;;;; arbitrary parameters, tunable for performance or other reasons + +;;; the number of table rows that we buffer at once when reading a table +;;; +;;; CMUCL has a compiled-in limit on how much C data can be allocated +;;; (through malloc() and friends) at any given time, typically 8 Mb. +;;; Setting this constant to a moderate value should make it less +;;; likely that we'll have to worry about the CMUCL limit. +(defconstant +n-buf-rows+ 200) +;;; the number of characters that we allocate for an error message buffer +(defconstant +errbuf-len+ 512) + +;;; 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 &rest indices) + `(addr (deref ,alien-object ,@indices))) + +;; constants - from OCI? + +(defconstant +var-not-in-list+ 1007) +(defconstant +no-data-found+ 1403) +(defconstant +null-value-returned+ 1405) +(defconstant +field-truncated+ 1406) + +(defconstant SQLT-INT 3) +(defconstant SQLT-STR 5) +(defconstant SQLT-FLT 4) +(defconstant SQLT-DATE 12) + +;;; Note that despite the suggestive class name (and the way that the +;;; *DEFAULT-DATABASE* variable holds an object of this class), a DB +;;; object is not actually a database but is instead a connection to a +;;; database. Thus, there's no obstacle to having any number of DB +;;; objects referring to the same database. + +(defclass oracle-database (database) ; was struct db + ((envhp + :reader envhp + :initarg :envhp + :type (alien (* (* t))) + :documentation + "OCI environment handle") + (errhp + :reader errhp + :initarg :errhp + :type (alien (* (* t))) + :documentation + "OCI error handle") + (svchp + :reader svchp + :initarg :svchp + :type (alien (* (* t))) + :documentation + "OCI service context handle") + (data-source-name + :initarg :dsn + :initform nil + :documentation + "optional data source name (used only for debugging/printing)") + (user + :initarg :user + :reader user + :type string + :documentation + "the \"user\" value given when data source connection was made") + (date-format + :initarg :date-format + :reader date-format + :initform "YYYY-MM-DD HH24:MI:SS\"+00\"") + (date-format-length + :type number + :documentation + "Each database connection can be configured with its own date +output format. In order to extract date strings from output buffers +holding multiple date strings in fixed-width fields, we need to know +the length of that format."))) + + +;;; Handle the messy case of return code=+oci-error+, querying the +;;; system for subcodes and reporting them as appropriate. ERRHP and +;;; NULLS-OK are as in the OERR function. + +(defun handle-oci-error (&key database nulls-ok) + (cond (database + (with-slots (errhp) + database + (with-alien ((errbuf (array char #.+errbuf-len+)) + (errcode (array long 1))) + (setf (deref errbuf 0) 0) ; i.e. init to empty string + (setf (deref errcode 0) 0) + (oci-error-get (deref errhp) 1 "" (c-& errcode 0) (c-& errbuf 0) +errbuf-len+ +oci-htype-error+) + (let ((subcode (deref errcode 0))) + (unless (and nulls-ok (= subcode +null-value-returned+)) + (error 'maisql-sql-error + :database database + :errno subcode + :error (cast (c-& errbuf 0) c-string))))))) + (nulls-ok + (error 'maisql-sql-error + :database database + :error "can't handle NULLS-OK without ERRHP")) + (t + (error 'maisql-sql-error + :database database + :error "OCI Error (and no ERRHP available to find subcode)")))) + +;;; Require an OCI success code. +;;; +;;; (The ordinary OCI error reporting mechanisms uses a fair amount of +;;; machinery (environments and other handles). In order to get to +;;; where we can use these mechanisms, we have to be able to allocate +;;; the machinery. The functions for allocating the machinery can +;;; return errors (e.g. out of memory) but shouldn't. Wrapping this function +;;; around function calls to such have-to-succeed functions enforces +;;; this condition.) + +(defun osucc (code) + (declare (type fixnum code)) + (unless (= code +oci-success+) + (error 'dbi-error + :format-control "unexpected OCI failure, code=~S" + :format-arguments (list code)))) + + +;;; 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 + 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: + +(defun deref-oci-string (arrayptr string-index size) + (declare (type (alien (* char)) arrayptr)) + (declare (type (mod #.+n-buf-rows+) string-index)) + (declare (type (and unsigned-byte fixnum) size)) + (let* ((raw (cast (addr (deref arrayptr (* string-index size))) c-string)) + (trimmed (string-trim " " raw))) + (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 +;; representation + +#+nil +(defvar +oci-date-bytes+ 7) + +;;; Return the INDEXth date in the OCI array, represented as +;;; a Common Lisp "universal time" (i.e. seconds since 1900). + +#+nil +(defun deref-oci-date (arrayptr index) + (oci-date->universal-time (addr (deref arrayptr + (* index +oci-date-bytes+))))) +#+nil +(defun oci-date->universal-time (oci-date) + (declare (type (alien (* char)) oci-date)) + (flet (;; a character from OCI-DATE, interpreted as an unsigned byte + (ub (i) + (declare (type (mod #.+oci-date-bytes+) i)) + (mod (deref oci-date i) 256))) + (let* ((century (* (- (ub 0) 100) 100)) + (year (+ century (- (ub 1) 100))) + (month (ub 2)) + (day (ub 3)) + (hour (1- (ub 4))) + (minute (1- (ub 5))) + (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 list-all-user-database-tables ((db oracle-database)) + (unless db + (setf db sql:*default-database*)) + (values (database-query "select TABLE_NAME from all_catalog + where owner <> 'PUBLIC' and owner <> 'SYSTEM' and owner <> 'SYS'" + db))) + + +(defmethod database-list-tables ((database oracle-database) + &key (system-tables nil)) + (if system-tables + (select [table_name] :from [all_catalog]) + (select [table_name] :from [all_catalog] + :where [and [<> [owner] "PUBLIC"] + [<> [owner] "SYSTEM"] + [<> [owner] "SYS"]] + :flatp t))) + +;; Return a list of all columns in TABLE. +;; +;; The Allegro version of this also returned a second value. + +(defmethod list-all-table-columns (table (db oracle-database)) + (declare (type string table)) + (unless db + (setf db (default-database))) + (let* ((sql-stmt (concatenate + 'simple-string + "select " + "''," + "all_tables.OWNER," + "''," + "user_tab_columns.COLUMN_NAME," + "user_tab_columns.DATA_TYPE from user_tab_columns," + "all_tables where all_tables.table_name = '" table "'" + " and user_tab_columns.table_name = '" table "'")) + (preresult (sql sql-stmt :db db :types :auto))) + ;; PRERESULT is like RESULT except that it has a name instead of + ;; type codes in the fifth column of each row. To fix this, we + ;; destructively modify PRERESULT. + (dolist (preresult-row preresult) + (setf (fifth preresult-row) + (if (find (fifth preresult-row) + #("NUMBER" "DATE") + :test #'string=) + 2 ; numeric + 1))) ; string + preresult)) + +(defmethod database-list-attributes (table (database oracle-database)) + (let* ((relname (etypecase table + (sql-sys::sql-ident + (string-upcase + (symbol-name (slot-value table 'sql-sys::name)))) + (string table)))) + (select [user_tab_columns column_name] + :from [user_tab_columns] + :where [= [user_tab_columns table_name] relname] + :flatp t))) + + + +;; 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. + +;; KLUDGE: This CASE statement is a strong sign that the code would be +;; cleaner if CD were made into an abstract class, we made variant +;; classes for CD-for-column-of-strings, CD-for-column-of-floats, +;; etc., and defined virtual functions to handle operations like +;; get-an-element-from-column. (For a small special purpose module +;; like this, would arguably be overkill, so I'm not going to do it +;; now, but if this code ends up getting more complicated in +;; maintenance, it would become a really good idea.) + +;; Arguably this would be a good place to signal END-OF-FILE, but +;; since the ANSI spec specifically says that END-OF-FILE means a +;; STREAM which has no more data, and QC is not a STREAM, we signal +;; DBI-ERROR instead. + +(defun fetch-row (qc &optional (eof-errorp t) eof-value) + (declare (optimize (speed 3))) + (cond ((zerop (qc-n-from-oci qc)) + (if eof-errorp + (dbi-error "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 (alien-resource-buffer (cd-buffer cd))) + (value + (let ((arb (alien-resource-buffer (cd-indicators cd)))) + (declare (type (alien (* (alien:signed 16))) arb)) + (unless (= (deref arb irow) -1) + (ecase (cd-oci-data-type cd) + (#.SQLT-STR (deref-oci-string b irow (cd-sizeof cd))) + (#.SQLT-FLT (deref (the (alien (* double)) b) irow)) + (#.SQLT-INT (deref (the (alien (* int)) b) irow)) + (#.SQLT-DATE (deref-oci-string b irow (cd-sizeof cd)))))))) + (push value reversed-result))) + (incf (qc-n-to-dbi qc)) + (nreverse reversed-result))))) + +(defun refill-qc-buffers (qc) + (with-slots (errhp) + (qc-db qc) + (setf (qc-n-to-dbi qc) 0) + (cond ((qc-oci-end-seen-p qc) + (setf (qc-n-from-oci qc) 0)) + (t + (let ((oci-code (%oci-stmt-fetch (deref (qc-stmthp qc)) + (deref errhp) + +n-buf-rows+ + +oci-fetch-next+ +oci-default+))) + (ecase oci-code + (#.+oci-success+ (values)) + (#.+oci-no-data+ (setf (qc-oci-end-seen-p qc) t) + (values)) + (#.+oci-error+ (handle-oci-error :database (qc-db qc) + :nulls-ok t)))) + (with-alien ((rowcount (array unsigned-long 1))) + (oci-attr-get (deref (qc-stmthp qc)) +oci-htype-stmt+ + (c-& rowcount 0) nil +oci-attr-row-count+ + (deref errhp)) + (setf (qc-n-from-oci qc) + (- (deref rowcount 0) (qc-total-n-from-oci qc))) + (when (< (qc-n-from-oci qc) +n-buf-rows+) + (setf (qc-oci-end-seen-p qc) t)) + (setf (qc-total-n-from-oci qc) + (deref rowcount 0))))) + (values))) + +;; the guts of the SQL function +;; +;; (like the SQL function, but with the QUERY argument hardwired to T, so +;; that the return value is always a cursor instead of a list) + +;; Is this a SELECT statement? SELECT statements are handled +;; specially by OCIStmtExecute(). (Non-SELECT statements absolutely +;; require a nonzero iteration count, while the ordinary choice for a +;; SELECT statement is a zero iteration count. + +;; SELECT statements are the only statements which return tables. We +;; don't free STMTHP in this case, but instead give it to the new +;; 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) + (with-slots (envhp svchp errhp) + db + (let ((stmthp (make-alien (* t)))) + (with-alien ((stmttype (array unsigned-short 1))) + + (oci-handle-alloc (deref envhp) (c-& stmthp) +oci-htype-stmt+ 0 nil) + (oci-stmt-prepare (deref stmthp) (deref errhp) + sql-stmt-string (length sql-stmt-string) + +oci-ntv-syntax+ +oci-default+ :database db) + (oci-attr-get (deref stmthp) +oci-htype-stmt+ + (c-& stmttype 0) nil +oci-attr-stmt-type+ + (deref errhp) :database db) + (let* ((select-p (= (deref stmttype 0) 1)) + (iters (if select-p 0 1))) + + (oci-stmt-execute (deref svchp) (deref stmthp) (deref errhp) + iters 0 nil nil +oci-default+ :database db) + (cond (select-p + (make-query-cursor db stmthp types)) + (t + (oci-handle-free (deref stmthp) +oci-htype-stmt+) + nil))))))) + + +;; Return a QUERY-CURSOR representing the table returned from the OCI +;; operation done through STMTHP. TYPES is the argument of the same +;; name from the external SQL function, controlling type conversion +;; of the returned arguments. + +(defun make-query-cursor (db stmthp types) + (let ((qc (%make-query-cursor :db db + :stmthp stmthp + :cds (make-query-cursor-cds db stmthp types)))) + (refill-qc-buffers qc) + qc)) + + +;; the hairy part of MAKE-QUERY-CURSOR: Ask OCI for information +;; about table columns, translate the information into a Lisp +;; vector of column descriptors, and return it. + +;; Allegro defines several flavors of type conversion, but this +;; implementation only supports the :AUTO flavor. + +;; A note of explanation: OCI's internal number format uses 21 +;; bytes (42 decimal digits). 2 separate (?) one-byte fields, +;; scale and precision, are used to deduce the nature of these +;; 21 bytes. See pp. 3-10, 3-26, and 6-13 of OCI documentation +;; for more details. + +;; When calling OCI C code to handle the conversion, we have +;; only two numeric types available to pass the return value: +;; double-float and signed-long. It would be possible to +;; bypass the OCI conversion functions and write Lisp code +;; which reads the 21-byte field directly and decodes +;; it. However this is left as an exercise for the reader. :-) + +;; The following table describes the mapping, based on the implicit +;; assumption that C's "signed long" type is a 32-bit integer. +;; +;; Internal Values SQL Type C Return Type +;; =============== ======== ============= +;; Precision > 0 SCALE = -127 FLOAT --> double-float +;; Precision > 0 && <=9 SCALE = 0 INTEGER --> signed-long +;; Precision = 0 || > 9 SCALE = 0 BIG INTEGER --> double-float +;; Precision > 0 SCALE > 0 DECIMAL --> double-float + +;; (OCI uses 1-based indexing here.) + +;; KLUDGE: This should work for all other data types except those +;; which don't actually fit in their fixed-width field (BLOBs and the +;; like). As Winton says, we (Cadabra) don't need to worry much about +;; those, since we can't reason with them, so we don't use them. But +;; for a more general application it'd be good to have a more +;; selective and rigorously correct test here for whether we can +;; actually handle the given DEREF-DTYPE value. -- WHN 20000106 + +;; Note: The OCI documentation doesn't seem to say whether the COLNAME +;; value returned here is a newly-allocated copy which we're +;; responsible for freeing, or a pointer into some system copy which +;; will be freed when the system itself is shut down. But judging +;; from the way that the result is used in the cdemodsa.c example +;; program, it looks like the latter: we should make our own copy of +;; the value, but not try to free it. + +;; WORKAROUND: OCI seems to return ub2 values for the +;; +oci-attr-data-size+ attribute even though its documentation claims +;; that it returns a ub4, and even though the associated "sizep" value +;; is 4, not 2. In order to make the code here work reliably, without +;; having to patch it later if OCI is ever fixed to match its +;; documentation, we pre-zero COLSIZE before making the call into OCI. + +;; To exercise the weird OCI behavior (thereby blowing up the code +;; below, beware!) try setting this value into COLSIZE, calling OCI, +;; then looking at the value in COLSIZE. (setf colsize #x12345678) +;; debugging only + + +(defun make-query-cursor-cds (database stmthp types) + (declare (optimize (speed 3)) + (type oracle-database database) + (type (alien (* (* t))) stmthp)) + (with-slots (errhp) + database + (unless (eq types :auto) + (error "unsupported TYPES value")) + (with-alien ((dtype unsigned-short 1) + (parmdp (* t)) + (precision (unsigned 8)) + (scale (signed 8)) + (colname c-string) + (colnamelen unsigned-long) + (colsize unsigned-long) + (colsizesize unsigned-long) + (defnp (* t))) + (let ((buffer nil) + (sizeof nil)) + (do ((icolumn 0 (1+ icolumn)) + (cds-as-reversed-list nil)) + ((not (eql (oci-param-get (deref stmthp) +oci-htype-stmt+ + (deref errhp) (addr 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 parmdp +oci-dtype-param+ (addr dtype) + nil +oci-attr-data-type+ (deref errhp)) + (case dtype + (#.SQLT-DATE + (setf buffer (acquire-alien-resource char (* 32 +n-buf-rows+))) + (setf sizeof 32 dtype #.SQLT-STR)) + (2 ;; number + ;;(oci-attr-get parmdp +oci-dtype-param+ + ;;(addr precision) nil +oci-attr-precision+ + ;;(deref errhp)) + (oci-attr-get parmdp +oci-dtype-param+ + (addr scale) nil +oci-attr-scale+ + (deref errhp)) + (cond + ((zerop scale) + (setf buffer (acquire-alien-resource signed +n-buf-rows+) + sizeof 4 ;; sizeof(int) + dtype #.SQLT-INT)) + (t + (setf buffer (acquire-alien-resource double-float +n-buf-rows+) + sizeof 8 ;; sizeof(double) + dtype #.SQLT-FLT)))) + (t ; Default to SQL-STR + (setf colsize 0 + dtype #.SQLT-STR) + (oci-attr-get parmdp +oci-dtype-param+ (addr colsize) + (addr colsizesize) +oci-attr-data-size+ + (deref errhp)) + (let ((colsize-including-null (1+ colsize))) + (setf buffer (acquire-alien-resource char (* +n-buf-rows+ colsize-including-null))) + (setf sizeof colsize-including-null)))) + (let ((retcodes (acquire-alien-resource short +n-buf-rows+)) + (indicators (acquire-alien-resource short +n-buf-rows+))) + (push (make-cd :name "col" ;(subseq colname 0 colnamelen) + :sizeof sizeof + :buffer buffer + :oci-data-type dtype + :retcodes retcodes + :indicators indicators) + cds-as-reversed-list) + (oci-define-by-pos (deref stmthp) + (addr defnp) + (deref errhp) + (1+ icolumn) ; OCI 1-based indexing again + (alien-resource-buffer buffer) + sizeof + dtype + (alien-resource-buffer indicators) + nil + (alien-resource-buffer retcodes) + +oci-default+))))))) + +;; Release the resources associated with a QUERY-CURSOR. + +(defun close-query (qc) + (oci-handle-free (deref (qc-stmthp qc)) +oci-htype-stmt+) + (let ((cds (qc-cds qc))) + (dotimes (i (length cds)) + (release-cd-resources (aref cds i)))) + (values)) + + +;; Release the resources associated with a column description. + +(defun release-cd-resources (cd) + (free-alien-resource (cd-buffer cd)) + (free-alien-resource (cd-retcodes cd)) + (free-alien-resource (cd-indicators cd)) + (values)) + + +(defmethod print-object ((db oracle-database) stream) + (print-unreadable-object (db stream :type t :identity t) + (format stream "\"/~a/~a\"" + (slot-value db 'data-source-name) + (slot-value db 'user)))) + + +(defmethod database-name-from-spec (connection-spec (database-type (eql :oracle))) + (check-connection-spec connection-spec database-type (user password dsn)) + (destructuring-bind (user password dsn) + connection-spec + (declare (ignore password)) + (concatenate 'string "/" dsn "/" user))) + + +(defmethod database-connect (connection-spec (database-type (eql :oracle))) + (check-connection-spec connection-spec database-type (user password dsn)) + (destructuring-bind (user password data-source-name) + connection-spec + (let ((envhp (make-alien (* t))) + (errhp (make-alien (* t))) + (svchp (make-alien (* t))) + (srvhp (make-alien (* t)))) + ;; Requests to allocate environments and handles should never + ;; fail in normal operation, and they're done too early to + ;; handle errors very gracefully (since they're part of the + ;; error-handling mechanism themselves) so we just assert they + ;; work. + (setf (deref envhp) nil) + #+oci-8-1-5 + (progn + (oci-env-create (c-& envhp) +oci-default+ nil nil nil nil 0 nil) + (oci-handle-alloc (deref envhp) (c-& errhp) +oci-htype-error+ 0 nil)) + #-oci-8-1-5 + (progn + (oci-initialize +oci-object+ nil nil nil nil) + (ignore-errors (oci-handle-alloc nil (c-& envhp) +oci-htype-env+ 0 nil)) ;no testing return + (oci-env-init (c-& envhp) +oci-default+ 0 nil) + (oci-handle-alloc (deref envhp) (c-& errhp) +oci-htype-error+ 0 nil) + (oci-handle-alloc (deref envhp) (c-& srvhp) +oci-htype-server+ 0 nil) + ;;(osucc (oci-server-attach srvhp errhp nil 0 +oci-default+)) + (oci-handle-alloc (deref envhp) (c-& svchp) +oci-htype-svcctx+ 0 nil) + ;; oci-handle-alloc((dvoid *)encvhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, 0, 0); + #+nil + (oci-attr-set (deref svchp) +oci-htype-svcctx+ (deref srvhp) 0 +oci-attr-server+ errhp) + ) + + #+nil + (format t "Logging in as user '~A' to database ~A~%" + user password data-source-name) + (oci-logon (deref envhp) (deref errhp) (c-& svchp) + user (length user) + password (length password) + data-source-name (length data-source-name)) + (let ((db (make-instance 'oracle-database + :name (database-name-from-spec connection-spec + database-type) + :envhp envhp + :errhp errhp + :db-type :oracle + :svchp svchp + :dsn data-source-name + :user user))) + ;; :date-format-length (1+ (length date-format))))) + (sql:execute-command + (format nil "alter session set NLS_DATE_FORMAT='~A'" + (date-format db)) :database db) + db)))) + + +;; Close a database connection. + +(defmethod database-disconnect ((database oracle-database)) + (osucc (oci-logoff (deref (svchp database)) (deref (errhp database)))) + (osucc (oci-handle-free (deref (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. + t) + +;;; Do the database operation described in SQL-STMT-STRING on database +;;; DB and, if the command is a SELECT, return a representation of the +;;; resulting table. The representation of the table is controlled by the +;;; QUERY argument: +;;; * If QUERY is NIL, the table is returned as a list of rows, with +;;; each row represented by a list. +;;; * If QUERY is non-NIL, the result is returned as a QUERY-CURSOR +;;; suitable for FETCH-ROW and CLOSE-QUERY +;;; The TYPES argument controls the type conversion method used +;;; to construct the table. The Allegro version supports several possible +;;; values for this argument, but we only support :AUTO. + +(defmethod database-query (query-expression (database oracle-database)) + (let ((cursor (sql-stmt-exec query-expression database :types :auto))) + (declare (type (or query-cursor null) cursor)) + (if (null cursor) ; No table was returned. + (values) + (do ((reversed-result nil)) + (nil) + (let* ((eof-value :eof) + (row (fetch-row cursor nil eof-value))) + (when (eq row eof-value) + (close-query cursor) + (return (nreverse reversed-result))) + (push row reversed-result)))))) + + +(defmethod database-create-sequence + (sequence-name (database oracle-database)) + (execute-command + (concatenate 'string "CREATE SEQUENCE " + (sql-escape sequence-name)) + :database database)) + +(defmethod database-drop-sequence + (sequence-name (database oracle-database)) + (execute-command + (concatenate 'string "DROP SEQUENCE " + (sql-escape sequence-name)) + :database database)) + +(defmethod database-sequence-next (sequence-name (database oracle-database)) + (caar + (query + (concatenate 'string "SELECT " + (sql-escape sequence-name) + ".NEXTVAL FROM dual" + ) :database database))) + + +(defmethod database-execute-command + (sql-expression (database oracle-database)) + (database-query sql-expression database) + ;; HACK HACK HACK + (database-query "commit" database) + t) + + +;;; a column descriptor: metadata about the data in a table +(defstruct (cd (:constructor make-cd) + (:print-function print-cd)) + ;; name of this column + (name (error "missing NAME") :type simple-string :read-only t) + ;; the size in bytes of a single element + (sizeof (error "missing SIZE") :type fixnum :read-only t) + ;; an array of +N-BUF-ROWS+ elements in C representation + (buffer (error "Missing BUFFER") + :type alien-resource + :read-only t) + ;; an array of +N-BUF-ROWS+ OCI return codes in C representation. + ;; (There must be one return code for every element of every + ;; row in order to be able to represent nullness.) + (retcodes (error "Missing RETCODES") + :type alien-resource + :read-only t) + (indicators (error "Missing INDICATORS") + :type alien-resource + :read-only t) + ;; the OCI code for the data type of a single element + (oci-data-type (error "missing OCI-DATA-TYPE") + :type fixnum + :read-only t)) + + +(defun print-cd (cd stream depth) + (declare (ignore depth)) + (print-unreadable-object (cd stream :type t) + (format stream + ":NAME ~S :OCI-DATA-TYPE ~S :OCI-DATA-SIZE ~S" + (cd-name cd) + (cd-oci-data-type cd) + (cd-sizeof cd)))) + +;;; the result of a database query: a cursor through a table +(defstruct (oracle-result-set (:print-function print-query-cursor) + (:conc-name "QC-") + (:constructor %make-query-cursor)) + (db (error "missing DB") ; db conn. this table is associated with + :type db + :read-only t) + (stmthp (error "missing STMTHP") ; the statement handle used to create + :type alien ; this table. owned by the QUERY-CURSOR + :read-only t) ; object, deallocated on CLOSE-QUERY + (cds) ; (error "missing CDS") ; column descriptors +; :type (simple-array cd 1) +; :read-only t) + (n-from-oci 0 ; buffered rows: number of rows recv'd + :type (integer 0 #.+n-buf-rows+)) ; from the database on the last read + (n-to-dbi 0 ; number of buffered rows returned, i.e. + :type (integer 0 #.+n-buf-rows+)) ; the index, within the buffered rows, + ; of the next row which hasn't already + ; been returned + (total-n-from-oci 0 ; total number of bytes recv'd from OCI + :type unsigned-byte) ; in all reads + (oci-end-seen-p nil)) ; Have we seen the end of OCI + ; data, i.e. OCI returning + ; less data than we requested? + ; OCI doesn't seem to like us + ; to try to read more data + ; from it after that.. + +(defun print-query-cursor (qc stream depth) + (declare (ignore depth)) + (print-unreadable-object (qc stream :type t :identity t) + (prin1 (qc-db qc) stream))) + + +(defmethod database-query-result-set (query-expression (database oracle-database) &optional full-set) + ) + +(defmethod database-dump-result-set (result-set (database oracle-database)) + ) + +(defmethod database-store-next-row (result-set (database oracle-database) list) + ) + +(defmethod sql-sys::database-start-transaction ((database oracle-database)) + (call-next-method)) + +;;(with-slots (svchp errhp) database +;; (osucc (oci-trans-start (deref svchp) +;; (deref errhp) +;; 60 +;; +oci-trans-new+))) +;; t) + + +(defmethod sql-sys::database-commit-transaction ((database oracle-database)) + (call-next-method) + (with-slots (svchp errhp) database + (osucc (oci-trans-commit (deref svchp) + (deref errhp) + 0))) + t) + +(defmethod sql-sys::database-abort-transaction ((database oracle-database)) + (call-next-method) + (osucc (oci-trans-rollback (deref (svchp database)) + (deref (errhp database)) + 0)) + t) + +(defparameter *constraint-types* + '(("NOT-NULL" . "NOT NULL"))) + +(defmethod database-output-sql ((str string) (database oracle-database)) + (if (and (null (position #\' str)) + (null (position #\\ str))) + (format nil "'~A'" str) + (let* ((l (length str)) + (buf (make-string (+ l 3)))) + (setf (aref buf 0) #\') + (do ((i 0 (incf i)) + (j 1 (incf j))) + ((= i l) (setf (aref buf j) #\')) + (if (= j (- (length buf) 1)) + (setf buf (adjust-array buf (+ (length buf) 1)))) + (cond ((eql (aref str i) #\') + (setf (aref buf j) #\') + (incf j))) + (setf (aref buf j) (aref str i))) + buf))) + + diff --git a/interfaces/oracle/oracle.lisp b/interfaces/oracle/oracle.lisp new file mode 100644 index 0000000..cb95e00 --- /dev/null +++ b/interfaces/oracle/oracle.lisp @@ -0,0 +1,318 @@ +;;; -*- Mode: Lisp -*- +;;; $Id: oracle.lisp,v 1.1 2002/04/01 05:27:55 kevin Exp $ + +;;; MaiSQL --- Common Lisp Interface Layer to SQL Databases +;;; This is copyrighted software. See documentation for terms. +;;; +;;; oracle.lisp --- FFI interface to Oracle on Unix +;;; +;;; The present content of this file is orented specifically towards +;;; Oracle 8.0.5.1 under Linux, linking against libclntsh.so + +(in-package :MAISQL-ORACLE) + +;; + +(defvar *oci-initialized* nil) + +(defvar *oci-env* nil) + + +;; +;; Opaque pointer types +;; + +(def-alien-type oci-env (* t)) + +(def-alien-type oci-server (* t)) + +(def-alien-type oci-error (* t)) + +(def-alien-type oci-svc-ctx (* t)) + +(def-alien-type oci-stmt (* t)) + + +(defvar *oci-handle-types* + '(:error ; error report handle (OCIError) + :service-context ; service context handle (OCISvcCtx) + :statement ; statement (application request) handle (OCIStmt) + :describe ; select list description handle (OCIDescribe) + :server ; server context handle (OCIServer) + :session ; user session handle (OCISession) + :transaction ; transaction context handle (OCITrans) + :complex-object ; complex object retrieval handle (OCIComplexObject) + :security)) ; security handle (OCISecurity) + +(defstruct oci-handle + (type :unknown) + (pointer (make-alien (* t)))) + +(defun oci-init (&key (mode +oci-default+)) + (let ((x (alien-funcall (extern-alien "OCIInitialize" (function int int (* t) (* t) (* t) (* t))) + mode nil nil nil nil))) + (if (= x 0) + (let ((env (make-alien oci-env))) + (setq *oci-initialized* mode) + (let ((x (alien-funcall (extern-alien "OCIEnvInit" (function int (* t) int int (* t))) + env +oci-default+ 0 nil))) + (format t ";; OEI: reutrned ~d~%" x) + (setq *oci-env* env)))))) + +(defun oci-check-return (value) + (if (= value +oci-invalid-handle+) + (error "Invalid Handle"))) + +(defun oci-get-handle (&key type) + (if (null *oci-initialized*) + (oci-init)) + (case type + (:error + (let ((ptr (make-alien (* t)))) + (let ((x (alien-funcall (extern-alien "OCIHandleAlloc" (function int unsigned-int (* t) int int (* t))) + (sap-ref-32 (alien-sap (deref *oci-env*)) 0) + ptr + +oci-default+ + 0 + nil))) + (oci-check-return x) + ptr))) + (:service-context + "OCISvcCtx") + (:statement + "OCIStmt") + (:describe + "OCIDescribe") + (:server + "OCIServer") + (:session + "OCISession") + (:transaction + "OCITrans") + (:complex-object + "OCIComplexObject") + (:security + "OCISecurity") + (t + (error "'~s' is not a valid OCI handle type" type)))) + +(defun oci-environment () + (let ((envhp (oci-handle-alloc :type :env))) + (oci-env-init envhp) + envhp)) + +;;; Check an OCI return code for erroricity and signal a reasonably +;;; informative condition if so. +;;; +;;; ERRHP provides an error handle which can be used to find +;;; subconditions; if it's not provided, subcodes won't be checked. +;;; +;;; NULLS-OK says that a NULL-VALUE-RETURNED subcondition condition is +;;; normal and needn't cause any signal. An error handle is required +;;; to detect this subcondition, so it doesn't make sense to set ERRHP +;;; unless NULLS-OK is set. + +(defmacro def-oci-routine ((c-oci-symbol lisp-oci-fn) c-return &rest c-parms) + (let ((ll (mapcar (lambda (x) (gensym)) c-parms))) + `(let ((%lisp-oci-fn (def-alien-routine (,c-oci-symbol ,(intern (concatenate 'string "%" (symbol-name lisp-oci-fn)))) + ,c-return ,@c-parms))) + (defun ,lisp-oci-fn (,@ll &key database nulls-ok) + (case (funcall %lisp-oci-fn ,@ll) + (#.+oci-success+ + +oci-success+) + (#.+oci-error+ + (handle-oci-error :database database :nulls-ok nulls-ok)) + (#.+oci-no-data+ + (error "OCI No Data Found")) + (#.+oci-success-with-info+ + (error "internal error: unexpected +oci-SUCCESS-WITH-INFO")) + (#.+oci-no-data+ + (error "OCI No Data")) + (#.+oci-invalid-handle+ + (error "OCI Invalid Handle")) + (#.+oci-need-data+ + (error "OCI Need Data")) + (#.+oci-still-executing+ + (error "OCI Still Executing")) + (#.+oci-continue+ + (error "OCI Continue")) + (t + (error "OCI unknown error, code=~A" (values)))))))) + + +(defmacro def-raw-oci-routine + ((c-oci-symbol lisp-oci-fn) c-return &rest c-parms) + (let ((ll (mapcar (lambda (x) (declare (ignore x)) (gensym)) c-parms))) + `(let ((%lisp-oci-fn (def-alien-routine (,c-oci-symbol ,(intern (concatenate 'string "%" (symbol-name lisp-oci-fn)))) + ,c-return ,@c-parms))) + (defun ,lisp-oci-fn (,@ll &key database nulls-ok) + (funcall %lisp-oci-fn ,@ll))))) + + +(def-oci-routine ("OCIInitialize" OCI-INITIALIZE) + int + (mode unsigned-long) ; ub4 + (ctxp (* t)) ; dvoid * + (malocfp (* t)) ; dvoid *(*) + (ralocfp (* t)) ; dvoid *(*) + (mfreefp (* t))) ; void *(*) + + +(def-oci-routine ("OCIEnvInit" OCI-ENV-INIT) + int + (envpp (* t)) ; OCIEnv ** + (mode unsigned-long) ; ub4 + (xtramem-sz unsigned-long) ; size_t + (usermempp (* t))) ; dvoid ** + +#+oci-8-1-5 +(def-oci-routine ("OCIEnvCreate" OCI-ENV-CREATE) + int + (p0 (* t)) + (p1 unsigned-int) + (p2 (* t)) + (p3 (* t)) + (p4 (* t)) + (p5 (* t)) + (p6 unsigned-long) + (p7 (* t))) + +(def-oci-routine ("OCIHandleAlloc" OCI-HANDLE-ALLOC) + int + (parenth (* t)) ; const dvoid * + (hndlpp (* t)) ; dvoid ** + (type unsigned-long) ; ub4 + (xtramem_sz unsigned-long) ; size_t + (usrmempp (* t))) ; dvoid ** + +(def-oci-routine ("OCIServerAttach" OCI-SERVER-ATTACH) + int + (srvhp (* t)) ; oci-server + (errhp (* t)) ; oci-error + (dblink c-string) ; :in + (dblink-len unsigned-long) ; int + (mode unsigned-long)) ; int + + +(def-oci-routine ("OCIHandleFree" OCI-HANDLE-FREE) + int + (p0 (* t)) ;; handle + (p1 unsigned-long)) ;;type + +(def-oci-routine ("OCILogon" OCI-LOGON) + int + (envhp (* t)) ; env + (errhp (* t)) ; err + (svchp (* t)) ; svc + (username c-string) ; username + (uname-len unsigned-long) ; + (passwd c-string) ; passwd + (password-len unsigned-long) ; + (dsn c-string) ; datasource + (dsn-len unsigned-long)) ; + +(def-oci-routine ("OCILogoff" OCI-LOGOFF) + int + (p0 (* t)) ; svc + (p1 (* t))) ; err + +(def-alien-routine ("OCIErrorGet" OCI-ERROR-GET) + void + (p0 (* t)) + (p1 unsigned-long) + (p2 c-string) + (p3 (* long)) + (p4 (* t)) + (p5 unsigned-long) + (p6 unsigned-long)) + +(def-oci-routine ("OCIStmtPrepare" OCI-STMT-PREPARE) + int + (p0 (* t)) + (p1 (* t)) + (p2 c-string) + (p3 unsigned-long) + (p4 unsigned-long) + (p5 unsigned-long)) + +(def-oci-routine ("OCIStmtExecute" OCI-STMT-EXECUTE) + int + (p0 (* t)) + (p1 (* t)) + (p2 (* t)) + (p3 unsigned-long) + (p4 unsigned-long) + (p5 (* t)) + (p6 (* t)) + (p7 unsigned-long)) + +(def-raw-oci-routine ("OCIParamGet" OCI-PARAM-GET) + int + (p0 (* t)) + (p1 unsigned-long) + (p2 (* t)) + (p3 (* t)) + (p4 unsigned-long)) + +(def-oci-routine ("OCIAttrGet" OCI-ATTR-GET) + int + (p0 (* t)) + (p1 unsigned-long) + (p2 (* t)) + (p3 (* unsigned-long)) + (p4 unsigned-long) + (p5 (* t))) + +#+nil +(def-oci-routine ("OCIAttrSet" OCI-ATTR-SET) + int + (trgthndlp (* t)) + (trgthndltyp int :in) + (attributep (* t)) + (size int) + (attrtype int) + (errhp oci-error)) + +(def-oci-routine ("OCIDefineByPos" OCI-DEFINE-BY-POS) + int + (p0 (* t)) + (p1 (* t)) + (p2 (* t)) + (p3 unsigned-long) + (p4 (* t)) + (p5 unsigned-long) + (p6 unsigned-short) + (p7 (* t)) + (p8 (* t)) + (p9 (* t)) + (p10 unsigned-long)) + +(def-oci-routine ("OCIStmtFetch" OCI-STMT-FETCH) + int + (stmthp (* t)) + (errhp (* t)) + (p2 unsigned-long) + (p3 unsigned-short) + (p4 unsigned-long)) + + +(def-oci-routine ("OCITransStart" OCI-TRANS-START) + int + (svchp (* t)) + (errhp (* t)) + (p2 unsigned-short) + (p3 unsigned-short)) + +(def-oci-routine ("OCITransCommit" OCI-TRANS-COMMIT) + int + (svchp (* t)) + (errhp (* t)) + (p2 unsigned-short)) + +(def-oci-routine ("OCITransRollback" OCI-TRANS-ROLLBACK) + int + (svchp (* t)) + (errhp (* t)) + (p2 unsigned-short)) + + diff --git a/interfaces/oracle/system.lisp b/interfaces/oracle/system.lisp new file mode 100644 index 0000000..e74033e --- /dev/null +++ b/interfaces/oracle/system.lisp @@ -0,0 +1,43 @@ +;;; -*- Mode: Lisp -*- +;;;; MaiSQL --- Common Lisp Interface Layer to SQL Databases +;;;; This is copyrighted software. See documentation for terms. +;;;; +;;;; MaiSQL.system --- System definition for UncommonSQL-PostgreSQL +;;;; +;;;; Checkout Tag: $Name: $ +;;;; $Id: system.lisp,v 1.1 2002/04/01 05:27:55 kevin Exp $ + +#+CLISP +(in-package "USER") +#-CLISP +(in-package :CL-USER) + +;;; System definition + +(mk:defsystem "UncommonSQL-Oracle" + :source-pathname "cl-library:uncommonsql;dbms;oracle" + :source-extension "lisp" + :components + ((:file "oracle-package") + (:file "oracle-loader" + :depends-on ("oracle-package")) + (:file "alien-resources" + :depends-on ("oracle-package")) + (:file "oracle-constants" + :depends-on ("oracle-package")) + (:file "oracle" + :depends-on ("oracle-constants" + "oracle-loader")) + (:file "oracle-sql" + :depends-on ("oracle" "alien-resources")) + (:file "oracle-objects" + :depends-on ("oracle-sql")) + ) + :depends-on (:uncommonsql) + ) + +(mk:oos "UncommonSQL-Oracle" :compile) + + + + diff --git a/interfaces/postgresql/postgresql-loader.cl b/interfaces/postgresql/postgresql-loader.cl index f9d6f1c..e57470e 100644 --- a/interfaces/postgresql/postgresql-loader.cl +++ b/interfaces/postgresql/postgresql-loader.cl @@ -7,7 +7,7 @@ ;;;; Programmer: Kevin M. Rosenberg ;;;; Date Started: Feb 2002 ;;;; -;;;; $Id: postgresql-loader.cl,v 1.3 2002/03/24 04:37:09 kevin Exp $ +;;;; $Id: postgresql-loader.cl,v 1.4 2002/04/01 05:27:55 kevin Exp $ ;;;; ;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg ;;;; @@ -49,10 +49,14 @@ set to the right path before compiling or loading the system.") (defmethod clsql-sys:database-type-load-foreign ((database-type (eql :postgresql))) (when - (uffi:load-foreign-library *postgresql-library-filename* - :module "postgresql" - :supporting-libraries - *postgresql-supporting-libraries*) + (uffi:load-foreign-library + (uffi:find-foreign-library + "libpq" + '("/opt/postgresql/lib/" "/usr/local/lib" "usr/lib/" + "/postgresql/lib/")) + :module "postgresql" + :supporting-libraries + *postgresql-supporting-libraries*) (setq *postgresql-library-loaded* t))) (clsql-sys:database-type-load-foreign :postgresql) diff --git a/interfaces/postgresql/postgresql-usql.cl b/interfaces/postgresql/postgresql-usql.cl new file mode 100644 index 0000000..25eb696 --- /dev/null +++ b/interfaces/postgresql/postgresql-usql.cl @@ -0,0 +1,109 @@ +;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*- +;;;; ************************************************************************* +;;;; FILE IDENTIFICATION +;;;; +;;;; Name: postgresql-usql.sql +;;;; Purpose: PostgreSQL interface for USQL routines +;;;; Programmers: Kevin M. Rosenberg and onShore Development Inc +;;;; Date Started: Mar 2002 +;;;; +;;;; $Id: postgresql-usql.cl,v 1.1 2002/04/01 05:27:55 kevin Exp $ +;;;; +;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg +;;;; and by onShore Development Inc. +;;;; +;;;; CLSQL users are granted the rights to distribute and use this software +;;;; as governed by the terms of the Lisp Lesser GNU Public License +;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL. +;;;; ************************************************************************* + +(declaim (optimize (debug 3) (speed 3) (safety 1) (compilation-speed 0))) +(in-package :clsql-postgresql) + +(defmethod database-list-tables ((database postgresql-database) + &key (system-tables nil)) + (let ((res (mapcar #'car (database-query + "SELECT tablename FROM pg_tables" + database nil)))) + (if (not system-tables) + (remove-if #'(lambda (table) + (equal (subseq table 0 3) + "pg_")) res) + res))) + + + +(defmethod database-list-attributes (table (database postgresql-database)) + (let* ((relname (etypecase table + (clsql::sql-ident + (string-downcase + (symbol-name (slot-value table 'clsql::name)))) + (string table))) + (result + (mapcar #'car + (database-query + (format nil + "SELECT attname FROM pg_class,pg_attribute WHERE pg_class.oid=attrelid AND relname='~A'" relname) + database nil)))) + (if result + (reverse + (remove-if #'(lambda (it) (member it '("cmin" + "cmax" + "xmax" + "xmin" + "oid" + "ctid" + ;; kmr -- added tableoid + "tableoid") :test #'equal)) + result))))) + +(defmethod database-attribute-type (attribute table + (database postgresql-database)) + (let ((result + (mapcar #'car + (database-query + (format nil + "SELECT pg_type.typname FROM pg_type,pg_class,pg_attribute WHERE pg_class.oid=pg_attribute.attrelid AND pg_class.relname='~A' AND pg_attribute.attname='~A' AND pg_attribute.atttypid=pg_type.oid" + table attribute) + database nil)))) + (if result + (intern (string-upcase (car result)) :keyword) nil))) + + +(defmethod database-create-sequence (sequence-name + (database postgresql-database)) + (database-execute-command + (concatenate 'string "CREATE SEQUENCE " (sql-escape sequence-name)) database)) + +(defmethod database-drop-sequence (sequence-name + (database postgresql-database)) + (database-execute-command + (concatenate 'string "DROP SEQUENCE " (sql-escape sequence-name)) database)) + +(defmethod database-sequence-next (sequence-name + (database postgresql-database)) + (parse-integer + (caar + (database-query + (concatenate 'string "SELECT NEXTVAL ('" (sql-escape sequence-name) "')") + database nil)))) + +(defmethod database-output-sql ((expr clsql-sys::sql-typecast-exp) + (database postgresql-database)) + (with-slots (clsql-sys::modifier clsql-sys::components) + expr + (if clsql-sys::modifier + (progn + (clsql-sys::output-sql clsql-sys::components database) + (write-char #\: clsql-sys::*sql-stream*) + (write-char #\: clsql-sys::*sql-stream*) + (write-string (symbol-name clsql-sys::modifier) + clsql-sys::*sql-stream*))))) + +(defmethod database-output-sql-as-type ((type (eql 'integer)) val + (database postgresql-database)) + ;; typecast it so it uses the indexes + (when val + (make-instance 'clsql-sys::sql-typecast-exp + :modifier 'int8 + :components val))) diff --git a/sql/db-interface.cl b/sql/db-interface.cl index 499bf8c..0fac5b2 100644 --- a/sql/db-interface.cl +++ b/sql/db-interface.cl @@ -5,13 +5,14 @@ ;;;; Name: db-interface.cl ;;;; Purpose: Generic function definitions for DB interfaces ;;;; Programmers: Kevin M. Rosenberg based on -;;;; Original code by Pierre R. Mai +;;;; Original code by Pierre R. Mai. Additions from +;;;; onShoreD to support UncommonSQL front-end ;;;; Date Started: Feb 2002 ;;;; -;;;; $Id: db-interface.cl,v 1.4 2002/03/29 08:34:44 kevin Exp $ +;;;; $Id: db-interface.cl,v 1.5 2002/04/01 05:27:55 kevin Exp $ ;;;; ;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg -;;;; and Copyright (c) 1999-2001 by Pierre R. Mai +;;;; and Copyright (c) 1999-2001 by Pierre R. Mai, and onShoreD ;;;; ;;;; CLSQL users are granted the rights to distribute and use this software ;;;; as governed by the terms of the Lisp Lesser GNU Public License @@ -113,3 +114,48 @@ function should signal a clsql-sql-error.")) (:documentation "Returns t and stores the next row in the result set in list or returns nil when result-set is finished.")) + + +;; Interfaces to support UncommonSQL + +(defgeneric database-create-sequence (name database) + (:documentation "Create a sequence in DATABASE.")) + +(defgeneric database-drop-sequence (name database) + (:documentation "Drop a sequence from DATABASE.")) + +(defgeneric database-sequence-next (name database) + (:documentation "Increment a sequence in DATABASE.")) + +(defgeneric database-start-transaction (database) + (:documentation "Start a transaction in DATABASE.")) + +(defgeneric database-commit-transaction (database) + (:documentation "Commit current transaction in DATABASE.")) + +(defgeneric database-abort-transaction (database) + (:documentation "Abort current transaction in DATABASE.")) + +(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.")) + +(defgeneric database-list-tables (database &key (system-tables nil)) + (:documentation "List all tables in the given database")) + +(defgeneric database-list-attributes (table database) + (:documentation "List all attributes in TABLE.")) + +(defgeneric database-attribute-type (attribute table database) + (:documentation "Return the type of ATTRIBUTE in TABLE.")) + +(defgeneric database-add-attribute (table attribute database) + (:documentation "Add the attribute to the table.")) + +(defgeneric database-rename-attribute (table oldatt newname database) + (:documentation "Rename the attribute in the table to NEWNAME.")) + +(defgeneric oid (object) + (:documentation "Return the unique ID of a database object.")) + + diff --git a/sql/package.cl b/sql/package.cl index b20450b..989b277 100644 --- a/sql/package.cl +++ b/sql/package.cl @@ -8,7 +8,7 @@ ;;;; Original code by Pierre R. Mai ;;;; Date Started: Feb 2002 ;;;; -;;;; $Id: package.cl,v 1.4 2002/03/27 05:04:19 kevin Exp $ +;;;; $Id: package.cl,v 1.5 2002/04/01 05:27:55 kevin Exp $ ;;;; ;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg ;;;; and Copyright (c) 1999-2001 by Pierre R. Mai @@ -41,6 +41,16 @@ #:database-query-result-set #:database-dump-result-set #:database-store-next-row + + ;; For UncommonSQL support + #:database-list-tables + #:database-list-attributes + #:database-attribute-type + #:database-create-sequence + #:database-drop-sequence + #:database-sequence-next + + #:sql-escape ;; Shared exports for re-export by CLSQL . #1=(#:clsql-condition @@ -101,6 +111,16 @@ #:number-to-sql-string #:float-to-sql-string #:sql-escape-quotes + + ;; For UncommonSQL support + #:sql-ident + #:list-tables + #:list-attributes + #:attribute-type + #:create-sequence + #:drop-sequence + #:sequence-next + )) (:documentation "This is the INTERNAL SQL-Interface package of CLSQL.")) diff --git a/sql/usql.cl b/sql/usql.cl new file mode 100644 index 0000000..5afb663 --- /dev/null +++ b/sql/usql.cl @@ -0,0 +1,136 @@ +;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*- +;;;; ************************************************************************* +;;;; FILE IDENTIFICATION +;;;; +;;;; Name: usql.cl +;;;; Purpose: High-level interface to SQL driver routines needed for +;;;; UncommonSQL +;;;; Programmers: Kevin M. Rosenberg and onShore Development Inc +;;;; Date Started: Mar 2002 +;;;; +;;;; $Id: usql.cl,v 1.1 2002/04/01 05:27:55 kevin Exp $ +;;;; +;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg +;;;; and onShore Development Inc +;;;; +;;;; CLSQL users are granted the rights to distribute and use this software +;;;; as governed by the terms of the Lisp Lesser GNU Public License +;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL. +;;;; ************************************************************************* + + +;;; Minimal high-level routines to enable low-level interface for USQL + +(declaim (optimize (debug 3) (speed 3) (safety 1) (compilation-speed 0))) +(in-package :clsql-sys) + +(defun list-tables (&key (database *default-database*) + (system-tables nil)) + "List all tables in *default-database*, or if the :database keyword arg +is given, the specified database. If the keyword arg :system-tables +is true, then it will not filter out non-user tables. Table names are +given back as a list of strings." + (database-list-tables database :system-tables system-tables)) + + +(defun list-attributes (table &key (database *default-database*)) + "List the attributes of TABLE in *default-database, or if the +:database keyword is given, the specified database. Attributes are +returned as a list of strings." + (database-list-attributes table database)) + +(defun attribute-type (attribute table &key (database *default-database*)) + "Return the field type of the ATTRIBUTE in TABLE. The optional +keyword argument :database specifies the database to query, defaulting +to *default-database*." + (database-attribute-type attribute table database)) + +(defun add-attribute (table attribute &key (database *default-database*)) + "Add the ATTRIBUTE to TABLE. The ATTRIBUTE sepcification must +include a type argument. The optional keyword argument :database +specifies the database to operation on, defaulting to +*default-database*." + (database-add-attribute table attribute database)) + +(defun rename-attribute (table oldatt newname + &key (database *default-database*)) + (error "(rename-attribute ~a ~a ~a ~a) is not implemented" table oldatt newname database)) + + +;; For SQL Identifiers of generic type +(defclass sql-ident (%sql-expression) + ((name + :initarg :name + :initform "NULL")) + (:documentation "An SQL identifer.")) + +(defmethod make-load-form ((sql sql-ident) &optional environment) + (declare (ignore environment)) + (with-slots (name) + sql + `(make-instance 'sql-ident :name ',name))) + + +;; KMR -- change aref to more specific char +(defun sql-escape (identifier) + (let* ((unescaped (etypecase identifier + (symbol (symbol-name identifier)) + (string identifier))) + (escaped (make-string (length unescaped)))) + (dotimes (i (length unescaped)) + (setf (char escaped i) + (cond ((equal (char unescaped i) #\-) + #\_) + ;; ... + (t + (char unescaped i))))) + escaped)) + + +(defun create-sequence (name &key (database *default-database*)) + (database-create-sequence name database)) + +(defun drop-sequence (name &key (database *default-database*)) + (database-drop-sequence name database)) + +(defun sequence-next (name &key (database *default-database*)) + (database-sequence-next name database)) + + +(defclass sql-typecast-exp (sql-value-exp) + () + (:documentation + "An SQL typecast expression.") + ) + + +(defclass sql-value-exp (%sql-expression) + ((modifier + :initarg :modifier + :initform nil) + (components + :initarg :components + :initform nil)) + (:documentation + "An SQL value expression.") + ) + +(defvar +null-string+ "NULL") + +(defvar *sql-stream* nil + "stream which accumulates SQL output") + +(defclass %sql-expression () + ()) + +(defmethod output-sql ((expr %sql-expression) &optional + (database *default-database*)) + (declare (ignore database)) + (write-string +null-string+ *sql-stream*)) + +#+ignore +(defmethod print-object ((self %sql-expression) stream) + (print-unreadable-object + (self stream :type t) + (write-string (sql-output self) stream))) + -- 2.34.1