ODBC 드라이버로 C 및 C++ 애플리케이션을 개발하세요

버전: 18.7.1.1
날짜: 2026년 9월 7일

C 또는 C++에서 ODBC API를 호출하려면 sql.h, sqlext.h, sqltypes.h를 포함한 다음 드라이버 관리자 임포트 라이브러리를 링크합니다. Microsoft ODBC Driver for SQL Server가 ODBC 표준에 추가하는 SQL Server 확장 기능을 사용하려면 msodbcsql.h도 포함하고, 핵심 ODBC 헤더 뒤에 포함하세요.

적용 대상: Windows, Linux 및 macOS용 Microsoft ODBC Driver 18 for SQL Server. 버전 17은 동일한 헤더 이름과 170 설치 경로, msodbcsql17 라이브러리 이름을 사용합니다.

헤더와 라이브러리

플랫폼은 드라이버 패키지가 아닌 핵심 ODBC 헤더와 드라이버 관리자를 제공합니다. Windows에서는 Windows SDK가 포함되어 있습니다. Linux와 macOS에서는 unixODBC 개발 패키지에 포함되어 있습니다. 드라이버 SDK는 msodbcsql.h 및 대량 복사 가져오기 라이브러리만 제공합니다.

네가 부르는 게 뭐야 Headers Windows Linux macOS
ODBC API sql.h, sqlext.h, sqltypes.h odbc32.lib -lodbc -lodbc
ODBC API, 유니코드 진입 지점 sqlucode.h 추가 odbc32.lib -lodbc -lodbc
ODBC 설치 API odbcinst.h 추가 odbccp32.lib -lodbcinst -lodbcinst
SQL Server 드라이버 확장 msodbcsql.h 추가 추가 도서관은 없습니다 추가 도서관은 없습니다 추가 도서관은 없습니다
대량 복사 (bcp_*) 함수 msodbcsql.h 추가 msodbcsql18.lib -lmsodbcsql-18 -lmsodbcsql.18

대량 복사 링크 이름은 파일 이름이 다르기 때문에 플랫폼마다 다릅니다. Linux에서는 -lmsodbcsql-18이(가) libmsodbcsql-18.so/usr/lib 심볼릭 링크를 통해 확인되며, 링커가 이미 그 위치를 검색하므로 -L는 필요하지 않습니다. macOS에서는 드라이버가 -lmsodbcsql.18 형태로 제공되며, 이는 libmsodbcsql.18.dylib와 일치하지만 Homebrew의 라이브러리 디렉터리는 Apple Silicon의 기본 검색 경로에 포함되어 있지 않습니다. 대량 복사 기능을 연결할 때 추가 -L$(brew --prefix)/lib 하세요.

대량 복사 함수만 드라이버 자체 라이브러리가 필요합니다. 연결 속성, 문장 속성, 열 속성, SQL Server 타입 식별자는 매크로와 타입 정의이므로 포함 msodbcsql.h 만 하면 충분합니다.

설치 API는 ODBC API와는 별도의 라이브러리입니다. Linux 또는 macOS에서 SQLGetPrivateProfileString 없이 -lodbcinst와 같은 함수를 호출하면 컴파일 시점이 아니라 링크 시점에 undefined reference 오류로 실패합니다.

리눅스와 macOS에서 핵심 헤더를 제공하는 unixODBC 개발 패키지를 설치하려면 ' UnixODBC 드라이버 관리자 설치'를 참조하세요.

리눅스와 macOS에서 C 코드에서 msodbcsql.h 앞에 wchar.h를 포함하세요

리눅스와 macOS 버전 msodbcsql.h 은 Always Encrypted 키스토어 제공자 인터페이스를 사용하여 wchar_t선언하지만, 이 유형을 정의하는 헤더는 포함되어 있지 않습니다. C++에서는 키 wchar_t 워드로 사용되므로 C++ 번역 유닛은 추가 헤더 없이 빌드됩니다. C에서 wchar_t는 typedef이므로, C 번역 단위에서는 먼저 <wchar.h>를 포함해야 합니다:

#include <wchar.h>

