共用方式為


FILESTREAM 支援 (ODBC)

SQL Server Native Client 中的 ODBC 支援增強型 FILESTREAM 功能。如需有關這項功能的詳細資訊,請參閱<FILESTREAM 支援>。

若要傳送與接收大於 2 GB 的 varbinary(max) 值,應用程式必須在 ColumnSize 設定為 SQL_SS_LENGTH_UNLIMITED 時,使用 SQLBindParameter 繫結參數,並在 SQLExecDirectSQLExecute 之前,將 StrLen_or_IndPtr 的內容設定為 SQL_DATA_AT_EXEC。

如同任何資料執行中 (data-at-execution) 參數,資料會與 SQLParamDataSQLPutData 一起提供。

如果資料行沒有與 SQLBindCol 繫結,您可以呼叫 SQLGetData 來提取 FILESTREAM 資料行之區塊中的資料。

如果資料行與 SQLBindCol 繫結,您可以更新 FILESTREAM 資料。

當您針對繫結的資料行呼叫 SQLFetch 時,如果緩衝區的大小不足以容納整個值,您將會收到「資料已截斷」警告。忽略此警告,並使用 SQLParamDataSQLPutData 呼叫,更新這個繫結資料行中的資料。如果資料行與 SQLBindCol 繫結,您可以使用 SQLSetPos 更新 FILESTREAM 資料。

範例

FILESTREAM 資料行的行為與 varbinary(max) 資料行完全相同,但是沒有大小限制。它們繫結為 SQL_VARBINARY (SQL_LONGVARBINARY 會搭配 image 資料行使用,而且此類型有一些限制。例如,SQL_LONGVARBINARY 無法當做輸出參數使用)。下列範例會示範 NTFS 對於 FILESTREAM 資料行的直接存取。這些範例會假設下列 Transact-SQL 程式碼已在資料庫中執行:

CREATE TABLE fileStreamDocs(
id uniqueidentifier ROWGUIDCOL NOT NULL UNIQUE,
author varchar(64),
document VARBINARY(MAX) FILESTREAM NULL)

讀取

void selectFilestream (LPCWSTR dstFilePath) {
SQLRETURN r;
SQLCHAR transactionToken[1024];
SQLWCHAR srcFilePath[1024];
SQLINTEGER cbTransactionToken, cbsrcFilePath;

// The GUID columns must be visible to the query, 
// even if it is not used
r = SQLExecDirect(hstmt, (SQLTCHAR *) 
_T("select GET_FILESTREAM_TRANSACTION_CONTEXT(); \
select TOP(1) id, document.PathName() \
from fileStreamDocs WHERE author = 'Chris Lee'"), 
SQL_NTS);
if (r != SQL_SUCCESS && r!=SQL_SUCCESS_WITH_INFO) {
ODBCError(henv, hdbc, hstmt, NULL, true); exit(-1);
}

r = SQLFetch(hstmt);
if (r != SQL_SUCCESS && r!=SQL_SUCCESS_WITH_INFO) {
ODBCError(henv, hdbc, hstmt, NULL, true); exit(-1);
}

r = SQLGetData(hstmt, 1, SQL_C_BINARY, 
transactionToken, sizeof(transactionToken), &cbTransactionToken);
if (r != SQL_SUCCESS && r!=SQL_SUCCESS_WITH_INFO) {
ODBCError(henv, hdbc, hstmt, NULL, true); exit(-1);
}

r = SQLMoreResults(hstmt);
if (r != SQL_SUCCESS && r!=SQL_SUCCESS_WITH_INFO) {
ODBCError(henv, hdbc, hstmt, NULL, true); exit(-1);
}
if (r != SQL_SUCCESS && r!=SQL_SUCCESS_WITH_INFO) {
ODBCError(henv, hdbc, hstmt, NULL, true); exit(-1);
}

r = SQLFetch(hstmt);
r = SQLGetData(hstmt, 2, SQL_C_TCHAR, 
srcFilePath, sizeof(srcFilePath), &cbsrcFilePath);
if (r != SQL_SUCCESS && r!=SQL_SUCCESS_WITH_INFO) {
ODBCError(henv, hdbc, hstmt, NULL, true); exit(-1);
}

if (!copyFileFromSql(srcFilePath, dstFilePath, transactionToken, cbTransactionToken)) {
DeleteFile(dstFilePath);
}
r = SQLTransact(henv, hdbc, SQL_ROLLBACK);
if (r != SQL_SUCCESS && r!=SQL_SUCCESS_WITH_INFO) {
ODBCError(henv, hdbc, hstmt, NULL, true); exit(-1);
}
}

插入

void insertFilestream(LPCWSTR srcFilePath) {
SQLRETURN r;
SQLCHAR transactionToken[64];
SQLWCHAR dstFilePath[1024];
SQLINTEGER cbTransactionToken, cbDstFilePath;
SQLUSMALLINT mode;

r = SQLExecDirect(hstmt, (SQLTCHAR *) 
_T("insert into fileStreamDocs (id, author, document)\
    output Get_Filestream_Transaction_Context(), inserted.document.PathName() \
        values (newid(), 'Chris Lee', convert(varbinary, '**Temp**')) "), SQL_NTS);
if (r != SQL_SUCCESS && r!=SQL_SUCCESS_WITH_INFO) {
ODBCError(henv, hdbc, hstmt, NULL, true); exit(-1);
}

r = SQLFetch(hstmt);
if (r != SQL_SUCCESS && r!=SQL_SUCCESS_WITH_INFO) {
ODBCError(henv, hdbc, hstmt, NULL, true); exit(-1);
}

r = SQLGetData(hstmt, 1, SQL_C_BINARY,
transactionToken, sizeof(transactionToken), &cbTransactionToken);
if (r != SQL_SUCCESS && r!=SQL_SUCCESS_WITH_INFO) {
ODBCError(henv, hdbc, hstmt, NULL, true); exit(-1);
}

r = SQLGetData(hstmt, 2, SQL_C_TCHAR,
dstFilePath, sizeof(dstFilePath), &cbDstFilePath);
if (r != SQL_SUCCESS && r!=SQL_SUCCESS_WITH_INFO) {
ODBCError(henv, hdbc, hstmt, NULL, true); exit(-1);
}

r = SQLCloseCursor(hstmt);
if (r != SQL_SUCCESS && r!=SQL_SUCCESS_WITH_INFO) {
ODBCError(henv, hdbc, hstmt, NULL, true); exit(-1);
}

if (copyFileToSql(
srcFilePath, dstFilePath, 
transactionToken, cbTransactionToken)) {
mode = SQL_COMMIT;
}
else {
mode = SQL_ROLLBACK;
}

r = SQLTransact(henv, hdbc, mode);
if (r != SQL_SUCCESS && r!=SQL_SUCCESS_WITH_INFO) {
ODBCError(henv, hdbc, hstmt, NULL, true); exit(-1);
}
}

Helper 常式

#define COPYBUFFERSIZE 4096
BOOL copyFileContents (HANDLE srcHandle, HANDLE dstHandle) {

BYTE buffer[COPYBUFFERSIZE];
DWORD bytesRead, bytesWritten;
BOOL r;

do {
r = ReadFile(srcHandle, buffer, COPYBUFFERSIZE, &bytesRead,NULL);
if (bytesRead == 0) {
return r;
}
r = WriteFile(dstHandle, buffer, bytesRead, &bytesWritten, NULL);
if (bytesWritten == 0) {
return r;
}
} while (TRUE);
}

BOOL copyFileToSql(LPCWSTR srcFilePath, LPCWSTR dstFilePath, LPBYTE transactionToken, SQLINTEGER cbTransactionToken) {


BOOL r;

HANDLE srcHandle, dstHandle;
unsigned int NtStatus;

srcHandle =  CreateFile(
                         srcFilePath,
                         GENERIC_READ,
                         FILE_SHARE_READ,
                         NULL,
                         OPEN_EXISTING,
                         FILE_FLAG_SEQUENTIAL_SCAN,
 NULL);

if (srcHandle == INVALID_HANDLE_VALUE) {
return FALSE;
}

dstHandle =  OpenSqlFilestream(
                         dstFilePath,
                         Write,
                         0,
                         transactionToken,
                         cbTransactionToken,
                         0);

if (dstHandle == INVALID_HANDLE_VALUE) {
NtStatus = GetLastError();
r = CloseHandle(srcHandle);
return FALSE;
}

//copy file
r = copyFileContents(srcHandle, dstHandle);

CloseHandle(srcHandle);

CloseHandle(dstHandle);

return r;
}

BOOL copyFileFromSql(LPCWSTR srcFilePath, LPCWSTR dstFilePath, LPBYTE transactionToken, SQLINTEGER cbTransactionToken) {


BOOL r;

HANDLE srcHandle, dstHandle;
unsigned int NtStatus;

srcHandle =  OpenSqlFilestream(
                         srcFilePath,
                         Read,
                         0,
                         transactionToken,
                         cbTransactionToken,
                         0);

if (srcHandle == INVALID_HANDLE_VALUE) {
return FALSE;
}

dstHandle =  CreateFile(
                         dstFilePath,
                         GENERIC_WRITE,
                         0,
                         NULL,
                         OPEN_ALWAYS,
                         FILE_ATTRIBUTE_NORMAL,
 NULL);

if (dstHandle == INVALID_HANDLE_VALUE) {
CloseHandle(srcHandle);
return FALSE;
}

r = copyFileContents(srcHandle, dstHandle);

CloseHandle(srcHandle);

CloseHandle(dstHandle);

return r;
}