FILESTREAM을 사용하여 데이터를 증분식으로 주고받기(ODBC)

이 예제에서는 FILESTREAM 기능을 사용하여 SQLPutData 및 SQLGetData로 데이터를 증분식으로 주고받는 방법을 보여 줍니다.

FILESTREAM 기능에 대한 자세한 내용은 FILESTREAM 지원(ODBC)을 참조하십시오.

이 예제를 컴파일하고 실행하기 전에 FILESTREAM 지원(FILESTREAM 사용 및 구성)을 설정합니다.

첫 번째(Transact-SQL) 코드 목록은 이 예제에서 사용하는 데이터베이스를 만듭니다. SQL Server 인스턴스에는 이 스크립트를 실행할 수 있는 쓰기 권한이 있어야 합니다(예: 로컬 시스템 계정으로 로그온).

두 번째 코드 목록은 C++ 코드입니다. 서버를 지정해야 합니다. C++ 코드 목록에서 "MyServer"를 유효한 서버 이름으로 변경합니다. INCLUDE 환경 변수에 sqlncli.h가 들어 있는 디렉터리를 포함해야 합니다. odbc32.lib, user32.lib, /D "_UNICODE", /D "UNICODE", odbc32.lib 및 /EHsc를 사용하여 C++ 코드 목록을 컴파일합니다.

세 번째(Transact-SQL) 코드 목록은 이 예제에서 사용하는 데이터베이스를 삭제합니다.

USE master
GO

-- enable file stream
exec sp_configure 'filestream access level', 2
GO

-- create directory for filestream database
EXEC sp_configure 'show advanced options', 1
GO
RECONFIGURE
GO
EXEC sp_configure 'xp_cmdshell', 1
GO
RECONFIGURE
GO
EXEC xp_cmdshell 'md c:\filestreamdemo'
GO

-- Drop the filestream demo database
IF EXISTS (SELECT name FROM master..sysdatabases WHERE name = 'myfilestreamdb')
    DROP DATABASE [myfilestreamdb]
GO

-- Create filestream demo database
CREATE DATABASE [myfilestreamdb] ON PRIMARY
    (NAME=[myfilestreamdbprimary], FILENAME='c:\filestreamdemo\dbf.mdf'),
    FILEGROUP [fsgrp] CONTAINS FILESTREAM (NAME=[fscnt],FILENAME='c:\filestreamdemo\fscnt')
    LOG ON (NAME=[dblog], FILENAME='c:\filestreamdemo\db1.ldf', SIZE=5MB, MAXSIZE=3000MB, FILEGROWTH=5MB)
GO

-- Create table that contain filestream column
CREATE TABLE [myfilestreamdb]..[mydocs]
(
    id UNIQUEIDENTIFIER ROWGUIDCOL NOT NULL UNIQUE,
    doc VARBINARY(MAX) FILESTREAM
)
GO

// compile with: /D "_UNICODE" /D "UNICODE" odbc32.lib /EHsc
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <tchar.h>
#include <windows.h>
#include <stdio.h>
#include <sql.h>
#include <sqlext.h>

#define _SQLNCLI_ODBC_
#include <sqlncli.h>

#define SUCCESS(x) (!((x) & 0xFFFE))

#define CHKRC(stmt) do { \
                        rc = (stmt); \
                        if (!SUCCESS(rc)) \
                            throw (RETCODE) rc; \
                    } while(0);

void PrintError(SQLSMALLINT HandleType, SQLHANDLE Handle) {
    RETCODE rc = SQL_SUCCESS;
    SQLTCHAR szSqlState[6], szMessage[1024];
    SQLSMALLINT i = 1, msgLen = 0;
    SQLINTEGER NativeError;

    do {
       i = 1;
       while (SQL_NO_DATA != (rc = SQLGetDiagRec(HandleType, Handle, i, szSqlState, &NativeError, szMessage, sizeof(szMessage)/sizeof(SQLTCHAR), &msgLen)) && SUCCESS(rc)) {
            _tprintf(_T("SQLState=%s, NativeError=%ld, Message=%s\r\n"), szSqlState, NativeError, szMessage);
            i++;
        }
    } 
    while (SQL_NO_DATA != (rc = SQLMoreResults(Handle)) && SUCCESS(rc));
}

int _tmain(int argc, _TCHAR* argv[]) {
    RETCODE rc = SQL_SUCCESS;
    HENV henv = SQL_NULL_HENV;
    HDBC hdbc = SQL_NULL_HDBC;
    SQLHSTMT hstmt = SQL_NULL_HSTMT;
    SQLTCHAR * pszConnection = _T("DRIVER={SQL Server Native Client 10.0};")
                               _T("Server=MyServer;")
                               _T("Trusted_Connection=Yes;");
    SQLLEN cbBuffer = SQL_DATA_AT_EXEC;
    BYTE rgbDoc[1024];
    SQLLEN cbDoc;

    try {
        CHKRC(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HENV, &henv));
        CHKRC(SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0));
        CHKRC(SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc));
        CHKRC(SQLDriverConnect(hdbc, NULL, pszConnection, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT));

        CHKRC(SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt));
        CHKRC(SQLPrepare(hstmt,  (SQLTCHAR *)_T("INSERT INTO [myfilestreamdb]..[mydocs] VALUES(newid(), ?)"), SQL_NTS));
        CHKRC(SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_VARBINARY, SQL_SS_LENGTH_UNLIMITED, 0, (SQLPOINTER)1, 0, &cbBuffer));

        rc = ::SQLExecute(hstmt);
        if (SQL_NEED_DATA == rc) {
            SQLPOINTER pParam = NULL;
            while (SQL_NEED_DATA == (rc = ::SQLParamData(hstmt, (SQLPOINTER *)&pParam))) {
                CHKRC(SQLPutData(hstmt, "Hello ", 6));
                CHKRC(SQLPutData(hstmt, "World!", 6));
            }
        }

        CHKRC(SQLFreeStmt(hstmt, SQL_CLOSE));
        CHKRC(SQLExecDirect(hstmt, _T("SELECT doc FROM [myfilestreamdb]..[mydocs]"), SQL_NTS));
        CHKRC(SQLBindCol(hstmt, 1, SQL_C_BINARY, (SQLPOINTER)rgbDoc, sizeof(rgbDoc), &cbDoc));
        CHKRC(SQLFetch(hstmt));

        rgbDoc[cbDoc] = '\0';
        printf("%s\r\n", (LPSTR)rgbDoc);
    }
    catch (RETCODE retcode) {
        rc = retcode;
    }

    if (!SUCCESS(rc))
        if (hstmt)
            PrintError(SQL_HANDLE_STMT, hstmt);
        else if (hdbc)
            PrintError(SQL_HANDLE_DBC, hdbc);
        else if(henv)
            PrintError(SQL_HANDLE_ENV, henv);

    if (hstmt)
        SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

    if (hdbc) {
        SQLDisconnect(hdbc);
        SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
    }

    if (henv)
        SQLFreeHandle(SQL_HANDLE_ENV, henv);
}

USE master
GO
-- Drop the filestream demo database
sp_detach_db 'myfilestreamdb'
IF EXISTS (SELECT name FROM master..sysdatabases WHERE name = 'myfilestreamdb')
    DROP DATABASE [myfilestreamdb]
EXEC xp_cmdshell 'rd /s /q c:\filestreamdemo'
GO