<wchar.h>를 포함하지 않으면 컴파일러는 unknown type name 'wchar_t' 내부에서 msodbcsql.h 오류를 보고합니다. Windows에서는 포함 추가가 무해하니, 플랫폼 가드 뒤에 두지 말고 공유 소스에 추가하세요.

핵심 ODBC 헤더 뒤에 msodbcsql.h를 포함하세요

msodbcsql.h가 드라이버 이름 매크로 외에 정의하는 모든 것은 #ifdef ODBCVER 블록 안에 있으며, ODBCVER를 정의하는 것은 sql.h이다. 먼저 포함 msodbcsql.h 하면 전처리기가 그 블록 전체를 건너뛰고 헤더는 아무것도 기여하지 않습니다. 컴파일러는 경고를 내지 않습니다.

/* Correct order. */
#ifdef _WIN32
#include <windows.h>
#endif

#include <wchar.h>
#include <sql.h>
#include <sqlext.h>
#include <sqltypes.h>
#include <msodbcsql.h>

msodbcsql.h 앞에 sql.h를 포함하면 ODBCVER 블록 내부의 모든 것이 정의되지 않은 상태가 됩니다. 컴파일러는 사용 시점에 오류를 보고하며, include(포함) 시점이 아닙니다:

order-wrong.c(7): error C2065: 'SQL_COPT_SS_BCP': undeclared identifier

Windows에서는 ODBC 헤더 앞에 windows.h를 포함해야 합니다. Windows SDK의 LONGDWORD 복사본은 sqltypes.hsql.h와 같은 Windows 형식을 사용합니다. msodbcsql.h는 SQL Server 구조를 pshpack8.hpoppack.h로 감싼다. 가 없으면 windows.hSDK 헤더 내에서 빌드가 실패합니다.

SDK 파일이 설치된 곳

플랫폼 msodbcsql.h 대량 복사 라이브러리
Windows %ProgramFiles%\Microsoft SQL Server\Client SDK\ODBC\180\SDK\Include %ProgramFiles%\Microsoft SQL Server\Client SDK\ODBC\180\SDK\Lib\<architecture>\msodbcsql18.lib
Linux /opt/microsoft/msodbcsql18/include /opt/microsoft/msodbcsql18/lib64, 심볼링크가 있습니다 /usr/lib/libmsodbcsql-18.so
macOS $(brew --prefix msodbcsql18)/include/msodbcsql18 $(brew --prefix)/lib/libmsodbcsql.18.dylib

Windows Lib 에서는 설치 프로그램이 컴퓨터에 배치한 각 프로세서 아키텍처별 하위 폴더가 폴더에 포함되어 있습니다. 예: x64, x86, 또는 arm64. 컴파일러의 포함 경로에 Include 폴더를 추가하고 링커의 라이브러리 경로에 아키텍처 하위 폴더를 추가하세요.

리눅스에서는 공유 객체에 버전이 지정되며, 이름은 libmsodbcsql-18.6.so.2.1와 같은 형식이고 SONAME는 포함하지 않습니다. 패키지는 그것을 가리키는 /usr/lib/libmsodbcsql-18.so을 설치하며, 이 때문에 -L 옵션 없이도 -lmsodbcsql-18이 해석됩니다. 버전 관리 파일 이름을 지정하는 대신 그 심볼링크를 통해 링크하세요. 그래야 드라이버 업데이트가 빌드를 망치지 않습니다.

macOS에서 Homebrew는 자체 프리픽스에 설치되며, Apple silicon에서는 /usr/local, Intel에서는 /opt/homebrew입니다. 두 접두사 모두 버전화된 Cellar 디렉터리에 대한 심볼링크입니다. 빌드 스크립트에서는 둘 중 어느 하나를 하드코딩하는 대신 brew --prefix unixodbcbrew --prefix msodbcsql18를 사용하세요.

경로 내 번호는 주요 드라이버 버전을 나타냅니다. 버전 17은 Windows에서는 /opt/microsoft/msodbcsql17/에, Linux에서는 ...\ODBC\170\SDK\에 설치되며, 가져오기 라이브러리는 msodbcsql17.lib입니다.

