C++かつODBCドライバー経由でのSQL Serverアクセス方法を解説します。
山括弧<…>で囲まれている箇所は、ご自身の環境に合わせて書き換えて下さい。
SQL Serverのインストール
こちらを参考にSQL Serverをインストールします。
DBインスタンス名はSQLExpress、ユーザーsaのパスワードはrootで設定した前提で進めます。
ODBC データソース アドミニストレーター > ドライバータブで、「ODBC Driver <バージョン> for SQL Server」が存在していることを確認します。
C++でのSQL Serverアクセス
1. 前提
Visual Studio SDKを必要とします。
こちらからVisual Studioをダウンロード・インストールして下さい。
2. DB接続
以下のように実装し、SQL Serverに接続します。
short ret;
// DB接続情報
wchar_t* db_connection = L"DRIVER={ODBC Driver <バージョン> for SQL Server};SERVER=localhost\\SQLEXPRESS;DATABASE=<DB名>;UID=sa;PWD=root";
void* hEnv = NULL; // 環境ハンドル
void* hDbc = NULL; // DB接続ハンドル
void* hStmt = NULL; // ステートメントハンドル
// 環境ハンドル
if((ret = ::SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv)) == SQL_ERROR){
// error
}
if((ret = ::SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, reinterpret_cast<SQLPOINTER>(SQL_OV_ODBC3), 0)) != SQL_SUCCESS){
// error
}
// DB接続ハンドル
if((ret = ::SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDbc)) != SQL_SUCCESS){
// error
}
// タイムアウト設定
if((ret = ::SQLSetConnectAttrW(hDbc, SQL_LOGIN_TIMEOUT, reinterpret_cast<SQLPOINTER>(5), 0)) != SQL_SUCCESS){
// error
}
// コミットモード設定
if((ret = ::SQLSetConnectAttrW(hDbc, SQL_ATTR_AUTOCOMMIT, reinterpret_cast<SQLPOINTER>(SQL_AUTOCOMMIT_ON), 0)) != SQL_SUCCESS){
// error
}
// DB接続
if((ret = ::SQLDriverConnectW(hDbc, NULL, reinterpret_cast<SQLWCHAR *>(db_connection), SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE)) != SQL_SUCCESS){
// error
}
// ステートメントハンドル
if((ret = ::SQLAllocHandle(SQL_HANDLE_STMT, hDbc, &hStmt)) != SQL_SUCCESS){
// error
}
3. DB接続
以下のように実装し、SQL Serverに対してSQLを実行します。
short ret;
short cols;
wchar_t* sql = L"<任意のSQL>";
struct col_t{ // カラム情報
wchar_t* name; // カラム名
wchar_t* value; // データ(bind用)
long width; // カラムデータ幅
long_name_width; // カラム名幅
long type; // データタイプ
long exist; // データ有無
}
// SQL実行
if((ret = ::SQLExecDirectW(hStmt, reinterpret_cast<SQLWCHAR *>(sql), SQL_NTS)) != SQL_SUCCESS){
// error
}
// 応答データのカラム数取得
if((ret = ::SQLNumResultCols(hStmt, &cols)) != SQL_SUCCESS){
// error
}
// 応答データの各カラム情報取得
std::vector<col_t> cCols;
for(short col = 1; col <= cols; col++){
col_t tCol;
// データ幅取得
if((ret = ::SQLColAttributeW(hStmt, col, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, &tCol.width)) != SQL_SUCCESS){
// error
}
// データ種別取得
if((ret = ::SQLColAttributeW(hStmt, col, SQL_DESC_CONCISE_TYPE, NULL, 0, NULL, &tCol.type)) != SQL_SUCCESS){
// error
}
// データカーソルの結び付け ※①
tCol.value = new wchar_t[width+2]; // +2は終端文字用(WindowsのUNICODEは2byte)
tCol.value[width] = 0;
if((ret = ::SQLBindCol(hStmt, col, SQL_UNICODE_CHAR, reinterpret_cast<SQLPOINTER>(tCol.value), (tCol.width+1) * sizeof(wchar_t), &tCol.exist)) != SQL_SUCCESS){
// error
}
// カラム名幅取得
if((ret = ::SQLColAttributeW(hStmt, col, SQL_DESC_NAME, NULL, 0, &tCol.name_width, NULL)) != SQL_SUCCESS){
// error
}
// カラム名取得
tCol.name = new wchar_t[tCol.name_width+2]; // +2は終端文字用(WindowsのUNICODEは2byte)
tCol.name[tCol.name_width] = 0;
if((ret = ::SQLColAttributeW(hStmt, col, SQL_DESC_NAME, tCol.name, (tCol.name_width+1) * sizeof(wchar_t), NULL, NULL)) != SQL_SUCCESS){
// error
}
// カラム情報格納
cCols.push_back(tCol);
}
// 応答データの各レコード情報取得
std::vector<std::vector<col_t>> cRecords;
while(true){
std::vector<col_t> cRecord;
// 1レコード取得
if((ret = ::SQLFetch(hStmt)) != SQL_SUCCESS){ // ここで※①のcol_t::valueに実データが格納される
if(ret == SQL_NO_DATA_FOUND){
// もうデータは無い
break;
}else{
// error
}
}
// レコード情報格納
cRecords.push_back(cRecord);
}
4. DBクローズ
以下のように実装し、SQL Serverとの接続をクローズします。
if(hStmt){
::SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
}
if(hDbc){
::SQLDisconnect(hDbc);
::SQLFreeHandle(SQL_HANDLE_DBC, hDbc);
}
if(hEnv){
::SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
}
TIPS
MySQLについてはこちらをご覧下さい。
コメント