Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Berlaku untuk:SQL Server
Azure SQL Database
Azure SQL Managed Instance
Azure Synapse Analytics
SQL database di Microsoft Fabric
Sebelum SQL Server 2005 (9.x), bekerja dengan jenis data bernilai besar memerlukan penanganan khusus. Jenis data nilai besar adalah jenis yang melebihi ukuran baris maksimum 8 KB. SQL Server 2005 (9.x) memperkenalkan penentu maksimum untuk jenis data varchar, nvarchar, dan varbinary untuk memungkinkan penyimpanan nilai sebesar 2^31 -1 byte. Kolom tabel dan variabel Transact-SQL dapat menentukan jenis data varchar(max), nvarchar(max), atau varbinary(max ).
Catatan
Jenis data nilai besar dapat memiliki ukuran maksimum antara 1 KB dan 8 KB, atau dapat ditentukan sebagai tidak terbatas.
Sebelumnya, hanya jenis data SQL Server seperti teks, ntext, dan gambar yang bisa sangat besar. Penentu maksimum untuk varchar, nvarchar, dan varbinary membuat jenis data ini redundan. Namun, karena jenis data panjang masih tersedia, sebagian besar antarmuka ke komponen akses data OLE DB akan tetap sama. Untuk kompatibilitas mundur dengan rilis sebelumnya, bendera DBCOLUMNFLAGS_ISLONG di Driver OLE DB untuk SQL Server tetap digunakan. Penyedia dan driver yang ditulis terhadap SQL Server 2005 (9.x) dan yang lebih baru terus menggunakan istilah ini untuk jenis baru ketika diatur ke panjang maksimum tak terbatas.
Catatan
Anda juga dapat menentukan jenis data varchar(max), nvarchar(max), dan varbinary(max) sebagai jenis parameter input dan output dari prosedur tersimpan, jenis pengembalian fungsi, atau dalam fungsi CAST dan CONVERT .
Catatan
Jika mereplikasi data, Anda mungkin perlu mengonfigurasi opsi konfigurasi server ukuran repl teks maks ke -1.
Menggunakan ADO dengan Driver OLE DB untuk SQL Server
Driver OLE DB untuk SQL Server mengekspos jenis varchar(max), varbinary(max), dan nvarchar(max) masing-masing sebagai DBTYPE_STR, DBTYPE_BYTES, dan DBTYPE_WSTR.
Jenis data varchar(max), varbinary(max), dan nvarchar(max) dalam kolom dengan ukuran maksimum yang diatur ke unlimited direpresentasikan sebagai ISLONG melalui set baris dan antarmuka skema OLE DB inti yang mengembalikan jenis data kolom.
Implementasi IAccessor objek perintah telah diubah untuk memungkinkan pengikatan sebagai DBTYPE_IUNKNOWN. Jika konsumen menentukan DBTYPE_IUNKNOWN dan mengatur pObject ke null, penyedia akan mengembalikan antarmuka ISequentialStream ke konsumen sehingga konsumen dapat mengalirkan data varchar(maks), nvarchar(maks), atau varbinary(maks) dari variabel output.
Nilai parameter output yang dialirkan dikembalikan setelah baris hasil apa pun. Jika aplikasi mencoba beralih ke hasil berikutnya yang ditetapkan dengan memanggil IMultipleResults::GetResult tanpa mengonsumsi semua nilai parameter output yang dikembalikan, DB_E_OBJECTOPEN akan dikembalikan.
Untuk mendukung streaming, Driver OLE DB untuk SQL Server memerlukan parameter panjang variabel untuk diakses secara berurutan. Persyaratan ini berarti bahwa DBPROP_ACCESSORDER harus diatur ke kolom DBPROPVAL_AO_SEQUENTIALSTORAGEOBJECTS atau DBPROPVAL_AO_SEQUENTIAL setiap kali varchar(maks), nvarchchar(maks), atau kolom varbinary(maks) atau parameter output terikat ke DBTYPE_IUNKNOWN. Panggilan ke IRowset::GetData akan gagal dengan DBSTATUS_E_UNAVAILABLE jika pembatasan pesanan akses ini tidak dipatuhi. Pembatasan ini tidak berlaku ketika tidak ada pengikatan output menggunakan DBTYPE_IUNKNOWN.
Driver OLE DB untuk SQL Server juga mendukung parameter output pengikatan sebagai DBTYPE_IUNKNOWN untuk jenis data nilai besar untuk memfasilitasi skenario di mana prosedur tersimpan mengembalikan jenis nilai besar sebagai nilai kembali yang diekspos sebagai DBTYPE_IUNKNOWN kepada klien.
Untuk bekerja dengan jenis ini, aplikasi memiliki opsi berikut:
- Ikat sebagai jenis yang memiliki pengikatan yang didukung dengan jenis dasar kolom (misalnya, untuk nvarchar(max), ikat sebagai jenis yang dapat diikat ke nvarchar). Jika buffer tidak cukup besar pemotongan akan terjadi, persis seperti untuk jenis dasar, meskipun nilai yang lebih besar sekarang tersedia.
- Ikat sebagai jenis yang memiliki konversi yang didukung dengan jenis dasar kolom dan tentukan juga DBTYPE_BYREF.
- Ikat sebagai DBTYPE_IUNKNOWN dan gunakan streaming.
Saat melaporkan ukuran maksimum kolom, Driver OLE DB untuk SQL Server akan melaporkan:
- Ukuran maksimum yang ditentukan, yang, misalnya, adalah 2000 untuk kolom varchar(2000), atau
- Nilai "tidak terbatas", yang untuk kolom varchar(maks) sama dengan ~0. Nilai ini diatur untuk properti metadata DBCOLUMN_COLUMNSIZE.
Aturan konversi standar akan berlaku untuk kolom varchar(max), yang berarti bahwa konversi apa pun yang valid untuk kolom varchar(2000) juga akan valid untuk kolom varchar(maks). Hal yang sama berlaku untuk kolom nvarchar(maks) dan varbinary(maks ).
Saat mengambil jenis nilai besar, pendekatan yang paling efisien adalah mengikat sebagai DBTYPE_IUNKNOWN dan mengatur properti set baris DBPROP_ACCESSORDER ke DBPROPVAL_AO_SEQUENTIALSTORAGEOBJECTS. Pengaturan ini akan menyebabkan nilai dialirkan langsung dari jaringan tanpa buffer perantara, seperti dalam contoh berikut:
#define UNICODE
#define _UNICODE
#define DBINITCONSTANTS
#define INITGUID
#define OLEDBVER 0x0250 // To include the correct interfaces.
#include <stdio.h>
#include <tchar.h>
#include <stddef.h>
#include <iostream>
using std::cout;
using std::endl;
#include <windows.h>
#include <oledb.h>
#include "msoledbsql.h"
#include <oledberr.h>
#define CHKHR_GOTO(hr, errMsg, Label) \
if (FAILED(hr)) \
{ \
cout << errMsg << endl; \
goto Label; \
}
#define MAX_COL_SIZE 8000
// ROUNDUP on all platforms pointers must be aligned properly.
#define ROUNDUP_AMOUNT 8
#define ROUNDUP_(size,amount) (((ULONG)(size)+((amount)-1))&~((amount)-1))
#define ROUNDUP(size) ROUNDUP_(size, ROUNDUP_AMOUNT)
HRESULT InitializeAndEstablishConnection(IDBInitialize** ppIDBInitialize);
void UnInitializeConnection(IDBInitialize* pIDBInitialize);
HRESULT CreateAndSetCommand(IDBInitialize* pIDBInitialize, ICommandText** ppICommandText);
HRESULT ProcessResultSet(IRowset* pIRowset);
void DisplayTime()
{
SYSTEMTIME st;
GetSystemTime(&st);
cout<< st.wHour << ":" << st.wMinute << ":" << st.wSecond << "." << st.wMilliseconds << endl;
}
void main()
{
HRESULT hr;
IDBInitialize* pIDBInitialize = NULL;
ICommandText* pICommandText = NULL;
IMultipleResults* pIMultipleResults = NULL;
IRowset* pIRowset = NULL;
hr = InitializeAndEstablishConnection(&pIDBInitialize);
CHKHR_GOTO(hr, L"Failed to establish connection.", _ExitMain);
hr = CreateAndSetCommand(pIDBInitialize, &pICommandText);
CHKHR_GOTO(hr, L"Failed to set up command object.", _ExitMain);
DisplayTime();
hr = pICommandText->Execute(NULL,
IID_IMultipleResults,
NULL,
NULL,
(IUnknown **) &pIMultipleResults);
CHKHR_GOTO(hr, L"Failed to execute command.", _ExitMain);
while (1)
{
hr = pIMultipleResults->GetResult(
NULL,
DBRESULTFLAG_DEFAULT,
IID_IRowset,
NULL,
(IUnknown**)&pIRowset);
CHKHR_GOTO(hr, L"Failed to obtain a results from MR object.", _ExitMain);
if (hr == DB_S_NORESULT)
break;
if (pIRowset)
{
hr = ProcessResultSet(pIRowset);
CHKHR_GOTO(hr, L"Failed to process the current Rowset.", _ExitMain);
pIRowset->Release();
pIRowset = NULL;
}
}
DisplayTime();
_ExitMain:
if (pIRowset)
{
pIRowset->Release();
pIRowset = NULL;
}
if (pIMultipleResults)
{
pIMultipleResults->Release();
pIMultipleResults = NULL;
}
if (pICommandText)
{
pICommandText->Release();
pICommandText = NULL;
}
UnInitializeConnection(pIDBInitialize);
return;
};
HRESULT InitializeAndEstablishConnection(IDBInitialize** ppIDBInitialize)
{
HRESULT hr;
IDBInitialize* pIDBInitialize = NULL;
IDBProperties* pIDBProperties = NULL;
const int NUM_DBINIT_PROPS = 3;
const wchar_t* const g_wszServer = L".";
const wchar_t* const g_wszCatalog = L"AdventureWorks";
const wchar_t* const g_wszSecurity = L"SSPI";
DBPROPSET rgdbPropSetInit[1];
DBPROP rgdbPropInit [NUM_DBINIT_PROPS];
*ppIDBInitialize = NULL;
hr = CoInitialize(NULL);
CHKHR_GOTO(hr, L"Failed to initialize COM.", _ExitInitialize);
hr = CoCreateInstance(CLSID_MSOLEDBSQL,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDBInitialize,
(void**)&pIDBInitialize);
CHKHR_GOTO(hr, L"Failed to create MSOLEDBSQL DataSource object.", _ExitInitialize);
for(int idxProp = 0; idxProp < NUM_DBINIT_PROPS; idxProp++)
{
VariantInit(&rgdbPropInit[idxProp].vValue);
}
rgdbPropInit[0].dwPropertyID = DBPROP_INIT_DATASOURCE;
rgdbPropInit[0].vValue.vt = VT_BSTR;
rgdbPropInit[0].vValue.bstrVal= SysAllocString(g_wszServer);
rgdbPropInit[0].dwOptions = DBPROPOPTIONS_REQUIRED;
rgdbPropInit[0].colid = DB_NULLID;
if (rgdbPropInit[0].vValue.bstrVal == NULL)
{
hr = E_OUTOFMEMORY;
goto _ExitInitialize;
}
rgdbPropInit[1].dwPropertyID = DBPROP_INIT_CATALOG;
rgdbPropInit[1].vValue.vt = VT_BSTR;
rgdbPropInit[1].vValue.bstrVal= SysAllocString(g_wszCatalog);
rgdbPropInit[1].dwOptions = DBPROPOPTIONS_REQUIRED;
rgdbPropInit[1].colid = DB_NULLID;
if (rgdbPropInit[1].vValue.bstrVal == NULL)
{
hr = E_OUTOFMEMORY;
goto _ExitInitialize;
}
rgdbPropInit[2].dwPropertyID = DBPROP_AUTH_INTEGRATED;
rgdbPropInit[2].vValue.vt = VT_BSTR;
rgdbPropInit[2].vValue.bstrVal= SysAllocString(g_wszSecurity);
rgdbPropInit[2].dwOptions = DBPROPOPTIONS_REQUIRED;
rgdbPropInit[2].colid = DB_NULLID;
if (rgdbPropInit[2].vValue.bstrVal == NULL)
{
hr = E_OUTOFMEMORY;
goto _ExitInitialize;
}
rgdbPropSetInit[0].guidPropertySet = DBPROPSET_DBINIT;
rgdbPropSetInit[0].cProperties = NUM_DBINIT_PROPS;
rgdbPropSetInit[0].rgProperties = rgdbPropInit;
hr = pIDBInitialize->QueryInterface(IID_IDBProperties, (void **)&pIDBProperties);
CHKHR_GOTO(hr, L"Failed to QI DataSource object for IDBProperties.", _ExitInitialize);
hr = pIDBProperties->SetProperties(1, rgdbPropSetInit);
CHKHR_GOTO(hr, L"Failed to set DataSource object Properties.", _ExitInitialize);
pIDBProperties->Release();
pIDBProperties = NULL;
hr = pIDBInitialize->Initialize();
CHKHR_GOTO(hr, L"Failed to establish connection with the server.", _ExitInitialize);
_ExitInitialize:
if (pIDBProperties)
{
pIDBProperties->Release();
pIDBProperties = NULL;
}
if (FAILED(hr))
{
if (pIDBInitialize)
{
pIDBInitialize->Release();
pIDBInitialize = NULL;
}
}
*ppIDBInitialize = pIDBInitialize;
return hr;
}
void UnInitializeConnection(IDBInitialize* pIDBInitialize)
{
if (pIDBInitialize)
{
pIDBInitialize->Uninitialize();
pIDBInitialize->Release();
pIDBInitialize = NULL;
}
CoUninitialize();
}
HRESULT CreateAndSetCommand(IDBInitialize* pIDBInitialize, ICommandText** ppICommandText)
{
HRESULT hr;
IDBCreateSession* pIDBCreateSession = NULL;
IDBCreateCommand* pIDBCreateCommand = NULL;
ICommandText* pICommandText = NULL;
ICommandProperties* pICommandProperties = NULL;
DBPROPSET rgCmdPropSet[1];
DBPROP rgCmdProperties[1];
const wchar_t* const g_wCmdString = L"declare @x xml, @y nvarchar(max); select @x = (SELECT * FROM Sales.SalesOrderHeader FOR XML AUTO); select @x;";
*ppICommandText = NULL;
if (!pIDBInitialize)
{
hr = E_FAIL;
goto _ExitCreateAndSetCommand;
}
hr = pIDBInitialize->QueryInterface(IID_IDBCreateSession, (void**) &pIDBCreateSession);
CHKHR_GOTO(hr, L"Failed to obtain IDBCreateSession interface from DSO.", _ExitCreateAndSetCommand);
hr = pIDBCreateSession->CreateSession(
NULL,
IID_IDBCreateCommand,
(IUnknown**) &pIDBCreateCommand);
CHKHR_GOTO(hr, L"Failed to Create a Session for command execution.", _ExitCreateAndSetCommand);
hr = pIDBCreateCommand->CreateCommand(
NULL,
IID_ICommandText,
(IUnknown**)&pICommandText);
CHKHR_GOTO(hr, L"Failed to Create a Command object.", _ExitCreateAndSetCommand);
hr = pICommandText->SetCommandText(DBGUID_DBSQL, g_wCmdString);
CHKHR_GOTO(hr, L"Failed to Set Command Text.", _ExitCreateAndSetCommand);
hr = pICommandText->QueryInterface(IID_ICommandProperties, (void**) &pICommandProperties);
CHKHR_GOTO(hr, L"Failed to obtain ICommandProperties interface from the command object.", _ExitCreateAndSetCommand);
rgCmdProperties[0].dwPropertyID = DBPROP_ACCESSORDER;
rgCmdProperties[0].vValue.vt = VT_I4;
rgCmdProperties[0].vValue.lVal = DBPROPVAL_AO_SEQUENTIAL;
rgCmdProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;
rgCmdProperties[0].colid = DB_NULLID;
rgCmdPropSet[0].guidPropertySet = DBPROPSET_ROWSET;
rgCmdPropSet[0].cProperties = 1;
rgCmdPropSet[0].rgProperties = rgCmdProperties;
hr = pICommandProperties->SetProperties(1, rgCmdPropSet);
CHKHR_GOTO(hr, L"Failed to Set Command object Properties.", _ExitCreateAndSetCommand);
_ExitCreateAndSetCommand:
if (pICommandProperties)
{
pICommandProperties->Release();
pICommandProperties = NULL;
}
if (pIDBCreateCommand)
{
pIDBCreateCommand->Release();
pIDBCreateCommand = NULL;
}
if (pIDBCreateSession)
{
pIDBCreateSession->Release();
pIDBCreateSession = NULL;
}
if (FAILED(hr))
{
if (pICommandText)
{
pICommandText->Release();
pICommandText = NULL;
}
}
*ppICommandText = pICommandText;
return hr;
}
HRESULT ProcessResultSet(IRowset* pIRowset)
{
HRESULT hr;
IColumnsInfo* pIColumnsInfo = NULL;
DBCOLUMNINFO* pDBColumnInfo = NULL;
ULONG lNumCols = 0;
wchar_t* pStringsBuffer = NULL;
DBBINDING* pBindings = NULL;
DBOBJECT dbobj;
ULONG idxBinding;
IAccessor* pIAccessor = NULL;
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
HROW hRows[1] = {DB_NULL_HROW};
HROW* pRow = &hRows[0];
BYTE* pBuffer = NULL;
ULONG lNumRowsRetrieved;
DBLENGTH dwOffset = 0;
hr = pIRowset->QueryInterface(IID_IColumnsInfo, (void **)&pIColumnsInfo);
CHKHR_GOTO(hr, L"Failed to QI Rowset for IColumnsInfo.", _ExitProcessResultSet);
hr = pIColumnsInfo->GetColumnInfo(&lNumCols, &pDBColumnInfo, &pStringsBuffer);
CHKHR_GOTO(hr, L"Failed to obtain Column Information.", _ExitProcessResultSet);
pBindings = new DBBINDING[lNumCols];
if (!pBindings)
{
hr = E_OUTOFMEMORY;
goto _ExitProcessResultSet;
}
memset(pBindings, 0, sizeof(DBBINDING) * lNumCols);
dbobj.dwFlags = STGM_READ;
dbobj.iid = IID_ISequentialStream;
for (idxBinding = 0; idxBinding < lNumCols; idxBinding++)
{
pBindings[idxBinding].iOrdinal = idxBinding + 1;
pBindings[idxBinding].obStatus = dwOffset;
pBindings[idxBinding].obLength = dwOffset + sizeof(DBSTATUS);
pBindings[idxBinding].obValue = dwOffset + sizeof(DBSTATUS) + sizeof(DBLENGTH);
pBindings[idxBinding].pTypeInfo = NULL;
pBindings[idxBinding].pBindExt = NULL;
pBindings[idxBinding].dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
pBindings[idxBinding].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
pBindings[idxBinding].eParamIO = DBPARAMIO_NOTPARAM;
pBindings[idxBinding].bPrecision = pDBColumnInfo[idxBinding].bPrecision;
pBindings[idxBinding].bScale = pDBColumnInfo[idxBinding].bScale;
pBindings[idxBinding].cbMaxLen = 0;
pBindings[idxBinding].wType = DBTYPE_WSTR;
// Determine the maximum number of bytes required in our buffer to
// contain the Unicode string representation of the provider's native
// data type, including room for the NULL-termination character
switch( pDBColumnInfo[idxBinding].wType )
{
case DBTYPE_NULL:
case DBTYPE_EMPTY:
case DBTYPE_I1:
case DBTYPE_I2:
case DBTYPE_I4:
case DBTYPE_UI1:
case DBTYPE_UI2:
case DBTYPE_UI4:
case DBTYPE_R4:
case DBTYPE_BOOL:
case DBTYPE_I8:
case DBTYPE_UI8:
case DBTYPE_R8:
case DBTYPE_CY:
case DBTYPE_ERROR:
// When the above types are converted to a string, they
// will all fit into 25 characters, so use that plus space
// for the NULL-terminator.
pBindings[idxBinding].cbMaxLen = (25 + 1) * sizeof(WCHAR);
break;
case DBTYPE_DECIMAL:
case DBTYPE_NUMERIC:
case DBTYPE_DATE:
case DBTYPE_DBDATE:
case DBTYPE_DBTIMESTAMP:
case DBTYPE_GUID:
// Converted to a string, the above types will all fit into
// 50 characters, so use that plus space for the terminator.
pBindings[idxBinding].cbMaxLen = (50 + 1) * sizeof(WCHAR);
break;
case DBTYPE_BYTES:
// In converting DBTYPE_BYTES to a string, each byte
// becomes two characters (e.g. 0xFF -> "FF"), so we
// will use double the maximum size of the column plus
// include space for the NULL-terminator.
pBindings[idxBinding].cbMaxLen = (pDBColumnInfo[idxBinding].ulColumnSize * 2 + 1) * sizeof(WCHAR);
break;
case DBTYPE_STR:
case DBTYPE_WSTR:
case DBTYPE_BSTR:
// Going from a string to our string representation,
// we can just take the maximum size of the column,
// a count of characters, and include space for the
// terminator, which is not included in the column size.
pBindings[idxBinding].cbMaxLen = (pDBColumnInfo[idxBinding].ulColumnSize + 1) * sizeof(WCHAR);
break;
default:
// For any other type, we will simply use our maximum
// column buffer size, since the display size of these
// columns may be variable (e.g. DBTYPE_VARIANT) or
// unknown (e.g. provider-specific types).
pBindings[idxBinding].cbMaxLen = MAX_COL_SIZE;
break;
}
// If the provider's native data type for this column is
// DBTYPE_IUNKNOWN or this is a BLOB column and the user
// has requested that we bind BLOB columns as ISequentialStream
// objects, bind this column as an ISequentialStream object if
// the provider supports our creating another ISequentialStream
// binding.
if(pDBColumnInfo[idxBinding].dwFlags & DBCOLUMNFLAGS_ISLONG)
{
pBindings[idxBinding].wType = DBTYPE_IUNKNOWN;
pBindings[idxBinding].cbMaxLen = sizeof(ISequentialStream*);
pBindings[idxBinding].pObject = (DBOBJECT *)CoTaskMemAlloc(sizeof(DBOBJECT));
if (!pBindings[idxBinding].pObject)
{
hr = E_OUTOFMEMORY;
goto _ExitProcessResultSet;
}
// Direct the provider to create an ISequentialStream
// object over the data for this column.
pBindings[idxBinding].pObject->iid = IID_ISequentialStream;
// We want read access on the ISequentialStream
// object that the provider will create for us
pBindings[idxBinding].pObject->dwFlags = STGM_READ;
}
// Ensure that the bound maximum length is no more than the
// maximum column size in bytes that we've defined.
pBindings[idxBinding].cbMaxLen = min(pBindings[idxBinding].cbMaxLen, MAX_COL_SIZE);
// Update the offset past the end of this column's data, so
// that the next column will begin in the correct place in
// the buffer.
dwOffset = pBindings[idxBinding].cbMaxLen + pBindings[idxBinding].obValue;
// Ensure that the data for the next column will be correctly
// aligned for all platforms, or, if we're done with columns,
// that if we allocate space for multiple rows that the data
// for every row is correctly aligned.
dwOffset = ROUNDUP(dwOffset);
}
hr = pIRowset->QueryInterface(IID_IAccessor, (void **) &pIAccessor);
CHKHR_GOTO(hr, L"Failed to obtain Accessor interface", _ExitProcessResultSet);
hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
lNumCols,
pBindings,
0,
&hAccessor,
NULL);
CHKHR_GOTO(hr, L"Failed to create Accessor", _ExitProcessResultSet);
for (idxBinding = 0; idxBinding < lNumCols; idxBinding++)
{
cout << pDBColumnInfo[idxBinding].pwszName << endl;
}
lNumRowsRetrieved = 0;
hr = pIRowset->GetNextRows(
NULL,
0,
1,
&lNumRowsRetrieved,
&pRow);
CHKHR_GOTO(hr, L"Failed to fetch a row from the rowset", _ExitProcessResultSet);
pBuffer = new BYTE[sizeof(DBSTATUS) + sizeof(DBLENGTH) + sizeof(IUnknown*)];
if (!pBuffer)
{
hr = E_OUTOFMEMORY;
goto _ExitProcessResultSet;
}
while(lNumRowsRetrieved && hr != DB_S_ENDOFROWSET)
{
memset(pBuffer, 0, sizeof(DBSTATUS) + sizeof(DBLENGTH) + sizeof(IUnknown*));
hr = pIRowset->GetData(hRows[0], hAccessor, pBuffer);
CHKHR_GOTO(hr, L"Failed to obtain row data", _ExitProcessResultSet);
for (idxBinding = 0; idxBinding < lNumCols; idxBinding++)
{
if (pBindings[idxBinding].wType == DBTYPE_IUNKNOWN)
{
BYTE pbBuff[3000];
ULONG cbNeeded = sizeof(pbBuff)/sizeof(BYTE);
ULONG cbRead;
ULONG cbReadTotal = 0;
ISequentialStream* pISequentialStream = NULL;
IUnknown* pIUnknown = *((IUnknown**)(pBuffer + pBindings[idxBinding].obValue));
pIUnknown->QueryInterface(IID_ISequentialStream, (void**)&pISequentialStream);
do
{
hr = pISequentialStream->Read(pbBuff, cbNeeded, &cbRead);
cbReadTotal += cbRead;
}
while (SUCCEEDED(hr) && hr != S_FALSE && cbRead == cbNeeded);
cout << "Total Bytes Read: " << cbReadTotal << endl;
pISequentialStream->Release();
pISequentialStream = NULL;
pIUnknown->Release();
pIUnknown = NULL;
}
}
pIRowset->ReleaseRows(1, pRow, NULL, NULL, NULL);
hr = pIRowset->GetNextRows(NULL,
0,
1,
&lNumRowsRetrieved,
&pRow);
CHKHR_GOTO(hr, L"Failed to fetch a row from the rowset.", _ExitProcessResultSet);
}
_ExitProcessResultSet:
pIRowset->ReleaseRows(1, pRow, NULL, NULL, NULL);
delete [] pBuffer;
if (pIAccessor)
{
if (hAccessor != DB_NULL_HACCESSOR)
{
pIAccessor->ReleaseAccessor(hAccessor, NULL);
}
pIAccessor->Release();
pIAccessor = NULL;
}
if (pBindings)
{
for (idxBinding = 0; idxBinding < lNumCols; idxBinding++)
{
if (pBindings[idxBinding].pObject)
CoTaskMemFree(pBindings[idxBinding].pObject);
}
}
delete [] pBindings;
CoTaskMemFree(pDBColumnInfo);
CoTaskMemFree(pStringsBuffer);
if (pIColumnsInfo)
{
pIColumnsInfo->Release();
pIColumnsInfo = NULL;
}
return hr;
}
Untuk informasi selengkapnya tentang bagaimana Driver OLE DB untuk SQL Server mengekspos jenis data nilai besar, lihat Blob dan Objek OLE.