플랫폼별 전체 파일 인벤토리는 시스템 요구사항, 설치 및 드라이버 파일(Windows), Linux에서 ODBC 드라이버 설치, macOS에서 ODBC 드라이버 설치를 참조하세요.

빌드 세팅을 확인하세요

이 프로그램은 헤더에 맞춰 컴파일되고, 드라이버 관리자와 연결되며, 드라이버 관리자가 볼 수 있는 드라이버를 나열합니다. 연결이 안 되니까, 빌드나 등록 문제와 네트워크 또는 자격 증명 문제만 분리됩니다.

#include <stdio.h>
#include <wchar.h>

#ifdef _WIN32
#include <windows.h>
#endif

#include <sql.h>
#include <sqlext.h>
#include <sqltypes.h>
#include <msodbcsql.h>

static void PrintDiagnostics(SQLSMALLINT handleType, SQLHANDLE handle)
{
    SQLCHAR state[6];
    SQLINTEGER native;
    SQLCHAR message[SQL_MAX_MESSAGE_LENGTH];
    SQLSMALLINT length;

    for (SQLSMALLINT record = 1;
         SQL_SUCCEEDED(SQLGetDiagRec(handleType, handle, record, state, &native,
                                     message, sizeof(message), &length));
         ++record)
    {
        fprintf(stderr, "  [%s] (%ld) %s\n", state, (long)native, message);
    }
}

int main(void)
{
    SQLHENV environment = SQL_NULL_HENV;
    SQLRETURN rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &environment);

    if (!SQL_SUCCEEDED(rc))
    {
        fprintf(stderr, "SQLAllocHandle for the environment failed.\n");
        return 1;
    }

    rc = SQLSetEnvAttr(environment, SQL_ATTR_ODBC_VERSION,
                       (SQLPOINTER)SQL_OV_ODBC3_80, 0);
    if (!SQL_SUCCEEDED(rc))
    {
        fprintf(stderr, "SQLSetEnvAttr for SQL_OV_ODBC3_80 failed.\n");
        PrintDiagnostics(SQL_HANDLE_ENV, environment);
        SQLFreeHandle(SQL_HANDLE_ENV, environment);
        return 1;
    }

    printf("Driver name from msodbcsql.h: %s\n", SQLODBC_DRIVER_NAME);
    printf("Installed drivers:\n");

    SQLCHAR description[256];
    SQLSMALLINT descriptionLength = 0;
    SQLUSMALLINT direction = SQL_FETCH_FIRST;

    while (SQL_SUCCEEDED(SQLDrivers(environment, direction,
                                    description, sizeof(description), &descriptionLength,
                                    NULL, 0, NULL)))
    {
        printf("  %s\n", description);
        direction = SQL_FETCH_NEXT;
    }

    SQLFreeHandle(SQL_HANDLE_ENV, environment);
    return 0;
}

협소 문자 프로그램으로 빌드하세요. UNICODE 또는 printf가 정의되면 SQLODBC_DRIVER_NAME는 와이드 문자열로 확장되는데, %s는 이를 _UNICODE와 함께 사용할 수 없습니다.

cl /W4 /I "%ProgramFiles%\Microsoft SQL Server\Client SDK\ODBC\180\SDK\Include" odbc-build-check.c /link odbc32.lib

Windows에서는 /W4가 Windows SDK에 포함된 C4201: nonstandard extension used: nameless struct/union 사본에서 두 개의 sqlext.h 경고를 보고합니다. 이 경고들은 코드가 아니라 SDK 헤더에서 나오며, 빌드는 성공합니다.

첫 번째 줄은 드라이버 이름이 이진법에 컴파일된 것을 보고합니다. 나머지는 드라이버 매니저가 직접 작성한 목록이므로, 기대했는데 보이지 않는 드라이버는 빌드 문제가 아니라 등록 문제입니다. 목록은 다를 수 있으며, SQL Server 드라이버뿐만 아니라 모든 설치된 ODBC 드라이버도 포함됩니다:

Driver name from msodbcsql.h: ODBC Driver 18 for SQL Server
Installed drivers:
  SQL Server
  ODBC Driver 17 for SQL Server
  ODBC Driver 18 for SQL Server
  Microsoft Access Driver (*.mdb, *.accdb)
  Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)
  Microsoft Access Text Driver (*.txt, *.csv)
  Microsoft Access dBASE Driver (*.dbf, *.ndx, *.mdx)

