插入一个BLOB OLE DB
-
20-09-2019 - |
题
我工作上的一个应用程序,它使用的是OLE DB和SQL服务器地客户访问SQL服务器数据库。迄今为止,我们仅只处理相当简单的SQL。为此,我已经获得一个 ICommandText
和使用 SetCommandText
.我现在想要插入一个大型对象进入数据库。我看到 ICommandStream
存在,但它似乎使用这将需要我加一个类实现了 IStream
也引用我的BLOB适当地(逃撇号,等等)。肯定有一个更简单的方法?
附注:OLE DB不是我的选择我不能改变它在这个阶段。因此更容易的方法"使用一些较高级别的"不可用。
解决方案 2
事实证明,还有一个 回答关于Microsoft SQLNCli队的博客.
扩大对这个,这里的代码,我在使用。首先,需要ISequentialStream SQL服务器地客户可以读取。我有我的内存数据,所以我可能只是构建这一指针指向我的斑点,但它是微不足道去,并获得数据从其他地方。这不是合同的一部分,但它也许是有用的,要知道,读似乎发生在1024字节的区块。这是我的流级:
struct ISequentialStream;
class XYZSQLStream : public ISequentialStream
{
public:
XYZSQLStream(LPBYTE data, __int64 ulLength);
virtual ~XYZSQLStream();
virtual BOOL Clear();
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(void __RPC_FAR *pv, ULONG cb, ULONG __RPC_FAR *pcbRead);
STDMETHODIMP Write(const void __RPC_FAR *pv, ULONG cb, ULONG __RPC_FAR *pcbWritten);
private:
ULONG m_cRef; // reference count
void* m_pBuffer; // buffer
ULONG m_cBufSize; // buffer size
ULONG m_iPos; // current index position in the buffer
};
执行这是微不足道的:
XYZSQLStream::XYZSQLStream(LPBYTE data, ULONG ulLength)
{
m_iPos = 0;
m_cRef = 0;
m_pBuffer = data;
m_cBufSize = ulLength;
AddRef();
}
XYZSQLStream::~XYZSQLStream()
{
// Shouldn't have any references left
if (m_cRef)
throw L"Destroying SQLStream with references";
delete[] m_pBuffer;
}
ULONG XYZSQLStream::AddRef()
{
return ++m_cRef;
}
ULONG XYZSQLStream::Release()
{
if (!m_cRef)
throw L"Releasing referenceless SQLStream";
if (--m_cRef)
return m_cRef;
delete this;
return 0;
}
HRESULT XYZSQLStream::QueryInterface(REFIID riid, void** ppv)
{
if (!ppv)
return E_INVALIDARG;
*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 XYZSQLStream::Clear()
{
m_iPos = 0;
m_cBufSize = 0;
m_pBuffer = NULL;
return TRUE;
}
HRESULT XYZSQLStream::Read(void *pv, ULONG cb, ULONG* pcbRead)
{
if (pcbRead)
*pcbRead = 0;
if (!pv)
return STG_E_INVALIDPOINTER;
if (cb == 0)
return S_OK;
ULONG cBytesLeft = m_cBufSize - m_iPos;
ULONG cBytesRead = cb > cBytesLeft ? cBytesLeft : cb;
//DEBUG(L"cb %d, left %d, read %d\n", cb, cBytesLeft, cBytesRead);
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 XYZSQLStream::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;
}
使用 ICommandText
, 你可以再执行一个 SELECT
在表。你不是真要检索数据的任何使用这个,它只是一种方法得到一个 IRowsetChange
.我有一个额外的ExecuteCommand方法。SQL通过在的原因是(类似) SELECT x,y,z FROM TableWithBlob
. FAIL
是一个自定义的宏记录的问题以及返回。
HRESULT XYZSQLCommand::ExecuteCommand(TCHAR* pSQL, IRowset** ppRowSet, IRowsetChange** ppRowSetChange)
{
HRESULT hr;
IRowsetChange* pIRowsetChange;
IRowset* pIRowset;
hr = m_pICommandText->SetCommandText(DBGUID_DBSQL, pSQL);
if (FAILED(hr))
FAIL(hr);
hr = m_pICommandText->Execute(NULL, IID_IRowsetChange, NULL, NULL, (IUnknown**)&pIRowsetChange);
if (FAILED(hr))
FAIL(hr);
hr = pIRowsetChange->QueryInterface(IID_IRowset, (void**)&pIRowset);
if (FAILED(hr))
{
pIRowsetChange->Release();
FAIL(hr);
}
*ppRowSet = pIRowset;
*ppRowSetChange = pIRowsetChange;
return S_OK;
}
我现在有一个IRowset和IRowsetChange表中的问题。你随后建造一个 DBBINDING
你通常会。我没有这个-这不是真的相关问题。有关位是:
static DBOBJECT streamObj = {STGM_READ, IID_ISequentialStream};
pDBBindings[nCol].pObject = &streamObj;
pDBBindings[nCol].wType = DBTYPE_IUNKNOWN;
pDBBindings[nCol].cbMaxLen = sizeof(ISequentialStream*);
当随后填写的匹配数据存储块的,然后你可以这样做(对不起丑恶的雾):
XYZSQLStream *stream = new XYZSQLStream(data_to_write, length_of_data);
*((ISequentialStream**)(pbData+pDBBindings[x].obValue)) = stream;
*((DBLENGTH*)(pbData+pDBBindings[x].obLength)) = (DBLENGTH)length_of_data;
*((DBSTATUS*)(pbData+pDBBindings[x].obStatus)) = DBSTATUS_S_OK;
让自己一个 IAccessor
用你 IRowsetChange
并将它:
IAccessor* pIAccessor;
HACCESSOR hAccessor;
DBBINDSTATUS* pDBBindStatus;
hr = pRowsetChange->QueryInterface(IID_IAccessor, (void**) &pIAccessor);
// Error handling elided
pDBBindStatus = new DBBINDSTATUS[ulCols];
//Associate the bindings with the data accessor for the rowset
hr = pIAccessor->CreateAccessor( DBACCESSOR_ROWDATA, ulCols, pDBBindings, 0, hAccessor, pDBBindStatus);
// Error handling, cleanup elided
最后,你可以插入你的行:
hr = pRowsetChange->InsertRow(NULL, hAccessor, pbData, NULL);
SQL服务器地客户将从中读取你的流入行。箍-跳跃是现在做的。 ReleaseAccessor
, 清除,等等。省略.
其他提示
一个斑点只是二进制数据,所以就需要使用某种形式的字节数组的。