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?

More than 1 year has passed since last update.

Mindでトランザクション事始めな書き方を探る(C文字列終端とエラーメッセージ)

Last updated at Posted at 2024-02-20

はじめに

API側でエラーコードとエラーメッセージをアプリケーションに返せるようになりましたので、それを利用できるようにします。また、前回までヌル終端文字列を文字列定数の末尾に記述していましたので、そこも改修しました。

お題のソースコード

エラーメッセージ

原型の全体イメージがないとわかりずらいかと思いますが、いちおう以下がポイントです。

mssqlodbc.src
関数名は 文字列定数配列
「openDb」
「closeDb」
    ※~略~※
「endTransaction」
「getErrorMsg」。
openDbは 		  定数 1。
closeDbは 		  定数 2。
    ※~略~※
getErrorMsgは 		定数 11。

    ※~略~※
SQLエラー取得とは	    $$NULLと 	getErrorMsgで 		API関数を呼び出す。
    ※~略~※

メインとは
    ※~略~※
		ここまでトランザクションスコープです

		[ret = 0] ならば トランザクションをコミットし
		さもなければ	 
			SQLエラー取得し Mind文字列に変換し 一行表示し
			トランザクションをロールバックし
		つぎに
    ※~略~※
	ここまで実行可能です

	API破棄処理すること。

C文字列終端

文字列実体変数に0を一文字追加で対応するようにしました。いちおう以下がポイントです。

mssqlodbc.src
    ※~略~※
接続文字列最大長は  定数 400バイト。
SQL文字列最大長は   定数 2000バイト。
パラメータ文字列最大長は 定数 400バイト。

DB接続とは 	 (接続文字列 → 1:成功/0:失敗)			
	retは	変数
	connectStrは 文字列実体 長さ 接続文字列最大長
	connectStrに 入れ
	0を connectStrに 一文字追加し
	connectStrと openDbで API関数を呼び出し retに 入れ
	[ret = 0] ならば 「DB接続 成功」を 一行表示し 
	さもなければ 「DB接続 失敗」を 一行表示し
	つぎに
	[ret = 0]を 返す。
 
 SQL文をセットとは (SQL文字列 → 0:成功/0以外:失敗)
	commandStrは 文字列実体 長さ SQL文字列最大長
	commandStrに 入れ
	0を commandStrに 一文字追加し			
	commandStrと setStatementで 	API関数を呼び出す。

文字列のSQLパラメータをセットとは (文字列 → 0:成功/0以外:失敗)
	parameterStrは 文字列実体 長さ パラメータ文字列最大長
	parameterStrに 入れ
	0を parameterStrに 一文字追加し		
	parameterStrと bindParameterStrで 	API関数を呼び出す。

     ※~略~※

メインとは
	datasourceは 文字列定数 「Driver={ODBC Driver 17 for SQL Server};Server=(local)\SQLEXPRESS;Database=日本語プログラミング言語;UID=sa;PWD=****;」
 	SELECTは   文字列定数 「SELECT LN.言語ID,LN.言語名,LN.よみがな,DLN.開発言語ID,DLN.開発言語名 FROM 言語名 AS LN 」続
					「LEFT JOIN 開発言語 AS DL ON LN.言語ID = DL.言語ID 」続
					「LEFT JOIN 開発言語名 AS DLN ON DLN.開発言語ID=DL.開発言語ID WHERE LN.言語ID IN (?,?)」
	INSERTは   文字列定数 「INSERT INTO 開発言語 (言語ID,開発言語ID) VALUES (?,?)」
	UPDATEは   文字列定数 「UPDATE 言語名 SET よみがな = ? WHERE 言語ID = ?」
	DELETEは   文字列定数 「DELETE 開発言語 WHERE 言語ID = ? AND 開発言語ID = ?」
     ※~略~※

			UPDATEで SQL文をセットし
			「まいんど」で 文字列のSQLパラメータをセットし
			7で 整数のSQLパラメータをセットし
			SQLコマンド実行し retに 入れ
			[ret ≠ 0] ならば Tranスコープを抜け出し	
			つぎに
     ※~略~※ 

API呼び出し単語内で対応しましたので、地味に呼び出し単語に渡す文字列にはnull終端不要になりました。

実行結果(1回目)

まず1回目です。API側のデバッグ出力は無効化されていますので、接続状況と結果セットだけがアプリケーション側でコンソール出力されます。

C:\pmind\sample>mssqlodbc.exe
ODBCライブラリをロードする
ロード成功
関数アドレス群を取得
取得成功
DB接続 成功
|言語ID|言語名|よみがな|開発言語ID|開発言語名|
|1|Mind|まいんど|1|C|
|1|Mind|まいんど|7|Forth|
|1|Mind|まいんど|8|Mind|
|7|Mind for Android|まいんど ふぉー あんどろいど|<NULL>|<NULL>|
|言語ID|言語名|よみがな|開発言語ID|開発言語名|
|1|Mind|まいんど|1|C|
|1|Mind|まいんど|8|Mind|
|7|Mind for Android|まいんど|3|Java|
ODBCライブラリを破棄する