문자열 리터럴이 아니라 SQLODBC_DRIVER_NAME에서 연결 문자열을 빌드하세요. 매크로는 컴파일한 헤더를 추적하기 때문에 SDK를 업그레이드하면 드라이버 이름이 한 곳에서 업데이트됩니다.

msodbcsql.h가 ODBC API에 추가하는 기능

msodbcsql.h표준 ODBC API에 SQL Server 구체적인 기능을 확장합니다. 각 가족은 기본 상수에서 연속된 숫자 범위를 차지합니다. 범위는 가족 간에 고유하지 않으므로, 값을 전달하는 함수가 구별을 결정합니다.

패밀리 기본 상수 Value
SQLSetConnectAttr의 연결 속성 SQL_COPT_SS_BASE 1200
의 명문 속성 SQLSetStmtAttr SQL_SOPT_SS_BASE 1225
SQLColAttribute의 열 속성 SQL_CA_SS_BASE 1200
SQLGetInfo용 정보 유형 SQL_INFO_SS_FIRST 1199
SQLGetDiagField용 진단 필드 SQL_DIAG_SS_BASE -1150
진단 동적 기능 코드 SQL_DIAG_DFC_SS_BASE -200

헤더는 또한 다음과 같이 선언합니다:

  • Microsoft Entra ID 설정과 액세스 토큰을 포함하는 SQL_COPT_SS_AUTHENTICATIONSQL_COPT_SS_ACCESS_TOKEN 등의 인증 특성.
  • ODBC에서 정의하지 않는 SQL Server 형식에 대한 -150~-199 범위의 SQL 형식 식별자는 SQL_SS_VARIANT, SQL_SS_VECTOR, SQL_SS_UDT, SQL_SS_XML, SQL_SS_TABLE, SQL_SS_TIME2SQL_SS_TIMESTAMPOFFSET입니다. 이들은 SQL 형식을 나타내므로, SQLBindParameterParameterType 인자처럼 ODBC가 SQL 형식을 예상하는 곳에 전달하면 됩니다.
  • 버퍼 측에 세 가지 일치하는 C 타입: SQL_C_SS_TIME2, SQL_C_SS_TIMESTAMPOFFSET, 그리고 SQL_C_SS_VECTOR. 다른 SQL Server 타입들은 표준 ODBC C 타입(예: SQL_C_BINARY 또는 SQL_C_WCHAR)에 바인딩되어 대응 유형이 없습니다SQL_C_SS_*.
  • SQL_C_SS_* 타입이 바인딩되는 구조는 다음과 같습니다: SQL_SS_TIME2_STRUCT, SQL_SS_TIMESTAMPOFFSET_STRUCT, SQL_SS_VECTOR_STRUCT.
  • bcp_sendrow, bcp_batch, bcp_done, bcp_init, bcp_bind를 포함한 프로토타입과 매크로를 일괄 복사합니다. BCP_ENCRYPT_OFF, , BCP_ENCRYPT_ON, 그리고 BCP_ENCRYPT_STRICT 옵션은 Windows 헤더에만 있습니다.

각 플랫폼은 각자의 사본 msodbcsql.h을 발송하며, 모두 같은 기호를 선언하지 않습니다. SQLPERF 구조와 이를 채우는 성능 연결 속성(예: SQL_COPT_SS_PERF_DATASQL_COPT_SS_PERF_QUERY, )은 Windows 헤더에만 있습니다. 리눅스와 macOS 헤더에는 해당 플랫폼의 성능 데이터가 표시되어 있지 않고, 드라이버도 해당 플랫폼의 성능 데이터를 수집하지 않습니다. 프로그래밍 가이드라인(Linux 및 macOS)을 참조하세요.

이 속성들이 대응하는 연결 문자열 키워드에 대해서는 DSN 및 연결 문자열 키워드 및 속성을 참조하세요. Microsoft Entra ID 설정에 대해서는 ODBC 드라이버와 함께 Microsoft Entra ID 사용하기를 참조하세요. 벡터 유형에 대해서는 벡터 데이터 타입을 참조하세요.

