Rövid útmutató: Csatlakozás és lekérdezés C++ és ODBC használatával

A következőkre vonatkozik:SQL ServerAzure SQL Database

Ebben a gyorsindításban C++ konzol alkalmazást építesz Windows-on, Linuxon vagy macOS-en. Az alkalmazás az Microsoft ODBC Driver 18 for SQL Server segítségével csatlakozik egy AdventureWorksLT adatbázishoz, egy lekérdezési paramétert köt, lefuttatja a lekérdezést, és felolvassa az eredménysorokat.

Prerequisites

  • Microsoft ODBC Driver 18 for SQL Server. Telepítsd a drivert Windows-ra, Linuxra vagy macOS-re.
  • Egy C++17 fordító és a platform ODBC fejlesztői fájljai:
    • Windows-on telepítsd a Visual Studio 2022-t vagy a Build Tools for Visual Studio 2022-t a C++ munkaterheléssel rendelkező asztali fejlesztéssel. A Windows SDK tartalmazza az ODBC-fejléceket és a(z) odbc32.lib elemet.
    • Linuxon telepíts egy C++ fordítót és az unixODBC fejlesztő csomagot a disztribúciódhoz. A csomag tartalmazza az ODBC fejlécfájlokat és a(z) libodbc elemet.
    • macOS-en telepítsd az Xcode parancssori eszközöket és az unixODBC-t a Homebrew-ből.
  • Egy adatbázis Azure SQL Database-ben vagy SQL Server-ben, amely tartalmazza a AdventureWorksLT mintaadatokat. Azure SQL Database esetén válaszd a Sample adatforrást, amikor egyetlen adatbázist hozol létre. SQL Server esetén állíts vissza egy AdventureWorksLT biztonsági mentést az AdventureWorks mintaadatbázisaiból.

Ellenőrizd a sofőröt

Erősítse meg, hogy a driver manager megtalálja a Microsoft ODBC Driver 18-at az SQL Server-hez.

Futtassa ezt a parancsot a PowerShellben:

Get-OdbcDriver -Name "ODBC Driver 18 for SQL Server"

Minden parancsnak fel kell tüntetnie ODBC Driver 18 for SQL Server. Ha a meghajtó nincs feltüntetve, telepítsd újra, mielőtt folytatnád.

Konfiguráld a kapcsolatot

Az alkalmazás a környezeti változóból olvassa fel a teljes kapcsolati karakterlánc-etODBC_CONNECTION_STRING. Nem jeleníti meg a kapcsolati karakterlánc-et, és nem fogadja el parancssori argumentumként.

Használj egy Driver 18 kapcsolati karakterlánc-et, amely érvényes az adatbázisodhoz és a hitelesítési módszeredhez. Az alábbi SQL hitelesítési példa működik Windows-on, Linuxon és macOS-en, amikor az adatbázis lehetővé teszi az SQL hitelesítést:

Driver={ODBC Driver 18 for SQL Server};Server=tcp:<server>,1433;Database=<database>;UID=<user_id>;PWD=<password>;Encrypt=yes;TrustServerCertificate=no;

A Microsoft Entra hitelesítési lehetőségeiről lásd a következőt: A Microsoft Entra ID használata az ODBC-illesztőprogrammal. Minden támogatott beállításért lásd a DSN és a kapcsolati karakterlánc kulcsszavakat és attribútumokat.

A Microsoft ODBC Driver 18 alapértelmezetten engedélyezi a titkosítást. Határozd Encrypt=yes meg, hogy a kérelem követelménye egyértelmű legyen. Tartsd TrustServerCertificate=no a gyártásban, hogy az illesztőprogram érvényesítse a szerver tanúsítványt. A tanúsítványnak a szerver nevét és láncát össze kell egyeztetnie egy olyan tanúsító hatósággal, amelyben az ügyfél megbízik. Konfigurációs útmutatásért lásd: Tanúsítvány validációs hibák.

Figyelmeztetés

TrustServerCertificate=yes kihagyja a tanúsítvány érvényesítését. Csak izolált helyi fejlesztéshez használd, miközben egy olyan tanúsítványt konfigurálsz, amit az ügyfél megbízik. Ne használja éles környezetben.

Állítsd be a környezeti változót anélkül, hogy hozzáadnád a kapcsolati karakterlánc-et a shell történetedhez.

Open Developer PowerShell for VS 2022. Futtatd ezeket a parancsokat, majd illesztsd be a kapcsolati karakterlánc-et a prompthoz:

$secureConnectionString = Read-Host "ODBC connection string" -AsSecureString
$env:ODBC_CONNECTION_STRING = [System.Net.NetworkCredential]::new(
    "", $secureConnectionString).Password
$secureConnectionString = $null

Egy környezeti változó távol tartja a kapcsolati karakterlánc szövegét a forrásfájltól, de a folyamat és annak gyermekfolyamatai el tudják olvasni azt. Termelési alkalmazásokhoz használd a Microsoft Entra hitelesítést, ahol lehetséges, és futásidőben szerezz titkokat egy biztonságos tárolóból.

Az alkalmazás létrehozása

  1. Hozz létre egy projektkönyvtárat, majd lépj be abba:

    New-Item -ItemType Directory odbc-quickstart
    Set-Location odbc-quickstart
    

  1. Hozzon létre egy odbc-quickstart.cpp nevű fájlt a következő kóddal:

    #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;
    }
    

Az alkalmazás csak a szabványos ODBC API-t használja, így tartalmazza a driver-manager fejléceket és a vezető-menedzser könyvtárhoz vezető linkeket. A kapcsolati karakterlánc futásidőben kiválasztja a Microsoft ODBC Driver 18-at az SQL Server számára.

SQL_DRIVER_NOPROMPT megakadályozza SQLDriverConnect , hogy konfigurációs párbeszédet nyissanak. Ha a kapcsolati karakterlánc hiányos, a hívás hibát ad vissza, és az alkalmazás minden diagnosztikai rekordot kinyomtat.

A lekérdezés a elemet SQL Server 0 paraméterként köti, beolvassa az első öt terméket a SalesLT.Product elemből, és SQLGetData-lel lekéri az egyes termékek azonosítóját és nevét.

Az alkalmazás létrehozása és futtatása

  1. Ugyanabban a fejlesztői PowerShell ablakban fordítsd le az alkalmazást:

    cl /std:c++17 /EHsc /W4 odbc-quickstart.cpp /link odbc32.lib
    
  2. Futtassa az alkalmazást:

    .\odbc-quickstart.exe
    

Az alkalmazás szabványos kimenete:

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

Töröld a kapcsolati karakterlánc-et, ha végeztél.

Remove-Item Env:\ODBC_CONNECTION_STRING