C++でのMySQLアクセス

c-mysqlのアイキャッチ画像 Windows

C++かつODBCドライバー経由でのMySQLアクセス方法を解説します。
山括弧<…>で囲まれている箇所は、ご自身の環境に合わせて書き換えて下さい。

MySQLのインストール

こちらからMySQL (mysql-installer-community-*.msi) をダウンロードします。
ダウンロードしたら同MSIファイルを実行し、インストールします。
インストール過程での設定は、すべてデフォルトのままで結構です。
ユーザーrootのパスワードはrootで設定した前提で進めます。

ODBC データソース アドミニストレーター > ドライバータブで、「MySQL ODBC <バージョン> UNICODE Driver」が存在していることを確認します。

C++でのMySQLアクセス

1. 前提

Visual Studio SDKを必要とします。
こちらからVisual Studioをダウンロード・インストールして下さい。

2. DB接続

以下のように実装し、MySQLに接続します。

short ret;

// DB接続情報
wchar_t* db_connection = L"DRIVER={MySQL ODBC <バージョン> Unicode Driver};SERVER=localhost;DATABASE=<DB名>;UID=root;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. SQL実行

以下のように実装し、MySQLに対して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クローズ

以下のように実装し、MySQLとの接続をクローズします。

if(hStmt){
    ::SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
}
if(hDbc){
    ::SQLDisconnect(hDbc);
    ::SQLFreeHandle(SQL_HANDLE_DBC, hDbc);
}
if(hEnv){
    ::SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
}

TIPS

SQL Serverについてはこちらをご覧下さい。

コメント

タイトルとURLをコピーしました