비동기 실행과 스레드 중 선택하세요

일부 ODBC 기능은 동기식 또는 비동기식으로 실행될 수 있습니다. 동기식 모드에서는 서버가 응답할 때까지 드라이버가 제어권을 반환하지 않습니다. 비동기 모드에서는 드라이버가 즉시 반환 SQL_STILL_EXECUTING 하고, 애플리케이션은 같은 인자로 같은 호출을 반복하다가 다른 반환 코드를 받을 때까지 반복합니다. 그 외 반환 코드(를 포함 SQL_ERROR)는 연산 완료를 의미합니다.

비동기 모드는 두 가지 형태가 있으며, 그 중 하나를 사용합니다. SQL_ASYNC_MODE와 함께 SQLGetInfo를 호출하여 드라이버가 어느 것을 지원하는지 확인하세요. 드라이버가 개별 문장 제어를 지원하거나, SQL_AM_CONNECTION 해당 설정이 전체 연결에 적용되거나, SQL_AM_NONE 드라이버가 함수를 비동기로 실행하지 않는 경우에 반환 SQL_AM_STATEMENT 됩니다.

구문 형식은 하나의 문 핸들에 대해 비동기 모드를 활성화합니다. 연결의 다른 모든 문장은 동기식을 유지하므로 두 종류의 문을 동시에 실행할 수 있습니다:

SQLSetStmtAttr(hStmt, SQL_ATTR_ASYNC_ENABLE,
               (SQLPOINTER)SQL_ASYNC_ENABLE_ON, SQL_IS_INTEGER);

SQL_AM_CONNECTIONSQL_ASYNC_MODE을 반환하면 문 속성은 읽기 전용이며, 이 호출은 SQLSTATE SQL_ERROR와 함께 HYC00를 반환합니다. 대신 연결 양식을 사용하세요.

이후 해당 연결에 할당한 모든 문장 핸들에 대해 연결 형식은 비동기 모드로 전환됩니다. 이미 존재하는 핸들에도 영향을 미치는지는 드라이버에 의해 정의되므로, 어떤 문장을 할당하기 전에 반드시 설정하세요:

SQLSetConnectAttr(hDbc, SQL_ATTR_ASYNC_ENABLE,
                  (SQLPOINTER)SQL_ASYNC_ENABLE_ON, SQL_IS_INTEGER);

해당 연결에 대한 문에서 함수가 아직 비동기적으로 실행 중이면 이 호출은 SQLSTATE SQL_ERROR와 함께 HY010를 반환합니다. 커서 자체가 열려 있다고 해서 통화가 차단되지 않습니다. 패싱은 SQL_ASYNC_ENABLE_OFF 연결에 있는 모든 문장을 다시 동기 모드로 전환합니다.

한 연결에서 드라이버가 동시에 지원하는 비동기 문장 수를 확인하려면 로 호출 SQLGetInfoSQL_MAX_ASYNC_CONCURRENT_STATEMENTS하세요. Microsoft ODBC Driver 18 for SQL Server는 1을 반환하므로, 연결당 한 번의 미완성 비동기 작업을 계획하고 더 많은 연결을 열거나 그 이상의 스레드를 사용하세요. 비동기 실행(폴링 방법)을 참조하세요.

스레드는 여러 작업을 계속 유지하는 또 다른 방법입니다. ODBC는 멀티스레드 운영체제에서 드라이버가 스레드 안전을 요구하므로, 한 스레드가 ODBC 차단 호출을 할 수 있고 다른 스레드는 계속 작동할 수 있습니다. 이렇게 하면 비동기 모드에서 필요한 폴링 루프와 반복되는 함수 호출을 피할 수 있습니다. 각 스레드마다 고유한 명문 핸들을 부여하세요. 드라이버는 같은 핸들을 동시에 사용하는 두 스레드를 직렬화할 가능성이 높기 때문에, 하나를 공유하면 동시성이 손실됩니다. 멀티스레딩을 참조하세요. 새 코드를 위해 스레드를 선호하고, 이미 작동하는 비동기 코드를 변환하기 전에 자신의 작업 부하를 측정하세요.

