Hızlı Başlangıç: Microsoft OLE DB Sürücüsü ile bağlanın ve sorgulayın

Bu hızlı başlangıçta, Visual Studio 2022 ve daha sonraki sürümlerle bir Windows C++ konsol uygulaması oluşturuyorsunuz. Uygulama, Azure SQL Veritabanı'e, Microsoft Fabric'teki SQL veritabanına veya SQL Server'a SQL Server için Microsoft OLE DB Driver 19 aracılığıyla bağlanır. Örnek veriye göre parametreli bir sorgu AdventureWorksLT çalıştırır ve sonucu doğrular.

Prerequisites

SQL veritabanı oluşturma

Aşağıdaki platformlardan birinde bir SQL veritabanı oluşturun veya bağlanın:

Bu hızlı başlatma için örnek veriyi seçin veya yükleyin AdventureWorksLT .

Bir SQL Server konteyneri için, konteyneri oluşturun ve örnek veriyi tek bir komutla yükleyin:

sqlcmd create mssql --accept-eula --using https://aka.ms/AdventureWorksLT.bak

Mevcut bir SQL Server örneği için, AdventureWorks örnek veritabanlarından bir AdventureWorksLT yedeklemeyi geri getirin.

Bu hızlı başlangıçtaki OLE DB istemci uygulaması Windows'ta çalışır. Bir SQL Server konteyneri, desteklenen başka bir ana bilgisayarda çalışabilir.

Sürücüyü doğrulayın

Visual Studio sürümünüz için bir x64 Native Tools Komut İstemi açın ve ardından aşağıdaki komutu çalıştırın:

Important

Bu hızlı başlangıçtaki komutlar Komut Mesajı sözdizimi kullanır. Bunları, komut istemi satırının sonu > ile biten bir x64 Native Tools Komut İstemi'nde çalıştırın. İstemin PS ile başladığı PowerShell'de bunları çalıştırmayın.

reg query HKCR\MSOLEDBSQL19

Komut kayıtlı MSOLEDBSQL19 sağlayıcıyı gösterir.

Bağlantıyı yapılandırma

OLEDB_CONNECTION_STRING öğesini x64 Native Tools Komut İstemi’nde ayarlayın. Uygulama, bağlantı dizesi'i ortamdan okur ve göstermez.

Azure SQL Veritabanı veya Fabric'teki SQL database için Microsoft Entra interaktif kimlik doğrulamasını kullanın. Yer tutucuları SQL kaynağınızdaki sunucu, veritabanı ve Microsoft Entra kullanıcı kimliğiyle değiştirin:

set "OLEDB_CONNECTION_STRING=Provider=MSOLEDBSQL19;Data Source=tcp:<server>,1433;Initial Catalog=<database>;Authentication=ActiveDirectoryInteractive;User ID=<user_id>;Use Encryption for Data=Mandatory;Trust Server Certificate=false;"

Fabric'teki SQL veritabanı için, kimliğinizin veritabanı öğesi için Okuma iznine sahip olması gerekir. SQL kimlik doğrulaması desteklenmiyor. Daha fazla bilgi için bkz. Microsoft Fabric'te SQL veritabanında Kimlik Doğrulama.

Windows Kimlik Doğrulamasını kabul eden mevcut bir SQL Server örneği için şunları kullanınIntegrated Security=SSPI:

set "OLEDB_CONNECTION_STRING=Provider=MSOLEDBSQL19;Data Source=tcp:<server>,1433;Initial Catalog=<database>;Integrated Security=SSPI;Use Encryption for Data=Mandatory;Trust Server Certificate=false;"

SQL kimlik doğrulamasını kabul eden bir SQL Server örneği veya konteyneri için Authentication=SqlPassword:

set "OLEDB_USER_ID=<user_id>"
set "OLEDB_PASSWORD=<password>"
set "OLEDB_CONNECTION_STRING=Provider=MSOLEDBSQL19;Data Source=tcp:<server>,1433;Initial Catalog=<database>;Authentication=SqlPassword;User ID=%OLEDB_USER_ID%;Password=%OLEDB_PASSWORD%;Use Encryption for Data=Mandatory;Trust Server Certificate=false;"

SQL Server sertifikası, sunucu adını ve zincirini Windows istemcisinin güvendiği bir sertifikasyon otoritesi (CA) ile eşleştirmelidir. Bir SQL Server konteyneri için, Taşıma Katmanı Güvenliği'ni (TLS) konteynerde yapılandırın ve uygulamayı çalıştırmadan önce veren CA'yı Windows istemcisine kaydedin. Daha fazla bilgi için, bağlantıları şifreleme Linux üzerinde SQL Server ve Configure SQL Server Database Engine for encrypting connections bölümlerine bakabilirsiniz.

