Sql server 使用OLE DB插入BLOB

Sql server 使用OLE DB插入BLOB,sql-server,oledb,sql-server-native-client,Sql Server,Oledb,Sql Server Native Client,我正在开发一个应用程序,它使用OLE DB和SQL Server本机客户端访问SQL Server DB。到目前为止,我只处理过相当简单的SQL。为此,我获得了一个ICommandText并使用了SetCommandText。现在我想在数据库中插入一个大对象。我看到ICommandStream是存在的,但使用它似乎需要添加一个实现IStream的类,并适当地引用我的BLOB转义撇号,等等。。当然有更简单的方法吗 旁注:OLE DB不是我的选择,在这个阶段我不能更改它。因此,无法使用更高级的更简单

我正在开发一个应用程序,它使用OLE DB和SQL Server本机客户端访问SQL Server DB。到目前为止,我只处理过相当简单的SQL。为此,我获得了一个ICommandText并使用了SetCommandText。现在我想在数据库中插入一个大对象。我看到ICommandStream是存在的,但使用它似乎需要添加一个实现IStream的类,并适当地引用我的BLOB转义撇号,等等。。当然有更简单的方法吗


旁注:OLE DB不是我的选择,在这个阶段我不能更改它。因此,无法使用更高级的更简单的方法。

blob只是二进制数据,因此您需要使用某种形式的字节数组。

事实证明,存在一个

为了对此进行扩展,下面是我最终使用的代码。首先,您需要一个ISequentialStream,以便SQL Server本机客户端从中读取。我的数据在内存中,所以我可以用一个指向我的BLOB的指针来构造它,但是从其他地方获取数据很简单。这不是合同的一部分,但是知道读取似乎是在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方法。在pSQL中传递的SQL类似于从TableWithBlob中选择x、y、z。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;
使用IRowsetChange为自己准备一个iAccess并将其绑定:

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 Server本机客户端将从流中读取并插入行。跳环现在完成了。ReleaseAccessor、cleanup等已删除。

抱歉,您的回答在OLE DB环境中对我没有帮助。