Prise en charge de FILESTREAM (ODBC)
À partir de SQL Server 2008 et SQL Server Native Client 10.0, ODBC prend en charge la fonctionnalité FILESTREAM améliorée. Pour plus d'informations sur cette fonctionnalité, consultez Prise en charge de FILESTREAM.
Pour envoyer et recevoir des valeurs varbinary(max) supérieures à 2 Go, une application doit lier des paramètres à l'aide de SQLBindParameter, ColumnSize étant définie avec la valeur SQL_SS_LENGTH_UNLIMITED, et définir le contenu de StrLen_or_IndPtr avec la valeur SQL_DATA_AT_EXEC avant SQLExecDirect ou SQLExecute.
Comme avec tout paramètre de données en cours d'exécution, les données sont fournies avec SQLParamData et SQLPutData.
Vous pouvez appeler SQLGetData pour extraire les données en plusieurs segments pour une colonne FILESTREAM si la colonne n'est pas liée avec SQLBindCol.
Vous pouvez mettre à jour les données FILESTREAM si elles sont liées avec SQLBindCol.
Si vous appelez SQLFetch sur une colonne liée, vous recevez un avertissement de « données tronquées » si la mémoire tampon n'est pas assez grande pour contenir la valeur entière. Ignorez cet avertissement et mettez à jour les données de la colonne liée avec les appels de SQLParamData et SQLPutData. Vous pouvez mettre à jour les données FILESTREAM en utilisant SQLSetPos si elles sont liées avec SQLBindCol.
Exemple
Les colonnes FILESTREAM se comportent exactement comme les colonnes varbinary(max), mais sans limite de taille. Elles sont liées en tant que SQL_VARBINARY. (SQL_LONGVARBINARY est utilisé avec les colonnes image et ce type comporte un certain nombre de restrictions. Par exemple, SQL_LONGVARBINARY ne peut pas être utilisé comme paramètre de sortie.) Les exemples suivants affichent l'accès NTFS direct pour les colonnes FILESTREAM. Ces exemples supposent que le code Transact-SQL suivant a été exécuté dans la base de données :
CREATE TABLE fileStreamDocs(
id uniqueidentifier ROWGUIDCOL NOT NULL UNIQUE,
author varchar(64),
document VARBINARY(MAX) FILESTREAM NULL)
Lecture
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);
}
}
Insertion
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);
}
}
Routines d'assistance
#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;
}