C++でSQLを埋め込む方法とODBC/JDBCの役割

C++でSQLクエリを実行するには、データベース接続ライブラリやORM(Object-Relational Mapping)フレームワークを利用するのが一般的です。これらのツールは、特定のDBMS(データベース管理システム)と連携するためのインターフェースを提供します。

ODBCによるSQL実行

ODBC(Open Database Connectivity)は、アプリケーションがさまざまなリレーショナルデータベースに標準化された方法でアクセスできるようにするAPI仕様です。C++では、sql.hsqlext.hといったヘッダをインクルードし、ODBC関数を使って接続・クエリ実行・結果処理を行います。

#include <sql.h>
#include <sqlext.h>

int main() {
    SQLHENV env;
    SQLHDBC dbc;
    SQLHSTMT stmt;
    SQLRETURN rc;

    // 環境ハンドル作成
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
    SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

    // 接続ハンドル作成と接続
    SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
    rc = SQLDriverConnect(dbc, nullptr,
        (SQLCHAR*)"DRIVER={ODBC Driver 17 for SQL Server};"
                  "SERVER=localhost;DATABASE=testdb;UID=user;PWD=pass;",
        SQL_NTS, nullptr, 0, nullptr, SQL_DRIVER_COMPLETE);

    if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) return -1;

    // ステートメントハンドル作成とクエリ実行
    SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
    SQLExecDirect(stmt, (SQLCHAR*)"SELECT product_name FROM products", SQL_NTS);

    // 結果の取得
    char buffer[256];
    while (SQLFetch(stmt) == SQL_SUCCESS) {
        SQLGetData(stmt, 1, SQL_C_CHAR, buffer, sizeof(buffer), nullptr);
        // buffer の内容を処理
    }

    // リソース解放
    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
    SQLDisconnect(dbc);
    SQLFreeHandle(SQL_HANDLE_DBC, dbc);
    SQLFreeHandle(SQL_HANDLE_ENV, env);

    return 0;
}

データベース固有のC++ライブラリの利用

多くのDBMSは、ODBCよりも高レベルなC++用クライアントライブラリを提供しています。たとえば、MySQL Connector/C++はC++ネイティブなインターフェースでMySQLとやり取りできます。

#include <mysql_driver.h>
#include <cppconn/connection.h>
#include <cppconn/statement.h>
#include <cppconn/resultset.h>

int main() {
    auto driver = get_driver_instance();
    std::unique_ptr<sql::Connection> conn(driver->connect("tcp://127.0.0.1:3306/testdb", "user", "pass"));
    std::unique_ptr<sql::Statement> stmt(conn->createStatement());
    std::unique_ptr<sql::ResultSet> res(stmt->executeQuery("SELECT name FROM employees"));

    while (res->next()) {
        // res->getString("name") で値を取得
    }
    return 0;
}

ORMフレームワークの活用

SOCIなどのORMライブラリを使うと、SQLを文字列として直接記述せずに、C++オブジェクトを通じてデータベース操作が可能です。これにより、型安全性やコードの可読性が向上します。

#include <soci/soci.h>
#include <soci/mysql/soci-mysql.h>

int main() {
    soci::session db(soci::mysql, "host=localhost;dbname=testdb;user=user;password=pass");

    std::string title;
    int id = 101;
    db << "SELECT book_title FROM books WHERE book_id = :id",
       soci::use(id), soci::into(title);

    // title に結果が格納される
    return 0;
}

ODBCとJDBCの概要とC++における役割

ODBCはマイクロソフトが提唱した、プラットフォームおよび言語に依存しないデータベース接続の標準です。C++アプリケーションはODBCドライバ経由で任意の対応DBMS(PostgreSQL、SQL Server、Oracleなど)に接続できます。ODBCは低レベルな制御が可能ですが、コードが冗長になりがちです。

JDBC(Java Database Connectivity)はJava向けの標準データベース接続APIであり、C++からは直接使用できません。ただし、JDBCの設計思想(ドライバマネージャ、ステートメント、結果セットなど)はODBCにも影響を与えており、両者は概念的に類似しています。

C++でのデータベースプログラミングにおいては、ODBCが最も汎用的な選択肢です。一方、パフォーマンスや開発効率を重視する場合は、データベース固有のC++ライブラリやSOCIのようなORMを採用することが多いです。選択は、プロジェクトの要件(移植性、保守性、実行速度など)に基づいて判断すべきです。

タグ: C++ ODBC SQL SOCI MySQL Connector/C++

6月7日 22:09 投稿