Windows에서는 드라이버 관리자가 알림 메서드를 지원하여 폴링 루프를 제거합니다. Win32 이벤트를 연결이나 문장 핸들과 연관시킵니다. 함수는 즉시 반환 SQL_STILL_EXECUTING 되며, 드라이버 관리자는 작업이 완료되면 이벤트를 알립니다. 이 모드에서는 폴링이 비활성화되어 있습니다: 원래 함수를 다시 호출하면 SQLSTATE IM017로 반환됩니다SQL_ERROR. 대신 결과를 확인하려면 전화 SQLCompleteAsync 를 하세요. 이 모드는 드라이버 관리자 버전 ODBC 3.81 이상이어야 하며, 드라이버도 이를 지원해야 합니다. 확인하려면 SQL_ASYNC_NOTIFICATIONSQLGetInfo에 전화해 보세요. 반환되는 값은 애플리케이션이 선언하는 ODBC 버전에 따라 달라집니다. Microsoft ODBC Driver 18 for SQL Server에서는 SQL_ASYNC_NOTIFICATION_CAPABLESQL_ATTR_ODBC_VERSION로 설정하는 애플리케이션은 SQL_OV_ODBC3_80를 반환받고, SQL_OV_ODBC3를 선언하는 애플리케이션은 동일한 드라이버에서 SQL_ASYNC_NOTIFICATION_NOT_CAPABLE를 반환받습니다. 연결을 할당하기 전에 SQL_OV_ODBC3_80을 선언하세요. 비 동기 실행(알림 방법)알림 방법 샘플을 참조하세요.

미해결 작전 취소

SQLCancel 문장 핸들에서 실행 중인 연산을 취소합니다. 다른 스레드 또는 폴링 루프에서, 보류 중인 호출의 핸들을 전달하여 이를 호출합니다.

SQLCancel은 그 용도로만 사용하세요. 더 이상 읽지 않으려는 결과 집합을 버리려면 대신 SQLCloseCursor 또는 SQLMoreResults을 호출하세요.

sqlncli.h에서 msodbcsql.h로 마이그레이션하세요

SQL Server Native Client는 종료되었으므로, 이를 사용하는 애플리케이션은 Microsoft ODBC Driver for SQL Server로 이동해야 합니다. API는 동일한 ODBC API이기 때문에, 대부분의 작업은 빌드 입력과 연결 문자열 내 드라이버 이름을 바꾸는 작업이 포함됩니다.

SQL Server 네이티브 클라이언트 Microsoft ODBC Driver 18 for SQL Server
sqlncli.h msodbcsql.h
sqlncli11.lib msodbcsql18.lib
sqlncli11.dll msodbcsql18.dll
Driver={SQL Server Native Client 11.0} Driver={ODBC Driver 18 for SQL Server}
SQLNCLI_VER SQLODBC_VER

msodbcsql.h 헤더는 여전히 SQLNCLI_*라는 이름의 매크로를 정의하므로, 이를 사용하는 소스 코드는 계속 컴파일됩니다. 이 정의들은 에 의해 #ifndef __sqlncli_h__보호되며, 이는 두 헤더를 같은 번역 단위에 포함시킬 수 없음을 의미합니다. sqlncli.h include를 제거하세요.

두 가지는 그대로 이어지지 않습니다:

  • 연결된 서버 및 해당 카탈로그의 목록을 반환하는 분산 쿼리 메타데이터 API 함수는 msodbcsql.h에 선언되지 않습니다. 그것들은 SQL Server Native Client에만 해당되었습니다.
  • 버전 18은 기본적으로 연결을 암호화하고 서버 인증서를 검증합니다. 네이티브 클라이언트는 그렇지 않았습니다. Native Client에서 작동했던 연결 문자열은 인증서 신뢰를 수정하거나 명시적으로 설정 Encrypt 하기 전까지는 첫 연결에서 실패할 수 있습니다. 연결 암호화 문제 해결을 참조하세요.

버전 17에서 버전 18까지의 나머지 변경 사항은 주요 버전 차이점을 참조하세요.