r1713: *** empty log message ***
authorKevin M. Rosenberg <kevin@rosenberg.net>
Mon, 1 Apr 2002 05:27:55 +0000 (05:27 +0000)
committerKevin M. Rosenberg <kevin@rosenberg.net>
Mon, 1 Apr 2002 05:27:55 +0000 (05:27 +0000)
27 files changed:
ChangeLog
clsql-aodbc.system
clsql-mysql.system
clsql-postgresql-socket.system
clsql-postgresql.system
clsql-uffi.system
clsql.system
interfaces/clsql-uffi/Makefile
interfaces/mysql/Makefile
interfaces/mysql/mysql-loader.cl
interfaces/mysql/mysql-usql.cl [new file with mode: 0644]
interfaces/oracle/Makefile [new file with mode: 0644]
interfaces/oracle/README [new file with mode: 0644]
interfaces/oracle/alien-resources.lisp [new file with mode: 0644]
interfaces/oracle/alloc.c [new file with mode: 0644]
interfaces/oracle/oracle-constants.lisp [new file with mode: 0644]
interfaces/oracle/oracle-loader.lisp [new file with mode: 0644]
interfaces/oracle/oracle-objects.lisp [new file with mode: 0644]
interfaces/oracle/oracle-package.lisp [new file with mode: 0644]
interfaces/oracle/oracle-sql.lisp [new file with mode: 0644]
interfaces/oracle/oracle.lisp [new file with mode: 0644]
interfaces/oracle/system.lisp [new file with mode: 0644]
interfaces/postgresql/postgresql-loader.cl
interfaces/postgresql/postgresql-usql.cl [new file with mode: 0644]
sql/db-interface.cl
sql/package.cl
sql/usql.cl [new file with mode: 0644]

index 13fa2093c069bab245a06af5ed96b26d407e520d..101319e0bbe41393ecaf21d1350acab7216e63d0 100644 (file)
--- 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
 
 29 Mar 2002 Kevin Rosenberg (kevin@rosenberg.net)
        * Separated db-interface and conditions from sql/sql.cl
 
index a540a70e2a47b32d2e34843fb36d9106c080c757..985a7ca7cb4679e20c3b2ed01212071bd0f2a812 100644 (file)
@@ -7,7 +7,7 @@
 ;;;; Programmer:    Kevin M. Rosenberg
 ;;;; Date Started:  Feb 2002
 ;;;;
 ;;;; 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
 ;;;;
 ;;;;
 ;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg
 ;;;;
