AZ-Prolog ユーザーズマニュアル

## 9-9.ODBCパッケージ

### 9-9-1.ODBC 機能の利用方法

##### （1）Windows ODBC データソースの設定

Windowsのスタート→コントロールパネル→管理ツール→データソース（ODBC）→システムDSNタブでAccess，SQLサーバなどのODBC・DSN(データソースネーム）を追加します。
設定内容の詳細はODBCに関するマニュアル、ヘルプなどをお調べください。
64ビットOSでは、64ビット用ODBCが組み込まれている必要があります。
64ビット用AccessのODBCドライバが組み込まれていない場合、下記からランタイムをインストールできます。（2015年3月現在）
http://www.microsoft.com/ja-jp/download/details.aspx?id=39358
ここでは、DSN、ユーザ、パスワードすべて、"test"という文字列で設定された前提のプログラムとなっています。異なる場合は、次のステップの sql_connect_data/4 を必要に応じて書き換えます

##### （2）ユーザー定義単位節　DSNのProlog定義

1.で設定したDSNをProlog単位節で定義し、データベースの接続時に利用します。これ以降がPrologプログラムです。

書式 | sql_connect_data(DSN識別子,DSN,User,Password).

第一引数DSN識別子は、SQL発行時に該当する sql_statement/3 の第一引数とユニフィケーションされるものが採用されます。複数のDSNを利用する場合、これを考慮した対応がとれるようにしてください。ここの例ではひとつのDSNしか利用していませんので、無名変数としていますが、DSN を複数利用し、SQL文を対応付けるには以下のようにでもすればよろしいでしょう。

    sql_connect_data(sqlsv(_)  ,"sqlsv_dsn" ,....
    sql_connect_data(access(_) ,"access_dsn",....

    sql_statement(sqlsv(1),    <== sqlsv_dsn を利用してコネクトするSQL文
    sql_statement(sqlsv(2),    <== sqlsv_dsn を利用してコネクトするSQL文
    sql_statement(access(1), 　<== access_dsnを利用してコネクトするSQL文

    DSN識別子 DSN名   User  Password
    sql_connect_data(_,      "test","test","test").

##### （3）ユーザー定義単位節　SQL文の定義

select_each,exec_direct,などSQL呼び出しを行う述語で利用するSQL文とそのSQL文が利用するDSNとのリンク、select 時の取得データ型をあらかじめ準備するか動的にアサーションします。

書式 | sql_statement(SQL識別子,出力定義リスト,SQL文リスト).
SQL識別子 | select_each,exec_direct,などSQL呼び出しを行う述語に指定され、SQL文を一意に選択するための識別子です。
出力定義リスト | select呼び出しのみ意味を持ち、select　アイテムの取得型をその順に記述します。 RDB上の定義と異なってもいい場合もあります。 （DB:integer => Prolog:atom） ＜出力データ型の定義＞ char/文字数：結果は文字数以内の長さのアトム date：結果は年月日の数値3要素のリスト long：結果はinteger double：結果はfloat timestamp：結果は年月日時分秒シーケンス番号の数値７要素のリスト
SQL文(リスト): | リストの要素を平坦結合したものがSQL文としてRDBへ渡されます。 要素は文字列リスト、アトム、数値、date型年月日表現リスト(＜例＞ [2006,12,31] )および変数で、変数は出現順に呼び出し元から与えられる入力値リストで埋められます。 SQL識別子 出力定義リスト SQL文
    sql_statement(create,[],["create table 山岳テーブル ",
    "( 山名  char(16) primary key, 地域 char(10) ,標高 integer,","  緯度  integer, 経度 integer, 地図 char(16) )"]).

    sql_statement(insert,[],["insert into 山岳テーブル",
      % 変数は呼び出し時に値を与えます" values ( '",_,"','",_,"',",_,",",_,",",_,",'",_,"')"]).

    sql_statement(select,[char/20,long],["select 山名,標高 from 山岳テーブル ",_,_]).

    sql_statement(select2,[char/20,char/20,long,long,long,char/20],["select * from 山岳テーブル where ",_]).

##### （4）SQL文の実行

select_each/3 | SQL文を実行する。非決定性述語。バックトラックにより次解を返す。 ?-select_each(-取得結果リスト,+SQL識別子,+SQL文の変数充当データリスト). -取得結果リスト：SERECT文の場合、取得データがリストで返る +SQL識別子： sql_statement/3 を特定する識別子 +SQL文の変数充当データリスト：SQL文中の変数に充当するデータ
exec_direct/2 | 結果取得をともなわないSQL文(insert,delete,dorp など)を実行する ?-exec_direct(+SQL識別子,+SQL文の変数充当データリスト).
exec_directs/3 | 結果取得をともなわないSQL文(insert,delete)を複数の充当値で実行する ?-exec_directs(+SQL識別子, 変数充当データリストのリスト,-エラーリスト). -エラーリスト：実行エラーとなった変数充当データリストのリスト
is_null/1 | 引数である該当取得データがnullの時に成功する
sql_cancels/1 | 指定SQL識別子の問い合わせをキャンセルする
odbc_close/0 | 現在接続されている全てのODBCコネクションをクローズする。 ★なお、前記の述語の部品を構成する次のものもPublicとなっている。SQL処理の間に別の処理をはさむ必要があったときなどに利用できる。仕様詳細はソースコード（odbc_prolog.pl）参照のこと。 odbc_open/3 select_each/4 select_each/6 fetch_one/4 exec_directs_pre/4 exec_directs_post/2 exec_directs_main/4 ★また、ODBCとの最下層のやり取りは、Cソースコンパイルド組込述語による。これらの仕様詳細はソースコード（odbc.c）を参照のこと。ユーザ独自のSQL操作系を構成できる。

##### （5）実行例

１)ODBC拡張機能を取り込みます

    | ?- dlib_require(odbc).
    yes

2)テーブルの生成
テーブルが生成されます。

    ?- exec_direct(create,[]).
    yes

3)データのインサート
データがインサートされます
insert_data/1 はフィールドに埋めるデータ並びのリストの単位節です。

    ?-insert_data(X),exec_direct(insert,X),fail.
    No

なお、これは次の方法でもよい。

    ?-bagof(X,insert_data(X),L),exec_directs(insert,L,Err).

4)データの条件なし取得
全件なので元SQL文の変数部分に空を渡します。

    ?-  select_each(X,select,["",""]).
      X= [富士山,3776];
      X= [北岳,3192]

5)データの条件つき取得

    ?- select_each(X,select,["where 標高 < ",3000]).
      X= [剣岳,2998];
      X= [水晶岳,2986]

    % インサートデータ

    %          　山名         地域  　標高　 緯度   経度    地図
    insert_data([富士山,     富士周辺,3776,352127,1384350,富士山]).
    insert_data([北岳,       南ア北部,3192,354017,1381431,仙丈ヶ岳]).
       :
    insert_data([鷲羽岳,     北ア北部,2924,362400,1373630,三ツ俣蓮岳]).
    insert_data([大天井岳,   北ア北部,2922,362143,1374215,槍ヶ岳]).

### 9-9-2.AZ-Prolog用のODBCインターフェース基層述語

##### （1）概要

1.ODBC 64ビットバージョン

Windows 7(64bit)
Microsoft Access 2013（64bit）
ODBCドライバ（MSAccess）14.00.7010.1000
ODBCドライバ（SQL Server）6.01.7601.17514
ODBCドライバ（SQL Server Native Client）2011.110.3000

Windows 7(64bit) MS Access 2013（64bit）
Windows 7(64bit) SQLServer 2012 ExpressEdition（64bit）

2.ODBC 32ビットバージョン

Windows 2000
Microsoft SQL Server 2000
ODBCドライバマネージャ 3.520.6526.0
ODBCドライバ(SQL Server) 2000.80.194.00

Windows 7(32bit) MS Access
Windows XP(32bit) MS Access

上記の構成で動作確認を行っています。
ODBC自体については、ODBCに関する文献、電子マニュアル等を参照してください。
ソース：odbc.c

##### （2）ODBCインターフェース

###### 1）定数

ODBCで使用されるシンボルの内、以下のものが同じ名前で
アトムとして組み込まれている。
(但し、全て小文字に置き換えている)

NULLハンドル値
sql_null_handle
戻り値(RV)
sql_succeeded sql_no_data sql_error sql_invalid_handle sql_still_executing sql_need_data
Cデータ型(CT)
sql_c_char sql_c_long sql_c_double sql_c_date sql_c_timestamp
SQLデータ型(SQLT)
sql_char sql_varchar sql_longvarchar sql_decimal sql_numeric sql_smallint sql_integer sql_real sql_float sql_double sql_bit sql_tinyint sql_bigint sql_binary sql_varbinary sql_datetime sql_type_time sql_type_timestamp
ハンドル型(HT)
sql_handle_env sql_handle_dbc sql_handle_stmt
入出力タイプ(IOT)
sql_param_input sql_param_output sql_param_input_output
トランザクション(TT)
sql_commit sql_rollback

###### 2）述語

以下の述語が組み込まれている。
2.1) 補助述語
これらはODBC関数には対応するものが存在しないが、Prologで使用するために
必要なので用意されている。
sql_free_param/1
sql_free_params/1
sql_get_param/2
sql_set_param/2
sql_select_assert/4
sql_select_assert_limit/1
sql_error_info/1
2.2） ODBC述語
同名のODBC関数(但しアンダースコアで区切られている)と同じ機能を持つ。
(＜例＞ODBC関数 SQLConnect() --> 述語 sql_connect)
sql_alloc_handle/3
sql_alloc_env/1
sql_alloc_connect/2
sql_bind_col/5
sql_bind_parameter/9
sql_connect/4
sql_disconnect/1
sql_free_handle/2
sql_free_connect/1
sql_exec_direct/2
sql_execute/1
sql_end_tran/3
sql_fetch/2
sql_prepare/2
sql_row_count/2

