Quickstart: Koppla upp dig och fråga med C++ och ODBC

gäller för:SQL ServerAzure SQL Database

I denna snabbstart bygger du en C++-konsolapplikation på Windows, Linux eller macOS. Applikationen ansluter till en AdventureWorksLT databas genom att använda Microsoft ODBC Driver 18 för SQL Server, binder en frågeparameter, kör frågan och läser resultatraderna.

Prerequisites

  • Microsoft ODBC Driver 18 för SQL Server. Installera drivrutinen för Windows, Linux eller macOS.
  • En C++17-kompilator och plattformens ODBC-utvecklingsfiler:
    • I Windows installerar du Visual Studio 2022 eller byggverktygen för Visual Studio 2022 med arbetsbelastningen Skrivbordsutveckling med C++. Windows SDK tillhandahåller ODBC-headers och odbc32.lib.
    • På Linux, installera en C++-kompilator och utvecklingspaketet unixODBC för din distribution. Paketet tillhandahåller ODBC-headers och libodbc.
    • På macOS, installera Xcode-kommandoradsverktygen och unixODBC från Homebrew.
  • En databas i Azure SQL Database eller SQL Server som innehåller AdventureWorksLT exempeldata. För Azure SQL Database, välj Exempeldatakällan när du skapar en enda databas. För SQL Server, återställ en AdventureWorksLT backup från AdventureWorks exempeldatabaser.

Verifiera föraren

Bekräfta att drivrutinshanteraren kan hitta Microsoft ODBC Driver 18 för SQL Server.

Kör detta kommando i PowerShell:

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

Varje kommando ska lista ODBC Driver 18 for SQL Server. Om drivrutinen inte är listad, installera om den innan du fortsätter.

Konfigurera anslutningen

Applikationen läser hela reťazec pripojenia från ODBC_CONNECTION_STRING miljövariabeln. Den visar inte reťazec pripojenia eller accepterar den som ett kommandoradsargument.

Använd en anslutningssträng för Driver 18 som är giltig för din databas och autentiseringsmetod. Följande exempel på SQL-autentisering fungerar på Windows, Linux och macOS när databasen tillåter SQL-autentisering:

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

För Microsoft Entra-autentiseringsalternativ, se Använd Microsoft Entra ID med ODBC-drivrutinen. För alla stödda inställningar, se DSN och reťazec pripojenia-nyckelord och attribut.

Microsoft ODBC Driver 18 aktiverar kryptering som standard. Specificera Encrypt=yes så att applikationens krav är explicit. Låt TrustServerCertificate=no vara i produktionsmiljö så att drivrutinen validerar servercertifikatet. Certifikatet måste matcha serverns namn och kedja med en certifieringsmyndighet som klienten litar på. För konfigurationsvägledning, se Certifikatvalideringsfel.

Caution

TrustServerCertificate=yes Hoppar över certifikatvalidering. Använd det endast för isolerad lokal utveckling medan du konfigurerar ett certifikat som klienten litar på. Använd den inte i produktion.

Ställ in miljövariabeln utan att lägga till reťazec pripojenia i din shellhistorik.

Öppna Developer PowerShell för VS 2022. Kör dessa kommandon och klistra sedan in reťazec pripojenia i prompten:

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

En miljövariabel håller reťazec pripojenia utanför källfilen, men processen och dess underprocesser kan läsa den. För produktionsprogram bör du använda Microsoft Entra-autentisering om möjligt och hämta hemligheter från ett säkert lagringsutrymme under körning.

Skapa programmet

  1. Skapa en projektkatalog och ändra till den:

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

  1. Skapa en fil med namnet odbc-quickstart.cpp med följande kod:

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

Applikationen använder endast det standardiserade ODBC-API:et, så den inkluderar drivrutinshanterarhuvuden och länkar till drivrutinshanterarbiblioteket. Anslutningssträngen väljer Microsoft ODBC Driver 18 for SQL Server under körning.

SQL_DRIVER_NOPROMPT förhindrar SQLDriverConnect att en konfigurationsdialog öppnas. Om anslutningssträngen är ofullständig returnerar anropet ett fel och programmet skriver ut varje diagnostikpost.

Frågan binder 0 som en SQL Server int-parameter, läser de fem första produkterna i SalesLT.Product, och hämtar varje produkt-ID och namn med SQLGetData.

Skapa och köra programmet

  1. I samma Developer PowerShell-fönster, kompilera applikationen:

    cl /std:c++17 /EHsc /W4 odbc-quickstart.cpp /link odbc32.lib
    
  2. Kör programmet:

    .\odbc-quickstart.exe
    

Applikationens standardutdata är:

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

Rensa anslutningssträngen när du är klar.

Remove-Item Env:\ODBC_CONNECTION_STRING