Suporte FILESTREAM (ODBC)
Aplica-se a:SQL Server
Importante
SQL Server Native Client (SNAC) não é fornecido com:
- SQL Server 2022 (16.x) e versões posteriores
- SQL Server Management Studio 19 e versões posteriores
O SQL Server Native Client (SQLNCLI ou SQLNCLI11) e o Microsoft OLE DB Provider for SQL Server (SQLOLEDB) herdado não são recomendados para o desenvolvimento de novos aplicativos.
Para novos projetos, use um dos seguintes drivers:
Para SQLNCLI fornecido como um componente do Mecanismo de Banco de Dados do SQL Server (versões de 2012 a 2019), consulte esta exceção Ciclo de vida do suporte.
ODBC no SQL Server Native Client dá suporte ao recurso FILESTREAM aprimorado. Para obter mais informações sobre esse recurso, consulte FILESTREAM Support. Para obter um exemplo demonstrando o suporte a ODB para FILESTREAM, consulte enviar e receber dados incrementalmente com FILESTREAM (ODBC).
Para enviar e receber valores de varbinary(max) maiores que 2 GB, um aplicativo deve vincular parâmetros usando SQLBindParameter com ColumnSize definido como SQL_SS_LENGTH_UNLIMITEDe definir o conteúdo de StrLen_or_IndPtr para SQL_DATA_AT_EXEC antes de SQLExecDirect ou SQLExecute.
Tal como acontece com qualquer parâmetro de dados em execução, os dados serão fornecidos com SQLParamData e SQLPutData.
Você pode chamar SQLGetData para buscar dados em partes para uma coluna FILESTREAM se a coluna não estiver vinculada ao SQLBindCol.
Você pode atualizar dados FILESTREAM se eles estiverem vinculados ao SQLBindCol.
Se você chamar SQLFetch em uma coluna acoplada, receberá um aviso de "dados truncados" se o buffer não for grande o suficiente para armazenar o valor inteiro. Ignore esse aviso e atualize os dados nesta coluna acoplada com chamadas SQLParamData e SQLPutData. Você pode atualizar dados FILESTREAM usando SQLSetPos se ele estiver vinculado ao SQLBindCol.
Exemplo
As colunas FILESTREAM se comportam exatamente como colunas de varbinary(max), mas sem um limite de tamanho. Eles estão vinculados como SQL_VARBINARY. (SQL_LONGVARBINARY é usado com colunas de imagem, e há restrições sobre esse tipo. Por exemplo, SQL_LONGVARBINARY não pode ser usado como um parâmetro de saída.) Os exemplos a seguir mostram acesso NTFS direto para colunas FILESTREAM. Esses exemplos pressupõem que o seguinte código de Transact-SQL tenha sido executado no banco de dados:
CREATE TABLE fileStreamDocs(
id uniqueidentifier ROWGUIDCOL NOT NULL UNIQUE,
author varchar(64),
document VARBINARY(MAX) FILESTREAM NULL)
Ler
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);
}
}
Inserir
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);
}
}
Rotinas Auxiliares
#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;
}