C:\pmind\sample>

無事に動作しました。定数にnull終端がなくても動作していることがわかります。

実行結果(2回目)

続けて同じSQLを投げてみます。今度は1回目でインサートされたレコードとPK制約違反でエラーになる想定です。

C:\pmind\sample>mssqlodbc.exe
ODBCライブラリをロードする
ロード成功
関数アドレス群を取得
取得成功
DB接続 成功
|言語ID|言語名|よみがな|開発言語ID|開発言語名|
|1|Mind|まいんど|1|C|
|1|Mind|まいんど|8|Mind|
|7|Mind for Android|まいんど|3|Java|
23000 [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]制約 'PK_開発言語' の PRIMARY KEY 違反。オブジェクト 'dbo.開発言語' には重複するキーを挿入できません。重複するキーの値は (7, 3) です。
|言語ID|言語名|よみがな|開発言語ID|開発言語名|
|1|Mind|まいんど|1|C|
|1|Mind|まいんど|8|Mind|
|7|Mind for Android|まいんど|3|Java|
ODBCライブラリを破棄する

C:\pmind\sample>

こんどはエラーコードとエラーメッセージが出力されました。

おわりに

道のりはまだ長いです。次は日付型のパラメータバインドの予定ですが、しばらくお休みします。

この記事内容の作業環境

Windows11 Pro 22H2
CPU Intel(R) Core(TM) i3-5005U 2.00 GHz
Microsoft Visual Studio Community 2022 Version 17.4.4
Microsoft Visual C++ 2022
Mind Version 8.0.08 for Windows
SQL Server 16.0.1000.6 Express Edition
SQL Server Management Studio 19.2.56.2

参考情報

ソースコード全文
mssqlodbc.src
DLLは 			変数。
DLLパスは 文字列定数	"C:\developments\mssqlodbc32\Debug\mssqlodbc32.dll"。
関数名は 文字列定数配列
「openDb」
「closeDb」
「exec」
「setStatement」
「bindParameterInt」
「bindParameterStr」
「getResultset」
「execCommand」
「setAutoCommit」
「endTransaction」
「getErrorMsg」。
openDbは 		定数 1。
closeDbは 		定数 2。
execは 		定数 3。
setStatementは 	定数 4。
bindParameterIntは 	定数 5。
bindParameterStrは 	定数 6。
getResultsetは 	定数 7。
execCommandは 		定数 8。
setAutoCommitは 	定数 9。
endTransactionは 	定数 10。
getErrorMsgは 		定数 11。
関数の個数は 定数 関数名の 要素数。
関数アドレスは 関数の個数の 変数。
結果セット型は 型紙
   列データは 変数
   全体は
   1000の 列データ。
接続文字列最大長は 定数 400バイト。
SQL文字列最大長は 定数 2000バイト。
パラメータ文字列最大長は 定数 400バイト。

ODBCライブラリをロードとは (・ → 真偽)
     DLLパスで モジュールをロードし 
   DLLに 入れ
     DLLが ゼロ以外を 返すこと。

ODBCライブラリを破棄とは (・ → ・)
     DLLが ゼロ以外
          ならば DLLで モジュールを解放し
               DLLを クリアする
          つぎに。

ODBC関数アドレス群を取得とは (・ → ・)
	関数の個数を
	回数指定し
		DLLと 関数名(回数)で モジュールの関数アドレスを得て
		 関数アドレス(回数)に 入れ
		エラー?
			ならば 打ち切り
			つぎに
	繰り返し。

API破棄処理とは (・ → ・)
    「ODBCライブラリを破棄する」を 一行表示し
    ODBCライブラリを破棄する。

API初期処理とは (・ → 0/1)

    「ODBCライブラリをロードする」を 一行表示し
    ODBCライブラリをロードし 偽? ならば 「ロード失敗」を 一行表示し 1を 返し 終わり
     つぎに
    「ロード成功」を 一行表示し


    「関数アドレス群を取得」を 一行表示し
    ODBC関数アドレス群を取得し エラー? ならば 「取得失敗」を 一行表示し 
	ODBCライブラリを破棄してから 1を 返し 終り
     つぎに
    「取得成功」を 一行表示し 0を 返す。

API関数を呼び出しとは (引数、番号 → 結果)
	関数アドレス(スタック)で アドレス指定でAPI呼出1すること。

DB接続とは 	 (接続文字列 → 1:成功/0:失敗)			
	retは	変数
	connectStrは 文字列実体 長さ 接続文字列最大長
	connectStrに 入れ
	0を connectStrに 一文字追加し
	connectStrと openDbで API関数を呼び出し retに 入れ
	[ret = 0] ならば 「DB接続 成功」を 一行表示し 
	さもなければ 「DB接続 失敗」を 一行表示し
	つぎに
	[ret = 0]を 返す。
成功ならばここからは	回数指定と	等価。
ここまで実行可能ですは	繰り返すと	等価。

