3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

日本語プログラミング言語Mind9βでSQLServer、Mysql、PostgreSQLにTclODBC接続(エラー処理)

Last updated at Posted at 2025-01-26

はじめに

今年の1月にMind9βを開発元@killyさんの御厚意により評価用としてご提供いただきましたので、前回の記事では、TclのODBCデータベース操作ライブラリをつかってSQLServer、Mysql、PostgreSQLに接続してみました。今回はその少し改良でエラー処理を追加しました。

前提条件

Windows11 Pro 22H2 22621.4169
mind version9-BETA-6

SQL Server 16.0.1000.6 Express Edition
SQL Server Management Studio 19.2.56.2
MySQL Community Server 8.3.0 winx64
mysql-workbench-community-8.0.36-winx64
mysql-connector-odbc-8.0.35-win32
postgresql-16.1-1-windows-x64
pgAdmin4↑これにはいってたやつ
psqlodbc_16_00_0000-x86

9βの言語拡張機能「評価」とは

ご関心があるようでしならば、たいへんお手数ですが、こちらの記事をご参照ください。

参考情報

tclDatabaseにはMysql、PostgreSQL、SQLLite固有のパッケージがありますが、今回評価しているのはtdbc:odbcというODBC接続用パッケージです。

お題のデータべース

SQLServer、Mysql、PostgreSQLでは共通のテーブル構成のデータベースを作成しています。データベース名は「日本語プログラミング言語」です。今回もそれを利用します。

db.png

お題のソースコード

今回は「評価した値」ではなく、エラー結果を返す「評価した値0」を使用します。また、エラー情報の取得はTcl_GetValueを使った単語を使用します。

ライブラリ

odebctcl.src
コマンドトークン設定は コマンドラインにトークンを設定と 等価。
コマンドトークン追加は コマンドラインにトークンを追加と 等価。
値を取得は             c_getvarと  等価。

接続文字列最大長は 定数 400バイト。
SQL文字列最大長は 定数 2000バイト。

改行コマンドトークン設定とは (トークン → ・)
    コマンドトークン設定し
    「&LF&」を コマンドトークン追加すること。

改行コマンドトークン追加とは (トークン → ・)
    コマンドトークン追加し
    「&LF&」を コマンドトークン追加すること。

ODBCライブラリをロードとは (・ → ・)
    "package require tdbc::odbc"を 評価すること。

SQL実行とは 	 (接続文字列 SQL文字列 → 結果文字列)
        connectStrは 文字列実体 長さ 接続文字列最大長
        commandStrは 文字列実体 長さ SQL文字列最大長
        成否は 変数
    commandStrに 入れ
    connectStrに 入れ
    「set stdout [open "CONOUT$" "w"]」を 改行コマンドトークン設定し
    「fconfigure $stdout -buffering line」を 改行コマンドトークン追加し
    「set connectionString {」を コマンドトークン追加し
    connectStrを コマンドトークン追加し
    「}」を 改行コマンドトークン追加し
    「set db [tdbc::odbc::connection create db $connectionString]」を 改行コマンドトークン追加し
    「set stmt [$db prepare {」を コマンドトークン追加し
    commandStrを コマンドトークンを追加し
    「}]」を 改行コマンドトークン追加し
    「set result [$stmt execute]」を 改行コマンドトークン追加し
    「$result foreach row {」を 改行コマンドトークン追加し
    「puts $stdout [dict get $row ]」を 改行コマンドトークン追加し
    「}」を 改行コマンドトークン追加し
    「$result close」を 改行コマンドトークン追加し
    「$stmt close」を 改行コマンドトークン追加し
    「$db close」を 改行コマンドトークン追加し
    「close $stdout」を コマンドトークン追加し
     コマンドラインを 評価した値0を 成否に 入れ
     成否が 0に 等しい
        ならば 「実行に失敗しました。」を 表示し 
                「errorInfo」と 10で 値を取得して 表示し 改行し
        つぎに
     返すこと。 

結果をモニタするとは (結果文字列 → ・)
    表示し 改行すること。

コマンドラインをモニタするとは (・ → ・)
    改行し
    コマンドラインを 表示し 改行し 改行すること。

テスト用コード

前回の記事と同じです。

SQLServerとMysqlのSELECT文はいまのところ共通ですが、PostgreSQLは日本語列名をダブルクォーテーションで囲わないと「言語id」になってしまうため囲っています。
TclスクリプトのモニタはSQLを実行した結果の後に出力しています。