index 812b1203f4b59778de7dfc3a5916e64e1514cc6c..e3068e71ebe8140fade8d1f6bc43c6fd53b6cefc 100644 (file)
@@ -7,7 +7,7 @@
 ;;;; Programmer:    Kevin M. Rosenberg
 ;;;; Date Started:  Feb 2002
 ;;;;
 ;;;; 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
 ;;;;
 ;;;;
 ;;;; 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"))
     :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)
     :depends-on (:uffi :clsql :clsql-uffi)
     :finally-do
     (when (clsql-sys:database-type-library-loaded :mysql)
index 7a89a856b9d22e7b563df30f86a0f1050e6c862a..dbcb4818393ee500169784d46e16014792ea9cb4 100644 (file)
@@ -7,7 +7,7 @@
 ;;;; Programmer:    Kevin M. Rosenberg
 ;;;; Date Started:  Feb 2002
 ;;;;
 ;;;; 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
 ;;;;
 ;;;;
 ;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg
 ;;;;
index 64874cb2c11e76d9f9dcd5306c02ff52fe35bc11..9b1cabd1a6a0cb8b8fe6bfd1bbbfd526f90c4807 100644 (file)
@@ -7,7 +7,7 @@
 ;;;; Programmer:    Kevin M. Rosenberg
 ;;;; Date Started:  Feb 2002
 ;;;;
 ;;;; 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
 ;;;;
 ;;;;
 ;;;; 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"))
     :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)
     :depends-on (:uffi :clsql :clsql-uffi)
     :finally-do
     (when (clsql-sys:database-type-library-loaded :postgresql)
index 2133f6b0a1120f51ac6223933a326080c40cc923..ce012a075a466dc5f3dee68090c1c8a8e2e452d6 100644 (file)
@@ -7,7 +7,7 @@
 ;;;; Programmer:    Kevin M. Rosenberg
 ;;;; Date Started:  Feb 2002
 ;;;;
 ;;;; 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
 ;;;;
 ;;;;
 ;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg
 ;;;;
index 867d69b9af5e15736c3d296ce45f05e392002f58..41ba9f24991289e7664a766d405233af547a54e2 100644 (file)
@@ -7,7 +7,7 @@
 ;;;; Programmer:    Kevin M. Rosenberg
 ;;;; Date Started:  Feb 2002
 ;;;;
 ;;;; 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
 ;;;;
 ;;;;
 ;;;; 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 "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*)
     :depends-on (:cmucl-compat)
     :finally-do
     (pushnew :clsql cl:*features*)
index 8bc8436c7e9d2ad93e2ea0086fc1798318e30bf3..897001d033ac8e04567fc7d97b1c3d73a9ef354a 100644 (file)
@@ -7,7 +7,7 @@
 #  Programer:    Kevin M. Rosenberg
 #  Date Started: Mar 2002
 #
 #  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
 #
 #
 # 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.
 ###########################################################################
 
 # (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
 
 # 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
 # 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:
 
 clean:
-       rm -f ${LIB}
+       rm -f $(SHARED) $(STATIC)
 
 realclean: clean
        rm -f *~
 
 
 realclean: clean
        rm -f *~
 
+
index 8452ef6a1ff4ad4519742027238f84468b3e3989..d805efc00fcee1dc5ec0457bf30ef3e1688eefed 100644 (file)
@@ -7,7 +7,7 @@
 #  Programer:    Kevin M. Rosenberg
 #  Date Started: Mar 2002
 #
 #  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
 #
 #
 # 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.
 ###########################################################################
 
 # (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
 
 # 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_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
 
 # 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:
 
 clean:
-       rm -f ${LIB}
+       rm -f $(SHARED) $(STATIC)
 
 realclean: clean
        rm -f *~
 
 realclean: clean
        rm -f *~
index caa8c55fa559ba80f6194e4dd62f2bb03f504f50..d12faddb751623f8e32e0d69d325ee00d201fbb6 100644 (file)
@@ -7,7 +7,7 @@
 ;;;; Programmers:   Kevin M. Rosenberg
 ;;;; Date Started:  Feb 2002
 ;;;;
 ;;;; 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
 ;;;;
 ;;;;
 ;;;; 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"
      ))
 
      #+(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")
     (cond
      ((probe-file "/opt/mysql/lib/mysql/libmysqlclient.so")
       "/opt/mysql/lib/mysql/libmysqlclient.so")
       (warn "Can't find MySQL client library to load.")))
   "Location where the MySQL client library is to be found.")
 
       (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,
 (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)))
   *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)
 
 
 (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 (file)
index 0000000..64e16cb
--- /dev/null
@@ -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 (file)
index 0000000..ce6118b
--- /dev/null
@@ -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 (file)
index 0000000..3164ad4
--- /dev/null
@@ -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
+;;;; <wdavies@cadabra.com> and William Newman <william.newman@airmail.net>.
+;;;; 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 (file)
index 0000000..f47fc4b
--- /dev/null
@@ -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 (file)
index 0000000..860c334
--- /dev/null
@@ -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 (file)
index 0000000..f680d24
--- /dev/null
@@ -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 (file)
index 0000000..f3d1791
--- /dev/null
@@ -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 (file)
index 0000000..14ecad2
--- /dev/null
@@ -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 (file)
index 0000000..27a93f3
--- /dev/null
@@ -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 (file)
index 0000000..30cbbba
--- /dev/null
@@ -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 (file)
index 0000000..cb95e00
--- /dev/null
@@ -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 (file)
index 0000000..e74033e
--- /dev/null
@@ -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)
+
+
+
+
index f9d6f1cf85036dc3956520d916c330c89861a649..e57470e6322a64f0661671563da6c3857428eaac 100644 (file)
@@ -7,7 +7,7 @@
 ;;;; Programmer:    Kevin M. Rosenberg
 ;;;; Date Started:  Feb 2002
 ;;;;
 ;;;; 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
 ;;;;
 ;;;;
 ;;;; 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
 (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)
     (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 (file)
index 0000000..25eb696
--- /dev/null
@@ -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)))
index 499bf8cfbd830d23c1883b09f054c6929c46d204..0fac5b28fd69ed0c4347d2519ff58ed416a91b33 100644 (file)
@@ -5,13 +5,14 @@
 ;;;; Name:          db-interface.cl
 ;;;; Purpose:       Generic function definitions for DB interfaces
 ;;;; Programmers:   Kevin M. Rosenberg based on
 ;;;; 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
 ;;;;
 ;;;; 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
 ;;;;
 ;;;; 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
 ;;;;
 ;;;; 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."))
   (: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."))
+
index b20450bf2ca7f462f75a4f18b8bd32654a9b9ae2..989b27731c044ef41c56f47c8ee740ce8cb0caff 100644 (file)
@@ -8,7 +8,7 @@
 ;;;;                Original code by Pierre R. Mai 
 ;;;; Date Started:  Feb 2002
 ;;;;
 ;;;;                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
 ;;;;
 ;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg
 ;;;; and Copyright (c) 1999-2001 by Pierre R. Mai
      #:database-query-result-set
      #:database-dump-result-set
      #:database-store-next-row
      #: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
      ;; Shared exports for re-export by CLSQL
      .
      #1=(#:clsql-condition
         #:number-to-sql-string
         #:float-to-sql-string
         #:sql-escape-quotes
         #: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."))
 
         ))
     (:documentation "This is the INTERNAL SQL-Interface package of CLSQL."))
 
diff --git a/sql/usql.cl b/sql/usql.cl
new file mode 100644 (file)
index 0000000..5afb663
--- /dev/null
@@ -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)))
+