適用於:SQL Server
Azure SQL 資料庫
Azure SQL 受控執行個體
Azure Synapse Analytics
Analytics Platform System (PDW)
重要
SQL Server Native Client (SNAC) 未隨附:
- SQL Server 2022 (16.x) 及更新版本
- SQL Server Management Studio 19 與更新版本
不建議使用 SQL Server Native Client (SQLNCLI 或 SQLNCLI11) 和舊版 Microsoft OLE DB Provider for SQL Server (SQLOLEDB) 進行新的應用開發。
針對新專案,請使用下列其中一個驅動程式:
針對 SQL Server 資料庫引擎 (2012 到 2019 版) 的隨附元件 SQLNCLI,請參閱支援生命週期例外狀況。
在 SQL Server 2005 (9.x) 之前,使用大數值資料類型需要經過特殊處理。 大型實值數據類型是超過8 KB的數據列大小上限的數據類型。 SQL Server 2005 (9.x) 引進了 varchar、nvarchar 和 varbinary 數據類型的最大規範,以允許儲存大小為 2^31 -1 個字節的值。 數據表數據行和 Transact-SQL 變數可以指定 varchar(max)、 nvarchar(max) 或 varbinary(max) 數據類型。
注意
大型實值數據類型的大小上限可以介於 1 到 8 KB 之間,也可以指定為無限制。
先前,只有 text、ntext 和 image 等 SQL Server 數據類型可以達到這類長度。 varchar、nvarchar 和 varbinary 的最大規範使得這些數據類型備援。 不過,由於仍可使用長數據類型,因此 OLE DB 和 ODBC 數據存取元件的大部分介面都會維持不變。 為了與舊版的回溯相容性,SQL Server Native Client OLE DB 提供者中的DBCOLUMNFLAGS_ISLONG旗標,而 SQL Server Native Client ODBC 驅動程式中的SQL_LONGVARCHAR仍使用中。 當新類型設定為無限制的最大長度時,可繼續使用專為 SQL Server 2005 (9.x) 和更新版本所撰寫的提供者和驅動程式詞彙。
注意
您也可以將 varchar(max) 、nvarchar(max) 和 varbinary(max) 資料類型指定為預存程序的輸入和輸出參數類型、函數傳回型別,或者指定於 CAST 和 CONVERT 函數。
注意
如果復寫數據,您可能需要將 max text repl size 伺服器組態選項 設定為 -1。
SQL Server Native Client OLE DB 提供者
SQL Server Native Client OLE DB 提供者會 分別將 varchar(max)、 varbinary(max)和 nvarchar(max) 類型公開為 DBTYPE_STR、DBTYPE_BYTES 和 DBTYPE_WSTR。
數據類型 varchar(max)、varbinary(max)和 nvarchar(max)在設定為無限制大小上限的數據行中,會透過核心 OLE DB 架構數據列集和傳回數據行數據類型的介面來表示為 ISLONG。
命令物件的 IAccessor 實作已變更為允許以 DBTYPE_IUNKNOWN 的形式進行繫結。 如果取用者指定 DBTYPE_IUNKNOWN 並將 pObject 設定為 null,則提供者會將 ISequentialStream 介面傳回給取用者,讓取用者可以將 varchar(max) 、nvarchar(max) 或 varbinary(max) 用資料流的形式傳出輸出變數。
以資料流傳輸的輸出參數值會在任何結果資料列之後傳回。 如果應用程式藉由呼叫 IMultipleResults::GetResult (而不取用所有的傳回輸出參數值) 嘗試繼續前往下一個結果集,就會傳回 DB_E_OBJECTOPEN。
為了支援串流,SQL Server Native Client OLE DB 提供者需要循序存取可變長度參數。 這表示每當
SQL Server Native Client OLE DB 提供者也支援將輸出參數係結為大型實值數據類型的DBTYPE_IUNKNOWN,以利預存程式將大型實值型別當做傳回值公開給用戶端 DBTYPE_IUNKNOWN的傳回值案例。
為了使用這些類型,應用程式具有下列選項:
系結為具有數據行基底類型的支持系結的類型(例如 nvarchar(max),系結為可以系結至 nvarchar 的類型。 如果緩衝區不夠大,就會發生截斷,就基底類型而言,雖然現在可以使用較大的值。
繫結為具有資料行基底類型所支援轉換的類型,並同時指定 DBTYPE_BYREF。
繫結為 DBTYPE_IUNKNOWN 並使用資料流。
報告數據行的大小上限時,SQL Server Native Client OLE DB 提供者將會報告:
定義的大小上限,例如 varchar(2000) 數據行為 2000,或
值 “unlimited”,如果 varchar(max) 數據行等於 ~0,則為 。 這個值會針對 DBCOLUMN_COLUMNSIZE 中繼資料屬性設定。
標準轉換規則適用於 varchar(max) 資料行,代表任何對 varchar( 2000 ) 資料行有效的轉換也對 varchar(max) 資料行有效。 相同的規則也適用於 nvarchar(max) 和 varbinary(max) 資料行。
在擷取大數值類型時,最有效的方法是繫結為 DBTYPE_IUNKNOWN,並將資料列集屬性 DBPROP_ACCESSORDER 設定為 DBPROPVAL_AO_SEQUENTIALSTORAGEOBJECTS。 這會導致值直接從沒有中繼緩衝的網路串流處理,如下列範例所示:
#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 "sqlncli.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_SQLNCLI11,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDBInitialize,
(void**)&pIDBInitialize);
CHKHR_GOTO(hr, L"Failed to create SQLNCLI11 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;
}
如需 SQL Server Native Client OLE DB 提供者如何公開大型實值數據類型的詳細資訊,請參閱 BLOB 和 OLE 物件。
SQL Server Native Client ODBC Driver
SQL Server Native Client ODBC 驅動程式會將 varchar(max)、 varbinary(max) 和 nvarchar(max) 類型公開為接受或傳回 ODBC SQL 數據類型之 ODBC API 函式中的SQL_VARCHAR、SQL_VARBINARY和SQL_WVARCHAR。
報告數據行的大小上限時,驅動程式會回報下列其中一項:
定義的大小上限,例如 varchar(2000) 數據行為 2000,或
值 “unlimited”,其中 varchar(max) 數據行等於 0。
標準轉換規則會套用至 varchar(max) 數據行,這表示對於 varchar(2000) 數據行有效的任何轉換,也適用於 varchar(max) 數據行。 相同的規則也適用於 nvarchar(max) 和 varbinary(max) 資料行。
以下是已增強以使用大型實值資料類型的 ODBC API 函式清單: