FILESTREAM のサポート (ODBC)
SQL Server 2008 と SQL Server Native Client 10.0 以降では、強化された FILESTREAM 機能が ODBC でサポートされています。この機能の詳細については、「FILESTREAM のサポート」を参照してください。
アプリケーションで 2 GB より大きい varbinary(max) 値を送受信するには、ColumnSize を SQL_SS_LENGTH_UNLIMITED に設定した SQLBindParameter を使用してパラメータをバインドし、SQLExecDirect や SQLExecute の前に StrLen_or_IndPtr の内容を SQL_DATA_AT_EXEC に設定する必要があります。
実行時データのすべてのパラメータと同様、データが SQLParamData および SQLPutData に渡されます。
列が SQLBindCol とバインドされていなければ、SQLGetData を呼び出すことによって、FILESTREAM 列のデータをまとめてフェッチできます。
FILESTREAM が SQLBindCol でバインドされている場合は、データを更新できます。
バインド列で SQLFetch を呼び出した場合、バッファの大きさが値全体を保持するのに十分でないと、"データが切り捨てられました" という警告が表示されます。この警告を無視して、SQLParamData と SQLPutData の呼び出しを使用してそのバインド列のデータを更新します。FILESTREAM が SQLBindCol とバインドされている場合は、SQLSetPos を使用してそのデータを更新できます。
使用例
FILESTREAM 列は、サイズの制限なく varbinary(max) 列とまったく同じように機能します。これらは SQL_VARBINARY としてバインドされます。SQL_LONGVARBINARY は image 列で使用され、この型に関する制限が存在します。たとえば、SQL_LONGVARBINARY を出力パラメータとして使用することはできません。次の例は、FILESTREAM 列に対する直接 NTFS アクセスを示しています。これらの例では、データベースで、次の 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);
}
}
ヘルパ ルーチン
#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;
}