Uygulamayı oluşturma

  1. Bir proje dizini oluşturun:

    mkdir oledb-quickstart
    cd oledb-quickstart
    
  2. Aşağıdaki kodla adlı oledb-quickstart.cpp bir dosya oluşturun:

    #include <windows.h>
    #include <oledb.h>
    #include <msdasc.h>
    #include <msoledbsql.h>
    
    #include <cstddef>
    #include <iomanip>
    #include <iostream>
    #include <string>
    
    template <typename T>
    void Release(T*& pointer)
    {
        if (pointer != nullptr)
        {
            pointer->Release();
            pointer = nullptr;
        }
    }
    
    struct ParameterData
    {
        DBSTATUS status;
        DBLENGTH length;
        LONG value;
    };
    
    constexpr std::size_t productNameCharacters = 51;
    
    struct RowData
    {
        DBSTATUS productIdStatus;
        DBLENGTH productIdLength;
        LONG productId;
        DBSTATUS nameStatus;
        DBLENGTH nameLength;
        wchar_t name[productNameCharacters];
    };
    
    std::wstring ReadEnvironmentVariable(const wchar_t* name)
    {
        const DWORD length = GetEnvironmentVariableW(name, nullptr, 0);
        if (length == 0)
            return {};
    
        std::wstring value(length, L'\0');
        const DWORD copied = GetEnvironmentVariableW(
            name,
            value.data(),
            length);
        if (copied == 0 || copied >= length)
            return {};
    
        value.resize(copied);
        return value;
    }
    
    int wmain()
    {
        const std::wstring connectionString =
            ReadEnvironmentVariable(L"OLEDB_CONNECTION_STRING");
        if (connectionString.empty())
        {
            std::wcerr << L"Set OLEDB_CONNECTION_STRING before running.\n";
            return 1;
        }
    
        HRESULT result = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
        if (FAILED(result))
        {
            std::wcerr << L"COM initialization failed: 0x"
                       << std::hex << result << L'\n';
            return 1;
        }
    
        IDataInitialize* dataInitialize = nullptr;
        IDBInitialize* dbInitialize = nullptr;
        IDBCreateSession* createSession = nullptr;
        IDBCreateCommand* createCommand = nullptr;
        ICommandText* commandText = nullptr;
        ICommandWithParameters* commandParameters = nullptr;
        IAccessor* parameterAccessor = nullptr;
        IRowset* rowset = nullptr;
        IAccessor* rowAccessor = nullptr;
        HACCESSOR parameterHandle = DB_NULL_HACCESSOR;
        HACCESSOR rowHandle = DB_NULL_HACCESSOR;
        HROW* rows = nullptr;
        DBCOUNTITEM rowCount = 0;
        bool initialized = false;
    
        do
        {
            result = CoCreateInstance(
                CLSID_MSDAINITIALIZE,
                nullptr,
                CLSCTX_INPROC_SERVER,
                IID_IDataInitialize,
                reinterpret_cast<void**>(&dataInitialize));
            if (FAILED(result))
                break;
    
            result = dataInitialize->GetDataSource(
                nullptr,
                CLSCTX_INPROC_SERVER,
                connectionString.c_str(),
                IID_IDBInitialize,
                reinterpret_cast<IUnknown**>(&dbInitialize));
            if (FAILED(result))
                break;
    
            result = dbInitialize->Initialize();
            if (FAILED(result))
                break;
            initialized = true;
    
            result = dbInitialize->QueryInterface(
                IID_IDBCreateSession,
                reinterpret_cast<void**>(&createSession));
            if (FAILED(result))
                break;
    
            result = createSession->CreateSession(
                nullptr,
                IID_IDBCreateCommand,
                reinterpret_cast<IUnknown**>(&createCommand));
            if (FAILED(result))
                break;
    
            result = createCommand->CreateCommand(
                nullptr,
                IID_ICommandText,
                reinterpret_cast<IUnknown**>(&commandText));
            if (FAILED(result))
                break;
    
            result = commandText->SetCommandText(
                DBGUID_DBSQL,
                const_cast<wchar_t*>(
                    L"SELECT TOP (5) ProductID, Name "
                    L"FROM SalesLT.Product "
                    L"WHERE ProductID > ? "
                    L"ORDER BY ProductID;"));
            if (FAILED(result))
                break;
    
            result = commandText->QueryInterface(
                IID_ICommandWithParameters,
                reinterpret_cast<void**>(&commandParameters));
            if (FAILED(result))
                break;
    
            DB_UPARAMS parameterOrdinal = 1;
            wchar_t parameterType[] = L"int";
            DBPARAMBINDINFO parameterInfo = {};
            parameterInfo.pwszDataSourceType = parameterType;
            parameterInfo.ulParamSize = sizeof(LONG);
            parameterInfo.dwFlags = DBPARAMFLAGS_ISINPUT;
            parameterInfo.bPrecision = 10;
    
            result = commandParameters->SetParameterInfo(
                1,
                &parameterOrdinal,
                &parameterInfo);
            if (FAILED(result))
                break;
    
            result = commandText->QueryInterface(
                IID_IAccessor,
                reinterpret_cast<void**>(&parameterAccessor));
            if (FAILED(result))
                break;
    
            DBBINDING parameterBinding = {};
            parameterBinding.iOrdinal = 1;
            parameterBinding.obStatus = offsetof(ParameterData, status);
            parameterBinding.obLength = offsetof(ParameterData, length);
            parameterBinding.obValue = offsetof(ParameterData, value);
            parameterBinding.dwPart = DBPART_STATUS | DBPART_LENGTH | DBPART_VALUE;
            parameterBinding.dwMemOwner = DBMEMOWNER_CLIENTOWNED;
            parameterBinding.eParamIO = DBPARAMIO_INPUT;
            parameterBinding.cbMaxLen = sizeof(LONG);
            parameterBinding.wType = DBTYPE_I4;
            parameterBinding.bPrecision = 10;
    
            DBBINDSTATUS parameterBindStatus = DBBINDSTATUS_OK;
            result = parameterAccessor->CreateAccessor(
                DBACCESSOR_PARAMETERDATA,
                1,
                &parameterBinding,
                sizeof(ParameterData),
                &parameterHandle,
                &parameterBindStatus);
            if (FAILED(result) || parameterBindStatus != DBBINDSTATUS_OK)
            {
                if (SUCCEEDED(result))
                    result = E_FAIL;
                break;
            }
    
            ParameterData parameter = {
                DBSTATUS_S_OK,
                sizeof(LONG),
                0
            };
            DBPARAMS parameters = {
                &parameter,
                1,
                parameterHandle
            };
    
            result = commandText->Execute(
                nullptr,
                IID_IRowset,
                &parameters,
                nullptr,
                reinterpret_cast<IUnknown**>(&rowset));
            if (FAILED(result))
                break;
    
            result = rowset->QueryInterface(
                IID_IAccessor,
                reinterpret_cast<void**>(&rowAccessor));
            if (FAILED(result))
                break;
    
            DBBINDING rowBindings[2] = {};
            rowBindings[0].iOrdinal = 1;
            rowBindings[0].obStatus = offsetof(RowData, productIdStatus);
            rowBindings[0].obLength = offsetof(RowData, productIdLength);
            rowBindings[0].obValue = offsetof(RowData, productId);
            rowBindings[0].dwPart =
                DBPART_STATUS | DBPART_LENGTH | DBPART_VALUE;
            rowBindings[0].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
            rowBindings[0].eParamIO = DBPARAMIO_NOTPARAM;
            rowBindings[0].cbMaxLen = sizeof(LONG);
            rowBindings[0].wType = DBTYPE_I4;
            rowBindings[0].bPrecision = 10;
    
            rowBindings[1].iOrdinal = 2;
            rowBindings[1].obStatus = offsetof(RowData, nameStatus);
            rowBindings[1].obLength = offsetof(RowData, nameLength);
            rowBindings[1].obValue = offsetof(RowData, name);
            rowBindings[1].dwPart =
                DBPART_STATUS | DBPART_LENGTH | DBPART_VALUE;
            rowBindings[1].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
            rowBindings[1].eParamIO = DBPARAMIO_NOTPARAM;
            rowBindings[1].cbMaxLen =
                productNameCharacters * sizeof(wchar_t);
            rowBindings[1].wType = DBTYPE_WSTR;
    
            DBBINDSTATUS rowBindStatus[2] = {
                DBBINDSTATUS_OK,
                DBBINDSTATUS_OK
            };
            result = rowAccessor->CreateAccessor(
                DBACCESSOR_ROWDATA,
                2,
                rowBindings,
                sizeof(RowData),
                &rowHandle,
                rowBindStatus);
            if (FAILED(result) ||
                rowBindStatus[0] != DBBINDSTATUS_OK ||
                rowBindStatus[1] != DBBINDSTATUS_OK)
            {
                if (SUCCEEDED(result))
                    result = E_FAIL;
                break;
            }
    
            DBCOUNTITEM productsPrinted = 0;
            while (true)
            {
                result = rowset->GetNextRows(
                    DB_NULL_HCHAPTER,
                    0,
                    1,
                    &rowCount,
                    &rows);
                if (FAILED(result) || rowCount == 0)
                    break;
    
                RowData row = {};
                result = rowset->GetData(rows[0], rowHandle, &row);
                if (FAILED(result) ||
                    row.productIdStatus != DBSTATUS_S_OK ||
                    row.productIdLength != sizeof(LONG) ||
                    row.nameStatus != DBSTATUS_S_OK ||
                    row.nameLength == 0 ||
                    row.nameLength % sizeof(wchar_t) != 0 ||
                    row.nameLength >= sizeof(row.name))
                {
                    result = E_FAIL;
                    break;
                }
                row.name[row.nameLength / sizeof(wchar_t)] = L'\0';
    
                if (productsPrinted == 0)
                {
                    std::wcout << L"Connected with MSOLEDBSQL19.\n\n";
                    std::wcout << std::left
                               << std::setw(12) << L"Product ID"
                               << L"Name\n";
                    std::wcout << std::setw(12) << L"----------"
                               << L"----\n";
                }
    
                std::wcout << std::left
                           << std::setw(12) << row.productId
                           << row.name << L'\n';
                ++productsPrinted;
    
                result = rowset->ReleaseRows(
                    rowCount,
                    rows,
                    nullptr,
                    nullptr,
                    nullptr);
                CoTaskMemFree(rows);
                rows = nullptr;
                rowCount = 0;
                if (FAILED(result))
                    break;
            }
    
            if (FAILED(result))
                break;
            if (productsPrinted == 0)
            {
                result = E_FAIL;
                break;
            }
        }
        while (false);
    
        if (rows != nullptr)
        {
            if (rowset != nullptr && rowCount != 0)
                rowset->ReleaseRows(rowCount, rows, nullptr, nullptr, nullptr);
            CoTaskMemFree(rows);
        }
        if (rowHandle != DB_NULL_HACCESSOR && rowAccessor != nullptr)
            rowAccessor->ReleaseAccessor(rowHandle, nullptr);
        if (parameterHandle != DB_NULL_HACCESSOR && parameterAccessor != nullptr)
            parameterAccessor->ReleaseAccessor(parameterHandle, nullptr);
    
        Release(rowAccessor);
        Release(rowset);
        Release(parameterAccessor);
        Release(commandParameters);
        Release(commandText);
        Release(createCommand);
        Release(createSession);
        if (initialized)
            dbInitialize->Uninitialize();
        Release(dbInitialize);
        Release(dataInitialize);
        CoUninitialize();
    
        if (FAILED(result))
        {
            std::wcerr << L"OLE DB operation failed: 0x"
                       << std::hex << result << L'\n';
            return 1;
        }
    
        return 0;
    }
    

