ODBC support for scsh 0.6.x =========================== This directory contains bindings to Unix ODBC libraries, which make it possible to call any ODBC functions from scsh directly. At the moment ODBC support is not part of the scsh distribution, since ODBC support is in an early stage of development -- to put it another way, it's for thrill seekers only! The code is complete, but needs testing. So, please let us know if you find a bug. ODBC supports also lacks some documentation. 1. Building scsh with ODBC support I recommend to use the scsh version from CVS. However, it might work with scsh-releases 0.6.1 or newer to. Be sure to have a ODBC implementation for Unix, like unixODBC or iODBC -- both seem to work fine. Apply the following patch: Index: autogen.sh =================================================================== RCS file: /cvsroot/scsh/scsh-0.6/autogen.sh,v retrieving revision 1.7 diff -u -r1.7 autogen.sh --- autogen.sh 12 Feb 2002 16:26:05 -0000 1.7 +++ autogen.sh 23 Apr 2003 15:23:43 -0000 @@ -2,7 +2,8 @@ autoheader && autoconf && -./configure && +./configure --with-iODBC=/afs/wsi/i386_fbsd46 && +##./configure --with-iODBC=/usr/lib && touch scsh/*.c && touch build/filenames.scm && rm -f scheme48.image cig/cig.image scsh/scsh.image && @@ -12,5 +13,4 @@ make i-know-what-i-am-doing && make c/scheme48.h&& make linker && -make build/initial.image && -make distclean +make build/initial.image Index: configure.in =================================================================== RCS file: /cvsroot/scsh/scsh-0.6/configure.in,v retrieving revision 1.28 diff -u -r1.28 configure.in --- configure.in 16 Apr 2003 12:41:36 -0000 1.28 +++ configure.in 23 Apr 2003 15:23:43 -0000 @@ -373,7 +373,30 @@ AC_SUBST(LIBS) AC_SUBST(TMPDIR) - +AC_ARG_WITH(unixODBC, + [ --with-unixODBC=DIR Support for unixODBC ], + [ with_unixodbc=$withval ], + [ with_unixodbc=no ] + ) +if test "$with_unixodbc" != no; then + odbc_includes="-I$with_unixodbc/include" + odbc_libs="-lodbc -L$with_unixodbc/lib" + AC_SUBST(odbc_includes) + AC_SUBST(odbc_libs) +fi + +AC_ARG_WITH(iODBC, + [ --with-iODBC=DIR Support for iODBC ], + [ with_iodbc=$withval ], + [ with_iodbc=no ] + ) +if test "$with_iodbc" != no; then + odbc_includes="-I$withval/include" + odbc_libs="-liodbc -L$withval/lib" + AC_SUBST(odbc_includes) + AC_SUBST(odbc_libs) +fi + AC_CONFIG_FILES(Makefile scsh/endian.scm scsh-config) AC_CONFIG_COMMANDS([scsh-config+x],[chmod +x scsh-config]) AC_OUTPUT Index: Makefile.in =================================================================== RCS file: /cvsroot/scsh/scsh-0.6/Makefile.in,v retrieving revision 1.61 diff -u -r1.61 Makefile.in --- Makefile.in 10 Mar 2003 12:13:02 -0000 1.61 +++ Makefile.in 23 Apr 2003 15:23:43 -0000 @@ -8,8 +8,8 @@ VPATH = @srcdir@ CC = @CC@ DEFS = @DEFS@ -LIBS = @LIBS@ -CFLAGS = @CFLAGS@ +LIBS = @LIBS@ @odbc_libs@ +CFLAGS = @CFLAGS@ @odbc_includes@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ @@ -47,7 +47,8 @@ # BUILD_RUNNABLE has to be Scheme 48 0.53. This is used for builds directly # out of the CVS repository. # We cannot use Scsh here since -i is not understood. -BUILD_RUNNABLE = /afs/wsi/i386_fbsd32/bin/scheme48 +#BUILD_RUNNABLE = /afs/wsi/ppc_macx55/scheme48-0.53/bin/scheme48 +BUILD_RUNNABLE = /afs/wsi/i386_fbsd32/scheme48-0.53/bin/scheme48 RUNNABLE = scsh MANPAGE = $(RUNNABLE).$(manext) LIB = $(libdir)/$(RUNNABLE) @@ -133,7 +134,7 @@ scsh/userinfo1.o \ scsh/sighandlers1.o \ scsh/libscsh.o \ - scsh/md5.o + scsh/md5.o SCSH_INITIALIZERS = s48_init_syslog s48_init_posix_regexp \ s48_init_userinfo s48_init_sighandlers \ @@ -169,16 +170,23 @@ # External code to include in the VM # After changing any of these you should delete `scheme48vm' and remake it. -EXTERNAL_OBJECTS = $(SOCKET_OBJECTS) $(LOOKUP_OBJECTS) -EXTERNAL_FLAGS = $(SOCKET_FLAGS) +EXTERNAL_OBJECTS = $(SOCKET_OBJECTS) $(LOOKUP_OBJECTS) $(ODBC_OBJECTS) +EXTERNAL_FLAGS = $(SOCKET_FLAGS) $(ODBC_FLAGS) +EXTERNAL_LDFLAGS = $(SOCKET_LD_FLAGS) $(ODBC_LD_FLAGS) EXTERNAL_INITIALIZERS = $(ADDITIONAL_INITIALIZER) $(SOCKET_INITIALIZERS) \ $(LOOKUP_INITIALIZERS) \ $(SCSH_INITIALIZERS) $(SRFI_INITIALIZERS) \ + $(ODBC_INITIALIZERS) \ s48_init_cig # Rules for any external code. +scsh/odbc/odbc.o: scsh/odbc/odbc.h + +ODBC_OBJECTS = scsh/odbc/odbc.o +ODBC_INITIALIZERS = s48_init_odbc + # Socket rules c/unix/socket.o: c/scheme48.h c/fd-io.h c/event.h @@ -837,7 +845,10 @@ scsh/rx/re-high.scm \ scsh/rx/regexp.scm \ scsh/rx/re-low.scm \ - scsh/rx/regress.scm + scsh/rx/regress.scm \ + scsh/odbc/odbc-interfaces.scm \ + scsh/odbc/odbc-packages.scm \ + scsh/odbc/odbc.scm # scsh/dbm.scm db.scm ndbm.scm # jcontrol @@ -861,7 +872,9 @@ $(srcdir)/scsh/rx/packages.scm \ $(srcdir)/scsh/scsh-package.scm \ $(srcdir)/scsh/lib/ccp-pack.scm \ - $(srcdir)/scsh/lib/char-package.scm + $(srcdir)/scsh/lib/char-package.scm \ + $(srcdir)/scsh/odbc/odbc-interfaces.scm \ + $(srcdir)/scsh/odbc/odbc-packages.scm opens = floatnums scsh ccp-lib scsh-top-package scsh-here-string-hax \ srfi-1 srfi-13 srfi-14 # srfi-14 is also exported by scsh This will add some rules to Makefile and add two options to configure: --with-iODBC=PATH and --with-unixODBC=PATH. Now it's time to build scsh. Edit the call to configure in autgen.sh to your needs, e.g.: ./configure --with-iODBC=/usr/local && Don't forget the && at the end of line! Now, run autogen.sh to build the VM and all that stuff. Run make to build scsh. If the build suceeds, tap yourself on the shoulder, that's important, it might the last sense of achievement from now on. 2. Running scsh with ODBC support Type ./scshvm -i scsh/scsh.image -- that's it! 3. How do I use ODBC support? If you installed the odbc-module-patch, simply type ,open odbc. If you have installed dynamic ODBC libraries make sure your system can find them, e.g. put the path in your LD_LIBRARY_PATH. This should look like this: [knauel@jimi scsh-0.6.cvs] ./scshvm -i scsh/scsh.image Welcome to scsh 0.6.3 (Health Reform) Type ,? for help. > ,open odbc Load structure odbc (y/n)? y [odbc ./scsh/odbc/odbc-bindcol.scm ./scsh/odbc/odbc.scm] > ,exit This is an example entry for ~/.odbc.ini: [test] DSN = mysql1 Driver = /afs/informatik.uni-tuebingen.de/pu/src/build/knauel/i386_fbsd43/lib/libmyodbc3.so Server = localhost Port = 3306 User = odbc Password= geheim TraceFile= stderr Trace = on It may be necessary to help your ODBC driver manager to find that file be setting the environment variable ODBCINI. Let's see what data sources are known to the system: (let* ((env-handle (odbc-alloc-environment-handle)) (data-sources (odbc-sql-data-sources env-handle))) (for-each (lambda (pair) (display "data source: ") (display (car pair)) (newline) (display "using driver: ") (display (cdr pair)) (newline)) data-sources)) Don't worry about freeing handles -- this will happen automatically when the scheme variable gets garbage collected. This example shows how you can read the information from ODBC's diag-recs in case an error occurs, which is to happen very likely: (define (display-errors handle) (let ((recs (odbc-sql-get-diag-recs handle))) (if (not (null? recs)) (for-each (lambda (rec) (newline) (display "state: ") (display (odbc-diag-sql-state rec)) (newline) (display "native error: ") (display (odbc-diag-native-error rec)) (newline) (display "message: ") (display (odbc-diag-message rec)) (newline)) recs) (begin (display "No error messages (so far ;-)") (newline))))) Not let's read some stuff from the database! Say we have a database with four columns a through d, where a,b,c are integer columns and d is text. Using the fancy odbc-sql-bindcol functions that's pretty easy: ,open low-odbc ,open low-odbc-constants (define (get-env-handle) (call-with-values odbc-alloc-environment-handle (lambda (status-code env-handle) (if (odbc-call-successful? status-code) env-handle (error "error allocating environment handle"))))) (define (get-conn-handle env-handle) (call-with-values (lambda () (odbc-alloc-connection-handle env-handle)) (lambda (status-code conn-handle) (if (odbc-call-successful? status-code) conn-handle (error "error allocating connection handle"))))) (define (get-stmt-handle conn-handle) (call-with-values (lambda () (odbc-alloc-statement-handle conn-handle)) (lambda (status-code stmt-handle) (if (odbc-call-successful? status-code) stmt-handle (error "error allocating statement handle"))))) (define env-handle (get-env-handle)) (define conn-handle (get-conn-handle env-handle)) (odbc-sql-connect conn-handle "pgfbsd" "test" "geheim") (define stmt-handle (get-stmt-handle conn-handle)) (odbc-sql-execute-direct stmt-handle "select * from abcd") (define col-a (odbc-sql-bindcol stmt-handle 1 sql-c-long 1)) (define col-b (odbc-sql-bindcol stmt-handle 2 sql-c-long 1)) (define col-c (odbc-sql-bindcol stmt-handle 3 sql-c-long 1)) (define col-d (odbc-sql-bindcol stmt-handle 4 sql-c-char 400)) (let lp ((retcode (odbc-sql-fetch stmt-handle)) (result '())) (if (or (odbc-call-successful? retcode) (equal? retcode sql-no-data)) (if (equal? retcode sql-no-data) result (lp (odbc-sql-fetch stmt-handle) (cons (list (col-a) (col-b) (col-c) (col-d)) result))) (error "Could not SQLFetch()"))) Please let me know, if you find some bugs. I hereby promise to complete the documentation as soon as possible! Eric Knauel