2.3） 補助述語詳細
補助関数には、パラメタに関する操作を行う述語と、
検索と検索結果のassertを一度に行うための述語がある。
パラメタとは、SQL文に関連付けられて、値の入出力のために存在するもので、
ODBC関数で使用される。(具体的には、sql_bind_col/5, sql_bind_parameter/9
の中でパラメタが生成される。)
パラメタは、パラメタの生成時点で指定されたCデータ型(CT)をもつ。
以下の説明の中の引数の表記で、+は入力、-は出力を表す。

sql_free_param(+Param)
指定した一個のパラメタの領域を開放する。 そのパラメタは使用できなくなる。 ＜例＞ sql_free_param(X).
sql_free_params(+ParamsList)
指定したリストの全ての要素のパラメタの領域を開放する。 ＜例＞ sql_free_params([P1, P2, P3]).
sql_get_param(+Param, -Value)
指定したパラメタの値を取得する。 ＜例＞ sql_get_param(P, V). %% ==> V = 10.6 パラメタがsql_c_char型のときは値はアトムになる。 sql_c_date型のときは、三個の要素をもったリスト([Year, Month, Day])になる。 sql_c_timestamp型のときは、七個の要素をもったリストになる。 ([Year, Month, Day, Hour, Minute, Second, Fraction])
sql_set_param(+Param, +Value)
指定したパラメタの値をセットする。 ＜例＞ sql_set_param(P, 200). 値の型については、sql_get_param/2の説明を参照。 但し、パラメタがsql_c_char型のときには、アトムではなく、 文字列(AZ-Prologでは整数のリスト)で指定しても良い。
sql_select_assert(+Stmt, +ColTypeList, +ColLengthList, +PredName)
指定したSQL文ハンドル(Stmt)を実行し、その検索結果の全ての行に対して、 述語名がPredNameの節をassertする。 ColTypeListはStmtにバインドするカラムの型のリストであり、ColLengthListは カラムのサイズのリストである。(sql_bind_col/5参照) ＜例＞ sql_select_assert(Stmt, [sql_c_char, sql_c_char, sql_c_timestamp, sql_c_long], [4, 20, _, _], sales). %% ==> sales('6380', '6871', [1994,9,14,0,0,0,0], 5). sales('7131', 'D4482', [2001,3,11,0,0,0,0], 20).
sql_select_assert_limit(+LimitNum)
sql_select_assert/4でassertする個数をLimitNum個に制限する。 無制限にするときは、LimitNumに-1を指定する。 (デフォルトは無制限) ＜例＞ sql_select_assert_limit(30).
sql_error_info(-Info)
ODBC関数の実行が正常終了しなかったとき、 そのエラーに関する情報文字列をアトムで返す。 ＜例＞ sql_error_info(S). %% ==> S = 'SQLBindCol: ......' どういう訳か、SQLGetDiagRec()がまともな情報を返してくれることが 滅多にないので、返される文字列の内の先頭の関数名以外は滅茶苦茶な ことが多いが、私にはどうすることもできない。

