在VC中用OLE DB讀寫SQL Server中的BLOB欄位 (轉)
首先,應當從ISequentialStream派生一個類,其頭如下(SeqStream.h):
//SeqStream.h
#if !defined (CSEQSTREAM_H)
#define CSEQSTREAM_H
:namespace prefix = o ns = "urn:schemas--com::office" />
class CSeqStream : public ISequentialStream
{
public:
//Constructors
CSeqStream();
virtual ~CSeqStream();
virtual BOOL Seek(ULONG iPos);
virtual BOOL Clear();
virtual BOOL CompareData(void* pBuffer);
virtual ULONG Length() { return m_cBufSize; };
virtual operator void* const() { return m_pBuffer; };
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppv);
STDMETHODIMP Read(
/* [out] */ void __RPC_FAR *pv,
/* [in] */ ULONG cb,
/* [out] */ ULONG __RPC_FAR *pcbRead);
STDMETHODIMP Write(
/* [in] */ const void __RPC_FAR *pv,
/* [in] */ ULONG cb,
/* [out]*/ ULONG __RPC_FAR *pcbWritten);
void ResetPosition();
protected:
//Data
private:
ULONG m_cRef; // reference count
void* m_pBuffer; // buffer
ULONG m_cBufSize; // buffer size
ULONG m_iPos; // current index position in the buffer
};
#endif
實現檔案如下(SeqStream.cpp):
#include "stdafx.h"
#include "SeqStream.h "
CSeqStream::CSeqStream()
{
m_iPos = 0;
m_cRef = 0;
m_pBuffer = NULL;
m_cBufSize = 0;
//The constructor AddRef's
AddRef();
}
CSeqStream::~CSeqStream()
{
//Shouldn't have any references left
// ASSERT(m_cRef == 0);
CoTaskMemFree(m_pBuffer);
}
ULONG CSeqStream::AddRef(void)
{
return ++m_cRef;
}
ULONG CSeqStream::Release(void)
{
// ASSERT(m_cRef);
if(--m_cRef)
return m_cRef;
delete this;
return 0;
}
HRESULT CSeqStream::QueryInterface(REFIID riid, void** ppv)
{
// ASSERT(ppv);
*ppv = NULL;
if (riid == IID_IUnknown)
*ppv = this;
if (riid == IID_ISequentialStream)
*ppv = this;
if(*ppv)
{
((IUnknown*)*ppv)->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
BOOL CSeqStream::Seek(ULONG iPos)
{
//Make sure the desired position is within the buffer
// ASSERT(iP== 0 || iPos < m_cBufSize);
//Reset the current buffer position
m_iPos = iPos;
return TRUE;
}
BOOL CSeqStream::Clear()
{
//Frees the buffer
m_iPos = 0;
m_cBufSize = 0;
CoTaskMemFree(m_pBuffer);
m_pBuffer = NULL;
return TRUE;
}
BOOL CSeqStream::CompareData(void* pBuffer)
{
// ASSERT(pBuffer);
//Quick and easy way to compare user buffer with the stream
return memcmp(pBuffer, m_pBuffer, m_cBufSize)==0;
}
HRESULT CSeqStream::Read(void *pv, ULONG cb, ULONG* pcbRead)
{
//Parameter checking
if(pcbRead)
*pcbRead = 0;
if(!pv)
return STG_E_INVALIDPOINTER;
if(cb == 0)
return S_OK;
//Actual code
ULONG cBytesLeft = m_cBufSize - m_iPos;
ULONG cBytesRead = cb > cBytesLeft ? cBytesLeft : cb;
//if no more bytes to retrieve return
if(cBytesLeft == 0)
return S_FALSE;
//Copy to users buffer the number of bytes requested or remaining
memcpy(pv, (void*)((BYTE*)m_pBuffer + m_iPos), cBytesRead);
m_iPos += cBytesRead;
if(pcbRead)
*pcbRead = cBytesRead;
if(cb != cBytesRead)
return S_FALSE;
return S_OK;
}
HRESULT CSeqStream::Write(const void *pv, ULONG cb, ULONG* pcbWritten)
{
//Parameter checking
if(!pv)
return STG_E_INVALIDPOINTER;
if(pcbWritten)
*pcbWritten = 0;
if(cb == 0)
return S_OK;
//Enlarge the current buffer
m_cBufSize += cb;
//Need to append to the end of the stream
m_pBuffer = CoTaskMemRealloc(m_pBuffer, m_cBufSize);
memcpy((void*)((BYTE*)m_pBuffer + m_iPos), pv, cb);
m_iPos += cb;
if(pcbWritten)
*pcbWritten = cb;
return S_OK;
}
void CSeqStream::ResetPosition()
{
m_iPos=0;
}
設要從一個檔案讀資料寫入到中的一個BLOB欄位,在SQL Server中的Table名為tMaterials,它的Key為MaterialID,BLOB欄位名為Stream。 寫入BLOB欄位資料時可用如下的方法:
BOOL SetBLOBData(WCHAR *awcname,CString strFile)
{
DB ObjectStruct;
ObjectStruct.dwFlags = STGM_READ;
ObjectStruct.iid = IID_ISequentialStream;
struct BLOBDATA
{
DBSTATUS dwStatus;
D dwLength;
ISequentialStream* pISeqStream;
};
BLOBDATA BLOBGetData;
BLOBDATA BLOBSetData;
const ULONG cBindings = 1;
DBBINDING rgBindings[cBindings];
HRESULT hr = S_OK;
IAccessor* pIAccessor = NULL;
ICommandProperties* pICommandProperties = NULL;
IRowsetChange* pIRowsetChange = NULL;
IRowset* pIRowset = NULL;
CSeqStream* pMySeqStream = NULL;
ULONG cRowsObtained = 0;
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
DBBINDSTATUS rgBindStatus[cBindings];
HROW* rghRows = NULL;
const ULONG cPropSets = 1;
DBPROPSET rgPropSets[cPropSets];
const ULONG cProperties = 1;
DBPROP rgProperties[cProperties];
rgPropSets[0].guidPropertySet = DBPROPSET_ROWSET;
rgPropSets[0].cProperties = cProperties;
rgPropSets[0].rgProperties = rgProperties;
rgPropSets[0].rgProperties[0].dwPropertyID = DBPROP_UPDATABILITY;
rgPropSets[0].rgProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;
rgPropSets[0].rgProperties[0].dwStatus = DBPROPSTATUS_OK;
rgPropSets[0].rgProperties[0].colid = DB_NULLID;
rgPropSets[0].rgProperties[0].vValue.vt = VT_I4;
V_I4(&rgPropSets[0].rgProperties[0].vValue) = DBPROPVAL_UP_CHANGE;
//設定Rowset屬性
hr = g_pICommandText->QueryInterface(IID_ICommandProperties,
(void **)&pICommandProperties);
if (FAILED(hr))
{
TRACE0("Failed to get ICommandProperties to set rowset properties.n");
return FALSE;
}
hr = pICommandProperties->SetProperties(cPropSets, rgPropSets);
if (FAILED(hr))
{
TRACE0("Execute failed to set rowset properties.n");
return FALSE;
}
//命令
CString strSql;
strSql.Format(" Stream FROM tMaterials WHERE MaterialID = %s ",gToQuote(awcname));
int nlen=strSql.GetLength();
wchar_t *pSql=(wchar_t*)malloc(nlen*sizeof(wchar_t));
mbstowcs(pSql,strSql.GetBuffer(MAX_PATH),nlen);
if (FAILED(hr = g_pICommandText->SetCommandText(DBGUID_DBSQL,
pSql)))
{
TRACE0("failed");
return FALSE;
}
hr = g_pICommandText->Execute(NULL, IID_IRowsetChange, NULL, NULL,
(IUnknown**)&pIRowsetChange);
if (FAILED(hr))
{
TRACE0("Failed to execute the commandn");
return FALSE;
}
rgBindings[0].iOrdinal = 1; //你的BLOB欄位的位置(從1開始),改為你所需要的
rgBindings[0].obValue = offsetof(BLOBDATA, pISeqStream);
rgBindings[0].obLength = offsetof(BLOBDATA, dwLength);
rgBindings[0].obStatus = offsetof(BLOBDATA, dwStatus);
rgBindings[0].pTypeInfo = NULL;
rgBindings[0].pObject = &ObjectStruct;
rgBindings[0].pBindExt = NULL;
rgBindings[0].dwPart = DBPART_VALUE | DBPART_STATUS | DBPART_LENGTH;
rgBindings[0].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
rgBindings[0].eParamIO = DBPARAMIO_NOTPARAM;
rgBindings[0].cbMaxLen = 0;
rgBindings[0].dwFlags = 0;
rgBindings[0].wType = DBTYPE_IUNKNOWN;
rgBindings[0].bPrecision = 0;
rgBindings[0].bScale = 0;
hr = pIRowsetChange->QueryInterface(IID_IAccessor,
(void**)&pIAccessor);
if (FAILED(hr))
{
TRACE0("Failed to get IAccessor interface.n");
return FALSE;
}
hr = pIAccessor->CreateAccessor(CCESSOR_ROWDATA,
cBindings,
rgBindings,
sizeof(BLOBDATA),
&hAccessor,
rgBindStatus);
if (FAILED(hr))
{
TRACE0("Failed to create an accessor.n");
return FALSE;
}
hr = pIRowsetChange->QueryInterface(IID_IRowset,
(void **)&pIRowset);
if (FAILED(hr))
{
TRACE0("Failed to get IRowset interface.n");
return FALSE;
}
hr = pIRowset->GetNextRows(NULL,0, 1,&cRowsObtained,&rghRows);
hr = pIRowset->GetData(rghRows[0],
hAccessor,
&BLOBGetData);
if (BLOBGetData.dwStatus == DBSTATUS_S_ISNULL)
//在資料庫的當前欄位為NULL
TRACE0("Provr returned a null value.n");
else if(BLOBGetData.dwStatus == DBSTATUS_S_OK)
{
//在這裡,從服務端為你分配的ISequentialStream介面讀入BLOB資料
//BLOBGetData.pISeqStream->Read(pBuffer,cBytes,&cBytesRead);
//無論你是否有讀資料,
SAFE_RELEASE(BLOBGetData.pISeqStream);
}
//生成一個新的Stream.
pMySeqStream = new CSeqStream();
//開始從檔案中讀資料寫入資料庫
CFile fle;
if (fle.Open(strFile,CFile::modeRead))
{
const ULONG cBytes = 4096;
BYTE pWriteData[cBytes]; //從這個陣列寫入BLOB資料
memset(pWriteData, '', cBytes);
UINT nRead=0;
nRead=fle.Read(pWriteData,cBytes);
while (nRead>0)
{
pMySeqStream->Write(pWriteData,nRead,NULL);
nRead=fle.Read(pWriteData,cBytes);
}
fle.Close();
//一定要執行此句,重設Stream當前位置到它的最開始處
pMySeqStream->ResetPosition();
BLOBSetData.pISeqStream = (ISequentialStream*)pMySeqStream;
BLOBSetData.dwStatus = DBSTATUS_S_OK;
BLOBSetData.dwLength = pMySeqStream->Length();
//將BLOB資料寫入到資料庫.
hr = pIRowsetChange->SetData(rghRows[0],
hAccessor,
&BLOBSetData);
if (FAILED(hr))
{
TRACE0("Failed to set data.n");
return FALSE;
}
}
else
{
AfxMessageBox(strFile+"不能開啟檔案!",MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
hr = pIAccessor->ReleaseAccessor(hAccessor, NULL);
if (FAILED(hr))
{
TRACE0("Failed to release accessor.n");
return TRUE;
}
hr = pIRowset->ReleaseRows(cRowsObtained,
rghRows,
NULL,
NULL,
NULL);
if (FAILED(hr))
TRACE0("Failed to release rows.n");
return TRUE;
}
你可以直接Copy以下程式碼,只需改動一下SQL語句即可。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-988409/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- DB2_更新SQL欄位DB2SQL
- 關於Thinkphp 使用AdvModel來讀取Blob欄位PHP
- SQL Server中獲取資料庫名、表名、欄位名和欄位註釋的SQL語句SQLServer資料庫
- MySQL中TEXT與BLOB欄位型別的區別MySql型別
- 在 SQL Server 中,建立表時可以直接為欄位新增唯一約束(UNIQUE)SQLServer
- 如何更換Azure SQL DB blob storage credentialsSQL
- SQL Server 查詢表註釋和欄位SQLServer
- 如何在PL/SQL中讀寫檔案(轉)SQL
- 《NET CLR via C#》---第七章(常量,讀/寫欄位,可讀欄位)C#
- PHP 操作 mysql blob 資料型別的欄位PHPMySql資料型別
- Sql查詢 一個表中某欄位的資料在另一個表中某欄位中不存在的SQL
- 地理位置經緯度在Mysql中用什麼欄位型別MySql型別
- 微軟改變資料訪問策略 OLE DB再次轉向ODBCOS微軟
- DB2 SQL改寫DB2SQL
- mysql sql同一個欄位多個行轉成一個欄位查詢MySql
- Q&A:在SQL Server 2005中編寫儲存過程RVSQLServer儲存過程
- Java mysql blob 資料讀寫操作JavaMySql
- [SQL]group by和order by是否能寫欄位別名SQL
- DB 合併多個欄位的模糊檢索
- Oracle資料庫連結(DBLink)中如何訪問包含BLOB欄位的資料Oracle資料庫
- 如何寫出更快的 SQL (db2)SQLDB2
- MS SQL 替換欄位中的 u00a0SQL
- DataGear 變更部署資料庫為SQL Server填坑指南(含轉寫後的SQL server程式碼及SQL server配置檔案)資料庫SQLServer
- JSON欄位型別在ORM中的使用JSON型別ORM
- sql語句修改欄位型別和增加欄位SQL型別
- SQL Server關於AlwaysOn的理解-讀寫分離的誤區(一)SQLServer
- 讀入寫出,轉二進位制
- 為SQL Server快照snapshot DB建立login訪問SQLServer
- DB2 和SQL Server自增列比較DB2SQLServer
- mybatis查詢mysql 資料庫中 BLOB欄位,結果出現亂碼MyBatisMySql資料庫
- mybatis&plus系列------Mysql的JSON欄位的讀取和轉換MyBatisMySqlJSON
- Spark SQL 欄位血緣在 vivo 網際網路的實踐SparkSQL
- sqlserver採集欄位的sql語句SQLServer
- SAP MIGO 報錯-在例程WERT_SIMULIEREN欄位NEUER_PREIS中欄位溢位-Go
- sql 統計多個欄位的和(如果欄位中含有 null 的處理)SQLNull
- SQL字元型欄位按數字型欄位排序實現方法SQL字元排序
- 正確讀取SQL Server中的擴充套件事件SQLServer套件事件
- Lazarus中對mysql資料庫Blob型別進行讀寫例子MySql資料庫型別
- 使用SQL-Server分割槽表功能提高資料庫的讀寫效能SQLServer資料庫