Microsoft Japan Data Platform Tech Sales Team
先日、とあるパートナー様より標題の件についてご質問をいただきました。例えば SQLGetDiagRec 関数のマニュアルを見ますと ”MessageText” の型は SQLCHAR となっております。そして、Microsoft ODBC Driver for SQL Server on Linux のプログラミングガイドラインには以下のような記述がございます。
文字のサポート
SQLCHAR データは、UTF-8 である必要があります。 SQLWCHAR データは UTF 16LE (リトル エンディアン) である必要があります。
Microsoft ODBC Driver for SQL Server on Linux の ODBC API のパラメータの内、 文字列部分の多くは SQLCHAR で定義されております。よって標題のご質問に対する回答は UTF-8 ということになります。
以上です、で終わってしまっては寂しいので実機にて確認してみました。
[実機環境]
APサーバー
OS : Redhat 6
ODBC Driver : ODBC Driver 11 for SQL SQL Server on Redhat
DBサーバー
OS : Windows Server 2012 R2
DB Software : SQL Server 2014 SP1
DB : AdventureWorks2014
[確認手順]
1. 先ずはこちらより msodbcsql-11.0.2270.0.tar.gz をダウンロードします。
2. Linux 環境で展開します。
$ tar zxvf msodbcsql-11.0.2270.0.tar.gz |
3. unixODBC Driver Manager をインストールします。詳細についてはこちらをご参照ください。(2016/7/20追記)
$ cd msodbcsql-11.0.2270.0
$ sudo ./build_dm.sh |
4. ODBC Driver をインストールするために事前チェックを実行します。事前チェック、インストールの詳細についてはこちらをご参照ください。(2016/7/20追記)
$ sudo ./install.sh verify |
5. 問題なければ ODBC Driver をインストールします。
$ sudo ./install.sh install |
6. /etc/odbc.ini ファイルに以下を記述します。
[MSSQLTest]
Driver = ODBC Driver 11 for SQL Server Server = <Server Name or IP Address>,<必要であればポート番号> |
7. /etc/odbcinst.ini に以下が登録されていることを確認します。
[ODBC Driver 11 for SQL Server]
Description=Microsoft ODBC Driver 11 for SQL Server Driver=/opt/microsoft/msodbcsql/lib64/libmsodbcsql-11.0.so.2270.0 Threading=1 UsageCount=1 |
8. 以下のようなテストコードを用意します。(なお、このコードはあくまでもサンプル用で簡略化しています。エラーハンドリングや注釈などもございませんがご了承ください。)
SQLGetDiagRecTest.c
#include <stdio.h> #include <stdlib.h> #include <sqlext.h> #include <sql.h> int main() { SQLHENV henv; SQLHDBC hdbc; SQLHSTMT hstmt = 0; SQLRETURN retcode; SQLRETURN r = 0; SQLCHAR szSqlState[6] = { 0 }; SQLINTEGER fNativeError = 0; SQLCHAR szErrorMsg[256] = { 0 }; SQLSMALLINT cbErrorMsgMax = sizeof(szErrorMsg) - 1; SQLSMALLINT cbErrorMsg = 0; char *strenv; strenv = getenv("LANG"); //printf("%s\n",strenv); // Allocate environment handle retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); // Set the ODBC version environment attribute if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0); // Allocate connection handle if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); // Set login timeout to 5 seconds if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0); // Connect to data source retcode = SQLConnect(hdbc, (SQLCHAR*) "MSSQLTest", SQL_NTS, (SQLCHAR*) "" , 5, (SQLCHAR*) "", 9); // Allocate statement handle if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); retcode = SQLExecDirect (hstmt, (SQLCHAR *) "USE [AdventureWorksDW2014]", SQL_NTS); r = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt,(SQLSMALLINT) 1, szSqlState, &fNativeError, szErrorMsg, cbErrorMsgMax, &cbErrorMsg); printf("%s\n",szErrorMsg); if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { SQLCancel(hstmt); SQLFreeHandle(SQL_HANDLE_STMT, hstmt); } SQLDisconnect(hdbc); } SQLFreeHandle(SQL_HANDLE_DBC, hdbc); } } SQLFreeHandle(SQL_HANDLE_ENV, henv); } }
|
9. 上記ソースをコンパイル
$ export LD_LIBRARY_PATH=/usr/local/lib:/usr/lib:/usr/local/include $ cc -m64 -g -I/usr/include -L/usr/local/lib -L/usr/lib -L/usr/local/include -lodbc -std=c99 -o SQLGetDiagRecTest SQLGetDiagRecTest.c |
10. strace でトレースを取得
$ strace -o trace.log ./SQLGetDiagRecTest > SQLGetDiagRecTest.log |
11. 出力結果の確認
トレースファイル ”trace.log“ を確認したところ、SQLGetDiagRec の MessageText 部分には以下が返ってきておりました。
"[Microsoft][ODBC Driver 11 for SQL Server][SQL Server]\343\203\207\343\203\274\343\202\277\343\203\231\343\203\274\343\202\271 \343\202\263\343\203\263\343\203\206\343\202\255\343\202\271\343\203\210\343\201\214 'AdventureWorksDW2014' \343\201\253\345\244\211\346\233\264\343\201\225\343\202\214\343\201\276\343\201\227\343\201\237\343\200\202\" |
文字列としては “USE [AdventureWorksDW2014]" を実行しておりますので、以下が返ってきているはずです。
[Microsoft][ODBC Driver 11 for SQL Server][SQL Server]データベース コンテキストが 'AdventureWorksDW2014' に変更されました。 |
そこで、マルチバイト文字部分の赤字部分について文字コードを比較したところ以下となりました。
UTF-8(8進) | |
デ | \343\203\207 |
ー | \343\203\274 |
タ | \343\202\277 |
ベ | \343\203\231 |
ー | \343\203\274 |
ス | \343\202\271 |
つまり、SQLGetDiagRec の SQLCHAR 型である MessageText 部分は UTF-8 であることが確認できました。
上記より、繰り返しとなりますが ODBC API を使用したアプリケーションを実装される際、 API パラメータ の SQLCHAR 型部分は UTF-8 となります。
同じコードで実験してみました。結果は以下のようになりました。
[Microsoft][ODBC Driver 11 for SQL Server][SQL Server]\307\374\277\331\374\271\263\363\306\255\271\310L ‘AdventureWorksDW2014’ …
UTF16の一部のみが結果として戻っているように見えます。
UTF16 結果
デ 30C7 C7 (\307)
ー 30FC FC (\374)
タ 30BF BF (\277)
ベ 30D9 D9 (\331)
ー 30FC FC (\374)
ス 30B9 B9 (\271)
LANGの指定はどのようになっているのでしょうか?
ja_JP.UTF-8で検証しました。
確認した環境は LANG=ja_JP.UTF-8 で実施いたしました。
因みにですが、unixODBC Driver Manager ですが、もし Redhat セットアップ時にインストールされているものがございましたら
一度アンインストールしていただいた上で今回の手順で unixODBC Driver Manager をインストールしていただいておりますでしょうか。
と申しますのは、build_dm.sh でインストールする際に、config オプションにて “with-iconv-char-enc=UTF8 –with-iconv-ucode-enc=UTF16LE” が指定されておりますので
build_dm.sh でインストールした以外の unixODBC Driver Manager が影響している可能性があるかもしれないと思いまして。
既に環境を壊してしまったために、複数の unixODBC Driver Manager がそもそもインストールできるのかなどは確認できてはおりませんが、
上記についていま一度ご確認いただけますでしょうか。
よろしくお願いいたします。
Redhat セットアップ時にインストールしたものを利用しております。
アンインストールして確認してみます。ありがとうございました。
ところで、 セットアップ時にインストールされているunixODBC Driver Manager は非サポート等あるのでしょうか?
以下参考URLを記載しておりませんでしたので、本文に追加いたしました。
https://msdn.microsoft.com/ja-jp/library/hh568449(v=sql.110).aspx
こちらにて、既にインストールされている Driver Manager については削除いただくガイドとなっております。
また、もし build_dm.sh を使用せずに手動でインストールいただく際には、UnixODBC-2.3.2+ は現時点での Microsoft ODBC Driver 13 for SQL Server ではサポートされておりませんので、unixODBC-2.3.1 を入手いただき、上記URLの手動インストール手順をご参照の上、unixODBC Driver Manager をインストールしていただければと思います。
よろしくお願いいたします。