2018年12月12日水曜日

ABCL

 あれ、CL-DBIはOrcleに対応してないのか1
 探せば、どこかにあるかもしれないけど、つらつら考えてそういや、ABCLってjava上で動くCommonLispなんだよな。それならjavaを使って(ojdbc.jarを使って)Oracleにアクセスできるんじゃね?
 「Class.forName("oracle.jdbc.driver.OracleDriver");」をやっただけではうまくいかなくて、けっこう苦労したけれど、いちおう、動いたような気がする。ざっくり。
 錯覚かもしれないが。

(in-package :cl-user)

(defpackage y-dbi
  (:use :cl :java))

(in-package :y-dbi)

(add-to-classpath "ここにojdbc.jarを指定")

(defvar oracle (jnew "oracle.jdbc.driver.OracleDriver")
  "oracleのドライバをロード")

(defun connect(&key server database user password)
  (let ((connect
  (concatenate 'string "jdbc:oracle:thin:@" server ":1521:" database))
 (properits (jnew "java.util.Properties")))
    (jcall "put" properits "user" user)
    (jcall "put" properits "password" password)
    (jcall "connect" oracle connect properits)))

(defun disconnect(conn)
  (jcall "close" conn))

(defun execute(conn sql)
  "ResultSetを返却する"
  (let ((stmt (jcall "createStatement" conn)))
    (jcall "executeQuery" stmt sql)))

(defun fetch(rs)
  (jcall "next" rs)
  (when (not (jcall "isAfterLast" rs))
    (let ((rsmd (jcall "getMetaData" rs)))
      (loop for i from 1 to (jcall "getColumnCount" rsmd)
  append
    (list (intern (jcall "getColumnName" rsmd i) 'keyword)
   (jcall "getString" rs i))))))

(defun select(conn sql &optional limit)
  (let ((rs (execute conn sql)))
    (if limit
 (loop for i from 0 to (- limit 1)
    collect (fetch rs))
 (loop for row = (fetch rs)
    while row
    collect row))))

(defun column(list)
  (loop for x in list
     for i from 0
       append (when (evenp i) (list x))))
CL-USER> (in-package :y-dbi)
#<PACKAGE Y-DBI>
Y-DBI> (select (connect :server "XXXX"
   :database "YYYY"
   :user "ZZZZ"
   :password "PASS") "select * from dual")
((:DUMMY "X"))
Y-DBI>

Footnotes:

1

商用なのである意味、当たり前か。