適用対象:SQL Server
Azure SQL データベース
このクイックスタートでは、Windows、Linux、macOS上でC++コンソールアプリケーションを構築します。 アプリケーションは、Microsoft ODBC Driver 18 for SQL Server を使用して AdventureWorksLT データベースに接続し、クエリ パラメーターをバインドし、クエリを実行し、結果行を読み取ります。
前提条件
- Microsoft ODBC Driver 18 for SQL Server. Windows、Linux、macOS用のドライバーをインストールしてください。
- C++17コンパイラとプラットフォームのODBC開発ファイル:
- Windowsでは、Visual Studio 2022またはデスクトップ開発(C++対応)ワークロードでVisual Studio 2022のビルドツールをインストールしてください。 Windows SDKはODBCヘッダーと
odbc32.libを提供します。 - Linuxでは、C++コンパイラとunixODBC開発パッケージをインストールしてください。 パッケージはODBCヘッダーと
libodbcを供給します。 - macOSでは、XcodeコマンドラインツールとHomebrewからunixODBCをインストールしてください。
- Windowsでは、Visual Studio 2022またはデスクトップ開発(C++対応)ワークロードでVisual Studio 2022のビルドツールをインストールしてください。 Windows SDKはODBCヘッダーと
- Azure SQL DatabaseまたはSQL Serverのデータベースで、
AdventureWorksLTサンプルデータを含むものです。 Azure SQL Databaseの場合は、単一のデータベースを作成する際にサンプルデータソースを選択してください。 SQL Serverは、AdventureWorksのサンプルデータベースからAdventureWorksLTバックアップを復元してください。
運転手の確認を
ドライバーマネージャーでMicrosoft ODBC Driver 18 for SQL Serverが見つかるか確認してください。
各コマンドは ODBC Driver 18 for SQL Serverをリストにすべきです。 ドライバーがリストにない場合は、先にインストールしてから続けてください。
接続の設定
アプリケーションはODBC_CONNECTION_STRING環境変数から完全な接続文字列を読み込みます。 接続文字列を表示せず、コマンドラインの引数として受け入れられません。
データベースと認証方法に有効なDriver 18の接続文字列を使いましょう。 以下のSQL認証の例は、データベースがSQL認証を許可している場合、Windows、Linux、macOSで動作します。
Driver={ODBC Driver 18 for SQL Server};Server=tcp:<server>,1433;Database=<database>;UID=<user_id>;PWD=<password>;Encrypt=yes;TrustServerCertificate=no;
Microsoft Entraの認証オプションについては、「ODBCドライバーでMicrosoft Entra IDを使用する」をご覧ください。 すべての対応設定については、DSNおよび接続文字列キーワードおよび属性を参照してください。
Microsoft ODBC Driver 18はデフォルトで暗号化を有効にしています。
Encrypt=yes を指定して、アプリケーションの要件を明示的にしてください。
TrustServerCertificate=no本番環境で保持して、ドライバーがサーバー証明書を検証します。 証明書はサーバー名とチェーンをクライアントが信頼する認証機関と一致しなければなりません。 設定ガイダンスについては、 証明書検証失敗を参照してください。
Caution
TrustServerCertificate=yes 証明書の検証を省略します。 クライアントが信頼する証明書を設定する間、ローカル開発の孤立した用途にのみ使ってください。 運用環境では使用しないでください。
環境変数は、接続文字列をシェル履歴に追加せずに設定してください。
VS 2022用のOpen Developer PowerShell。 これらのコマンドを実行し、プロンプトの接続文字列を貼り付けてください:
$secureConnectionString = Read-Host "ODBC connection string" -AsSecureString
$env:ODBC_CONNECTION_STRING = [System.Net.NetworkCredential]::new(
"", $secureConnectionString).Password
$secureConnectionString = $null
環境変数は接続文字列をソースファイルから除外しますが、プロセスとその子プロセスはそれを読み取ることができます。 本番アプリケーションでは可能な限りMicrosoft Entra認証を使用し、実行時に安全なストアから秘密を取得します。
アプリケーションを作成する
プロジェクトディレクトリを作成し、それに変更してください:
次のコードを使用して、
odbc-quickstart.cppという名前のファイルを作成します。#ifdef _WIN32 #include <windows.h> #endif #include <sql.h> #include <sqlext.h> #include <sqltypes.h> #include <cstdlib> #include <iomanip> #include <iostream> #include <string> std::string ReadEnvironmentVariable(const char* name) { #ifdef _WIN32 char* value = nullptr; std::size_t length = 0; if (_dupenv_s(&value, &length, name) != 0 || value == nullptr) return {}; std::string result(value); std::free(value); return result; #else const char* value = std::getenv(name); return value == nullptr ? std::string{} : value; #endif } void PrintDiagnostics(SQLSMALLINT handleType, SQLHANDLE handle) { SQLCHAR state[6]; SQLINTEGER nativeError; SQLCHAR message[SQL_MAX_MESSAGE_LENGTH]; SQLSMALLINT messageLength; for (SQLSMALLINT record = 1; SQL_SUCCEEDED(SQLGetDiagRec(handleType, handle, record, state, &nativeError, message, sizeof(message), &messageLength)); ++record) { std::cerr << '[' << state << "] (" << nativeError << ") " << message << '\n'; } } bool Succeeded(SQLRETURN result, SQLSMALLINT handleType, SQLHANDLE handle) { if (SQL_SUCCEEDED(result)) return true; PrintDiagnostics(handleType, handle); return false; } struct OdbcHandles { SQLHENV environment = SQL_NULL_HENV; SQLHDBC connection = SQL_NULL_HDBC; SQLHSTMT statement = SQL_NULL_HSTMT; ~OdbcHandles() { if (statement != SQL_NULL_HSTMT) SQLFreeHandle(SQL_HANDLE_STMT, statement); if (connection != SQL_NULL_HDBC) { SQLDisconnect(connection); SQLFreeHandle(SQL_HANDLE_DBC, connection); } if (environment != SQL_NULL_HENV) SQLFreeHandle(SQL_HANDLE_ENV, environment); } }; int main() { std::string connectionString = ReadEnvironmentVariable("ODBC_CONNECTION_STRING"); if (connectionString.empty()) { std::cerr << "Set ODBC_CONNECTION_STRING before running.\n"; return 1; } OdbcHandles handles; SQLRETURN result = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &handles.environment); if (!SQL_SUCCEEDED(result)) { std::cerr << "Unable to allocate an ODBC environment handle.\n"; return 1; } result = SQLSetEnvAttr( handles.environment, SQL_ATTR_ODBC_VERSION, reinterpret_cast<SQLPOINTER>(SQL_OV_ODBC3_80), 0); if (!Succeeded(result, SQL_HANDLE_ENV, handles.environment)) return 1; result = SQLAllocHandle( SQL_HANDLE_DBC, handles.environment, &handles.connection); if (!Succeeded(result, SQL_HANDLE_ENV, handles.environment)) return 1; result = SQLDriverConnect( handles.connection, nullptr, reinterpret_cast<SQLCHAR*>(connectionString.data()), SQL_NTS, nullptr, 0, nullptr, SQL_DRIVER_NOPROMPT); if (!Succeeded(result, SQL_HANDLE_DBC, handles.connection)) return 1; result = SQLAllocHandle( SQL_HANDLE_STMT, handles.connection, &handles.statement); if (!Succeeded(result, SQL_HANDLE_DBC, handles.connection)) return 1; SQLINTEGER minimumProductId = 0; SQLLEN minimumProductIdLength = 0; result = SQLBindParameter( handles.statement, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 10, 0, &minimumProductId, 0, &minimumProductIdLength); if (!Succeeded(result, SQL_HANDLE_STMT, handles.statement)) return 1; SQLCHAR query[] = "SELECT TOP (5) ProductID, Name " "FROM SalesLT.Product " "WHERE ProductID > ? " "ORDER BY ProductID;"; result = SQLExecDirect(handles.statement, query, SQL_NTS); if (!Succeeded(result, SQL_HANDLE_STMT, handles.statement)) return 1; std::cout << "Product ID Name\n" << "---------- ----\n"; while (SQL_SUCCEEDED(result = SQLFetch(handles.statement))) { SQLINTEGER productId; SQLLEN productIdLength; SQLCHAR productName[256]; SQLLEN productNameLength; result = SQLGetData( handles.statement, 1, SQL_C_SLONG, &productId, sizeof(productId), &productIdLength); if (!Succeeded(result, SQL_HANDLE_STMT, handles.statement)) return 1; result = SQLGetData( handles.statement, 2, SQL_C_CHAR, productName, sizeof(productName), &productNameLength); if (!Succeeded(result, SQL_HANDLE_STMT, handles.statement)) return 1; std::cout << std::left << std::setw(12) << productId << productName << '\n'; } if (result != SQL_NO_DATA) { PrintDiagnostics(SQL_HANDLE_STMT, handles.statement); return 1; } return 0; }
アプリケーションは標準のODBC APIのみを使用しているため、ドライバーマネージャーのヘッダーとドライバーマネージャーライブラリへのリンクが含まれています。 接続文字列は実行時にMicrosoft ODBCドライバー18 for SQL Serverを選択します。
SQL_DRIVER_NOPROMPT
SQLDriverConnect設定ダイアログを開くことを阻止します。 接続文字列が不完全の場合、呼び出しはエラーを返し、アプリケーションはすべての診断レコードを印刷します。
クエリは0をSQL Server intパラメータとしてバインドし、最初の5つの製品をSalesLT.Productで読み取り、各製品IDと名前をSQLGetDataで取得します。
アプリケーションの構築と実行
同じ開発者PowerShellウィンドウでアプリケーションをコンパイルします:
cl /std:c++17 /EHsc /W4 odbc-quickstart.cpp /link odbc32.libアプリケーションを実行します。
.\odbc-quickstart.exe
アプリケーションの標準出力は以下の通りです:
Product ID Name
---------- ----
680 HL Road Frame - Black, 58
706 HL Road Frame - Red, 58
707 Sport-100 Helmet, Red
708 Sport-100 Helmet, Black
709 Mountain Bike Socks, M
完了したら、接続文字列をクリアしてください。