SQL実行とは 	 (SQL文字列 → 0:成功/0以外:失敗)
	commandStrは 文字列実体 長さ SQL文字列最大長
	commandStrに 入れ
	0を commandStrに 一文字追加し
	commandStrと execで 		API関数を呼び出す。
DB切断とは		    $$NULLと  	closeDbで 		API関数を呼び出す。
SQL文をセットとは (SQL文字列 → 0:成功/0以外:失敗)
	commandStrは 文字列実体 長さ SQL文字列最大長
	commandStrに 入れ
	0を commandStrに 一文字追加し			
	commandStrと setStatementで 	API関数を呼び出す。
整数のSQLパラメータをセットとは		bindParameterIntで 	API関数を呼び出す。
文字列のSQLパラメータをセットとは (文字列 → 0:成功/0以外:失敗)
	parameterStrは 文字列実体 長さ パラメータ文字列最大長
	parameterStrに 入れ
	0を parameterStrに 一文字追加し		
	parameterStrと bindParameterStrで 	API関数を呼び出す。
結果セット取得とは	    $$NULLと 	getResultsetで 	API関数を呼び出す。
SQLコマンド実行とは	    $$NULLと 	execCommandで 		API関数を呼び出す。
コミットモードをセットとは 		setAutoCommitで 	API関数を呼び出す。
トランザクションを終了とは 		endTransactionで 	API関数を呼び出す。
SQLエラー取得とは	    $$NULLと 	getErrorMsgで 		API関数を呼び出す。

トランザクションを開始とは	 (・ → 1:成功/0:失敗)	
	retは	変数
	0で コミットモードをセットし retに 入れ
	[ret = 0]を 返す。
Tranスコープを抜け出すとは 		打ち切りと 	等価。
ここまでトランザクションスコープですは	繰り返すと	等価。
トランザクションをコミットとは		1で トランザクションを終了する。
トランザクションをロールバックとは 	0で トランザクションを終了する。
結果セットを表示するとは	(・ →  ・)
	resultSetは 	変数
	iは 		変数
	resultSetに 入れ
	[resultSet ≠ 0] ならば

		[i := 1]
		ここから
			resultSetの 列データ(i)が 0に 等しい ならば 打ち切り つぎに
			「|」を 表示し
			resultSetの 列データ(i)を Mind文字列に変換し 表示し
			iを 一つ増加し
		繰り返し
	つぎに。


メインとは
	datasourceは 文字列定数 「Driver={ODBC Driver 17 for SQL Server};Server=(local)\SQLEXPRESS;Database=日本語プログラミング言語;UID=sa;PWD=****;」
	SELECTは   文字列定数 「SELECT LN.言語ID,LN.言語名,LN.よみがな,DLN.開発言語ID,DLN.開発言語名 FROM 言語名 AS LN 」続
					「LEFT JOIN 開発言語 AS DL ON LN.言語ID = DL.言語ID 」続
					「LEFT JOIN 開発言語名 AS DLN ON DLN.開発言語ID=DL.開発言語ID WHERE LN.言語ID IN (?,?)」
	INSERTは   文字列定数 「INSERT INTO 開発言語 (言語ID,開発言語ID) VALUES (?,?)」
	UPDATEは   文字列定数 「UPDATE 言語名 SET よみがな = ? WHERE 言語ID = ?」
	DELETEは   文字列定数 「DELETE 開発言語 WHERE 言語ID = ? AND 開発言語ID = ?」

	retは 		変数


	API初期処理しておき retに 入れ
	[ret ≠ 0] ならば 終わり つぎに

	datasourceで DB接続し 
	成功ならばここから

		SELECTで SQL文をセットし
		1で 整数のSQLパラメータをセットし
		7で 整数のSQLパラメータをセットし
		結果セット取得し 結果セットを表示する

		トランザクションを開始し
		成功ならばここから

			INSERTで SQL文をセットし
			7で 整数のSQLパラメータをセットし
			3で 整数のSQLパラメータをセットし
			SQLコマンド実行し retに 入れ
			[ret ≠ 0] ならば Tranスコープを抜け出し
			つぎに

			UPDATEで SQL文をセットし
			「まいんど」で 文字列のSQLパラメータをセットし
			7で 整数のSQLパラメータをセットし
			SQLコマンド実行し retに 入れ
			[ret ≠ 0] ならば Tranスコープを抜け出し	
			つぎに

			DELETEで SQL文をセットし
			1で 整数のSQLパラメータをセットし
			7で 整数のSQLパラメータをセットし
			SQLコマンド実行し retに 入れ
			[ret ≠ 0] ならば Tranスコープを抜け出し
			つぎに
			
	
		ここまでトランザクションスコープです

		[ret = 0] ならば トランザクションをコミットし
		さもなければ	 
			SQLエラー取得し Mind文字列に変換し 一行表示し
			トランザクションをロールバックし
		つぎに

		SELECTで SQL文をセットし
		1で 整数のSQLパラメータをセットし
		7で 整数のSQLパラメータをセットし
		結果セット取得し 結果セットを表示する

		DB切断し

	ここまで実行可能です

	API破棄処理すること。

3
1
4

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?