Bağlantı dizesi IDataInitialize::GetDataSource öğesine iletilir. Bu API, aralıklı anahtar kelime isimlerini Use Encryption for Data kullanır ve Trust Server Certificate. Bağlantı dizileri şifreleme talep eder ve sertifika doğrulaması gerektirir.

Sorgu, parametre işareti olarak soru işareti kullanır. Uygulama, minimum ürün kimliğini 0 bir SQL Server int olarak bağlar, SalesLT.Product içinden en fazla beş satır okur ve ürün kimliğini ve adını yazdırır.

Uygulamayı derleme ve çalıştırma

  1. Aynı x64 Native Tools Komut Açarı'nda kurulu OLE DB SDK başlığını bulun ve dizinini şu adreste OLEDB_INCLUDEkaydedin:

    for /f "delims=" %i in ('where /r "%ProgramFiles%\Microsoft SQL Server\Client SDK\OLEDB" msoledbsql.h') do for %j in ("%~dpi.") do set "OLEDB_INCLUDE=%~fj"
    
  2. Seçilen dizini gösterin ve başlığı içerdiğinden emin olun:

    echo %OLEDB_INCLUDE%
    dir "%OLEDB_INCLUDE%\msoledbsql.h"
    
  3. Uygulamayı derleyin:

    cl /std:c++17 /EHsc /W4 /I"%OLEDB_INCLUDE%" oledb-quickstart.cpp /link ole32.lib oleaut32.lib
    
  4. Uygulamayı çalıştırın:

    oledb-quickstart.exe
    
  5. Mevcut Komut Diziminden bağlantı dizesi'i temizleyin:

    set OLEDB_CONNECTION_STRING=
    set OLEDB_USER_ID=
    set OLEDB_PASSWORD=
    

Ürün sıraları AdventureWorksLT sürümüne göre değişebilir. Çıkış aşağıdaki örneğe benzer:

Connected with MSOLEDBSQL19.

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