Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Berlaku untuk: SQL Server
Azure SQL Database
Dalam quickstart ini, Anda membangun aplikasi konsol C++ di Windows, Linux, atau macOS. Aplikasi terhubung ke AdventureWorksLT database dengan menggunakan Microsoft ODBC Driver 18 untuk SQL Server, mengikat parameter query, menjalankan query, dan membaca baris hasilnya.
Prerequisites
- Microsoft ODBC Driver 18 untuk SQL Server. Instal driver untuk Windows, Linux, atau macOS.
- Sebuah kompiler C++17 dan berkas pengembangan ODBC platform:
- Di Windows, instal Visual Studio 2022 atau Build Tools untuk Visual Studio 2022 dengan beban kerja pengembangan Desktop dengan C++. Windows SDK menyediakan header ODBC dan
odbc32.lib. - Di Linux, instal compiler C++ dan paket pengembangan unixODBC untuk distribusi Anda. Paket menyediakan header ODBC dan
libodbc. - Di macOS, instal alat baris perintah Xcode dan unixODBC dari Homebrew.
- Di Windows, instal Visual Studio 2022 atau Build Tools untuk Visual Studio 2022 dengan beban kerja pengembangan Desktop dengan C++. Windows SDK menyediakan header ODBC dan
- Sebuah database di Azure SQL Database atau SQL Server yang berisi
AdventureWorksLTdata contoh. Untuk Azure SQL Database, pilih sumber data Contoh saat Anda membuat satu basis data. Untuk SQL Server, pulihkan file cadanganAdventureWorksLTdari database sampel AdventureWorks.
Verifikasi driver tersebut
Pastikan driver manager dapat menemukan Microsoft ODBC Driver 18 untuk SQL Server.
Jalankan perintah ini di PowerShell:
Get-OdbcDriver -Name "ODBC Driver 18 for SQL Server"
Setiap perintah harus mencantumkan ODBC Driver 18 for SQL Server. Jika driver tidak tercantum, instal ulang sebelum melanjutkan.
Konfigurasikan koneksi
Aplikasi membaca seluruh string koneksi dari variabel lingkungan ODBC_CONNECTION_STRING. Aplikasi ini tidak menampilkan string koneksi atau menerimanya sebagai argumen baris perintah.
Gunakan string koneksi Driver 18 yang valid untuk database dan metode autentikasi Anda. Contoh autentikasi SQL berikut bekerja di Windows, Linux, dan macOS ketika database mengizinkan autentikasi SQL:
Driver={ODBC Driver 18 for SQL Server};Server=tcp:<server>,1433;Database=<database>;UID=<user_id>;PWD=<password>;Encrypt=yes;TrustServerCertificate=no;
Untuk opsi otentikasi Microsoft Entra, lihat Gunakan Microsoft Entra ID dengan driver ODBC. Untuk semua pengaturan yang didukung, lihat kata kunci dan atribut DSN serta string koneksi.
Microsoft ODBC Driver 18 mengaktifkan enkripsi secara default. Tentukan Encrypt=yes agar persyaratan aplikasi secara eksplisit. Biarkan TrustServerCertificate=no dalam mode produksi agar driver memvalidasi sertifikat server. Sertifikat harus mencocokkan nama server dan rantai dengan otoritas sertifikasi yang dipercaya oleh klien. Untuk panduan konfigurasi, lihat Kegagalan validasi sertifikat.
Caution
TrustServerCertificate=yes melewatkan validasi sertifikat. Gunakan hanya untuk pengembangan lokal terisolasi saat Anda mengonfigurasi sertifikat yang dipercaya klien. Jangan gunakan dalam produksi.
Atur variabel lingkungan tanpa menambahkan string koneksi ke riwayat shell Anda.
Buka Developer PowerShell untuk VS 2022. Jalankan perintah-perintah ini, lalu tempelkan string koneksi di prompt:
$secureConnectionString = Read-Host "ODBC connection string" -AsSecureString
$env:ODBC_CONNECTION_STRING = [System.Net.NetworkCredential]::new(
"", $secureConnectionString).Password
$secureConnectionString = $null
Variabel lingkungan menyimpan string koneksi di luar file sumber, tetapi proses tersebut dan proses turunannya dapat membacanya. Untuk aplikasi produksi, gunakan autentikasi Microsoft Entra jika memungkinkan dan ambil data rahasia dari penyimpanan aman saat aplikasi berjalan.
Buat aplikasi
Buat direktori proyek dan ubah ke direktori tersebut:
Buat file bernama
odbc-quickstart.cppdengan kode berikut:#ifdef _WIN32 #include <windows.h> #endif #include <sql.h> #include <sqlext.h> #include <sqltypes.h> #include <cstdlib> #include <iomanip> #include <iostream> #include <string> #include <string_view> 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 } bool PrintDiagnostics(SQLSMALLINT handleType, SQLHANDLE handle) { bool dataTruncated = false; 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'; if (std::string_view(reinterpret_cast<const char*>(state), 5) == "01004") dataTruncated = true; } return dataTruncated; } bool Succeeded(SQLRETURN result, SQLSMALLINT handleType, SQLHANDLE handle, bool* dataTruncated = nullptr) { if (result == SQL_SUCCESS) return true; const bool diagnosticReportsTruncation = PrintDiagnostics(handleType, handle); if (dataTruncated != nullptr) *dataTruncated = diagnosticReportsTruncation; return result == SQL_SUCCESS_WITH_INFO; } 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 (!Succeeded(result, SQL_HANDLE_ENV, handles.environment)) { 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 ((result = SQLFetch(handles.statement)) != SQL_NO_DATA) { if (!Succeeded(result, SQL_HANDLE_STMT, handles.statement)) return 1; SQLINTEGER productId = 0; SQLLEN productIdLength = 0; SQLCHAR productName[256] = {}; SQLLEN productNameLength = 0; result = SQLGetData( handles.statement, 1, SQL_C_SLONG, &productId, sizeof(productId), &productIdLength); if (!Succeeded(result, SQL_HANDLE_STMT, handles.statement)) return 1; bool productNameTruncated = false; result = SQLGetData( handles.statement, 2, SQL_C_CHAR, productName, sizeof(productName), &productNameLength); if (!Succeeded(result, SQL_HANDLE_STMT, handles.statement, &productNameTruncated)) return 1; std::string productNameText; if (productNameLength == SQL_NULL_DATA) { productNameText = "<NULL>"; } else if (productNameTruncated || productNameLength > static_cast<SQLLEN>(sizeof(productName) - 1)) { std::cerr << "Product name was truncated; no partial value was printed.\n"; return 1; } else if (productNameLength == SQL_NO_TOTAL) { std::cerr << "Product name length is unknown; no value was printed.\n"; return 1; } else if (productNameLength < 0) { std::cerr << "The driver returned an invalid product-name length.\n"; return 1; } else if (productNameLength == 0) { productNameText = "<empty>"; } else { productNameText.assign( reinterpret_cast<const char*>(productName), static_cast<std::size_t>(productNameLength)); } std::cout << std::left << std::setw(12) << productId << productNameText << '\n'; } return 0; }
Aplikasi ini hanya menggunakan API ODBC standar, sehingga menyertakan header driver-manager dan tautan ke pustaka driver-manager. string koneksi memilih Microsoft ODBC Driver 18 untuk SQL Server saat runtime.
SQL_DRIVER_NOPROMPT mencegah SQLDriverConnect membuka dialog konfigurasi. Jika string koneksi tidak lengkap, pemanggilan akan menghasilkan kesalahan dan aplikasi mencetak semua rekaman diagnostik. Aplikasi ini juga mencetak diagnostik saat panggilan ODBC yang diperiksa mengembalikan SQL_SUCCESS_WITH_INFO, yang berarti panggilan berhasil dengan peringatan.
Kueri mengikat 0 sebagai parameter SQL Server int, membaca lima produk pertama dari SalesLT.Product, dan mengambil setiap ID produk serta namanya dengan SQLGetData. Untuk nama produk, aplikasi menampilkan <NULL> untuk SQL_NULL_DATA dan <empty> untuk nilai nol panjang. Jika SQLGetData melaporkan SQLSTATE 01004, panjang yang tidak diketahui, atau panjang yang lebih besar dari buffer, aplikasi melaporkan masalah dan keluar tanpa mencetak nama sebagian.
Membangun dan menjalankan aplikasi
Di jendela Developer PowerShell yang sama, kompilasi aplikasi:
cl /std:c++17 /EHsc /W4 odbc-quickstart.cpp /link odbc32.libJalankan aplikasi:
.\odbc-quickstart.exe
Output standar aplikasi adalah:
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
Hapus string koneksi setelah selesai.