お題のソースコードのMind9βでのビルド

C:\developments\vscode\mind9>mind testodbctcl guilib 

日本語プログラミング言語 Mind Version 8.11 for Windows
          Copyright(C) 1985 Scripts Lab. Inc.
コンパイル中 .. 終了
Coping.. c:\mind9-beta\mind9-beta\bin\mindexw.exe --> testodbctcl.exe

ビルド成功です!:tada:

お題のMind9βでの実行の様子

コンソールウィンドウを展開していますので、CUI出力を以下に示します。
前半は実行した結果、後半はMindのTcl評価へ与えたTclスクリプトの確認用出力です。これを3つのデータベースに対して実行しました。

前記掲載状態のコードは正常スクリプトのため、正常実行されます。その結果は前回の記事をご参照ください。

次にTclスクリプトでエラーを起こすため、下記のコードの「$row」の後に存在しない列名「xxx」を追記して実行します。

odebctcl.src
    「puts $stdout [dict get $row xxx]」を 改行コマンドトークン追加し

スクリプト部分はリテラル書きなのでいったんビルドしなおして実行します。

実行に失敗しました。key "xxx" not known in dictionary
    while executing
"dict get $row xxx"
    ("uplevel" body line 2)
    invoked from within
"uplevel 1 [lindex $args 1]"
    (class "::tdbc::resultset" method "foreach" line 40)
    invoked from within
"$result foreach row {
puts $stdout [dict get $row xxx]
}"


set stdout [open "CONOUT$" "w"]
fconfigure $stdout -buffering line
set connectionString {Driver={ODBC Driver 17 for SQL Server};Server=(local)\SQLEXPRESS;Database=日本語プログラミング言語;UID=sa;PWD=mind;}
set db [tdbc::odbc::connection create db $connectionString]
set stmt [$db prepare {SELECT * FROM 言語名 WHERE 言語ID IN (1,7)}]
set result [$stmt execute]
$result foreach row {
puts $stdout [dict get $row xxx]
}
$result close
$stmt close
$db close
close $stdout

実行に失敗しました。can't create object "db": command already exists with that name
    while executing
"tdbc::odbc::connection create db $connectionString"
    invoked from within
"set db [tdbc::odbc::connection create db $connectionString]"


set stdout [open "CONOUT$" "w"]
fconfigure $stdout -buffering line
set connectionString {Driver={MySQL ODBC 8.0 Unicode Driver};Server=localhost;Port=3306;Database=日本語プログラミング言 語;UID=root;PWD=mind;charset=cp932}
set db [tdbc::odbc::connection create db $connectionString]
set stmt [$db prepare {SELECT * FROM 言語名 WHERE 言語ID IN (1,7)}]
set result [$stmt execute]
$result foreach row {
puts $stdout [dict get $row xxx]
}
$result close
$stmt close
$db close
close $stdout

実行に失敗しました。can't create object "db": command already exists with that name
    while executing
"tdbc::odbc::connection create db $connectionString"
    invoked from within
"set db [tdbc::odbc::connection create db $connectionString]"


set stdout [open "CONOUT$" "w"]
fconfigure $stdout -buffering line
set connectionString {Driver={PostgreSQL UNICODE};Server=localhost;Port=5432;Database=日本語プログラミング言語;UID=postgres;PWD=mind;}
set db [tdbc::odbc::connection create db $connectionString]
set stmt [$db prepare {SELECT * FROM 言語名 言語名 WHERE "言語ID" IN (1,7)}]
set result [$stmt execute]
$result foreach row {
puts $stdout [dict get $row xxx]
}
$result close
$stmt close
$db close
close $stdout

エラー内容無事に取得できました:tada:
2回目以降のエラー内容が異なっているのは、1回目の処理が失敗したタイミングがDB接続開通した後なので、クローズ処理が実行されず、同じ接続識別子のdbでオープンしようとしたのでここでエラーとなっていることがわかります。このあたりはまだ試作状態でスクリプトを一本書きしていますので、次回から分割実行に進行します。

エラー判定ができるようになったので、次回は結合クエリより先にトランザクションの記述方法などを検討してみます。

おわりに

いかがでしたでしょうか?なにかの参考になれば幸いです。まだほんのさわりの部分ですが、今年で生誕40周年を迎える日本語プログラミング言語Mind、ついに新バージョンがベールをぬぎはじめます!

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?