2.4） ODBC述語詳細
ODBC関数自体の機能については、ODBCに関する文献、電子マニュアルを参照。

sql_alloc_handle(+HT, +InHandle, -OutHandle)
指定したハンドル型(HT)のハンドルを生成して返す。 InHandleはハンドル値またはsql_null_handleアトムを指定する。 ＜例＞ sql_alloc_handle(sql_handle_stmt, DBC, Stmt).
sql_alloc_env(-Env)
環境ハンドルを生成する。 ＜例＞ sql_alloc_env(Env).
sql_alloc_connect(+EnvHandle, -DBCHandle)
DB接続ハンドルを生成する。 最初の引数で環境ハンドルを指定する。 ＜例＞ sql_alloc_connect(Env, DBC).
sql_bind_col(+Stmt, +ColNum, +CT, -Param, +Size)
パラメタを生成して、指定したSQL文ハンドルの指定した番号のカラムに バインドする。生成されたパラメタがParam引数にセットされる。 ColNumはカラム番号(1から始まる)。 CTはパラメタのCデータ型アトム。 Sizeはsql_c_char型のときにだけ意味がある。他の場合は不定値でもよい。 ＜例＞ sql_bind_col(Stmt, 2, sql_c_char, OrderNum, 20).
sql_bind_parameter(+Stmt, +Num, +IOT, +CT, +SQLT, +ColSize, +DecimalDigit, -Param, +Size)
パラメタを生成して、指定したSQL文ハンドルの指定した番号のパラメタとして バインドする。生成されたパラメタがParam引数にセットされる。 Numはパラメタの番号(1から始まる)。 CTはパラメタのCデータ型アトム。 SQLTはSQLデータ型アトム。 Sizeはsql_c_char型のときにだけ意味がある。他の場合は不定値でもよい。 ColSize, DecimalDigitについては、ODBC関数のSQLBindParameter()を参照。 ＜例＞ sql_bind_parameter(Stmt, 1, sql_param_input, sql_c_date, sql_char, 0, 0, ParamOrdDate, 0).
sql_connect(+DBCHandle, +DSN, +UserName, +Password)
指定したDB接続ハンドルで、データーベースに接続する。 DSN, UserName, Passwordはアトムまたは文字列で指定する。 ＜例＞ sql_connect(DBC, 'AnyDSN', 'yamamoto', 'aaaaaaaaaaaaaa').
sql_disconnect(+DBCHandle)
指定したDB接続ハンドルの接続を切る。 ＜例＞ sql_disconnect(DBC).
sql_free_handle(+HT, +Handle)
指定したハンドルを開放する。 ＜例＞ sql_free_handle(sql_handle_env, Env).
sql_free_connect(+DBCHandle)
指定したDB接続ハンドルを開放する。 ＜例＞ sql_free_connect(DBC).
sql_exec_direct(+Stmt, +SQLString)
指定したSQL文ハンドルで、指定したSQL文を直接実行する。 SQLStringは、アトムか文字列で指定する。 ＜例＞ sql_exec_direct(Stmt, "delete sales where ord_date = '2002-04-23'").
sql_execute(+Stmt)
指定したSQL文ハンドルを実行する。 ＜例＞ sql_execute(Stmt).
sql_end_tran(+HT, +Handle, +CompletionType)
指定したハンドルで、指定したタイプでトランザクションを終了する。 CompletionTypeは、sql_commitかsql_rollbackのどちらか。 ＜例＞ sql_end_tran(sql_handle_dbc, DBC, sql_commit). デフォルトで自動コミットモードになっているのであれば、 これを実行しても意味がない。
sql_fetch(+Stmt, -Result)
実行されたSQL文ハンドルの一行分の結果を取得する。 結果の値は、sql_bind_colされたパラメタにセットされる。 Resultには、戻り値(RV)として定義されたアトムのどれかが返される。 ＜例＞ sql_fetch(Stmt, Result). %% ==> Result = sql_succeeded
sql_prepare(+Stmt, +SQLString)
指定したSQL文ハンドルで、指定したSQL文の実行を準備する。 SQLStringは、アトムか文字列で指定する。 ＜例＞ sql_prepare(Stmt, "select stor_id, ord_num, qty from sales where ord_date = ?").
sql_row_count(+Stmt, -Count)
指定したSQL文ハンドルの実行結果として影響を受けた行数を返す。 (INSERT, UPDATEのときのみ) ＜例＞ sql_row_count(Stmt, Row). %% ==> Row = 7

▲