Извлечение данных столбца с помощью IRow :: GetColumns (OLE DB) (MSSQL) - PullRequest
0 голосов
/ 29 сентября 2011

В моем приложении я пытаюсь прочитать данные из столбца VARCHAR (4000).Поскольку размер столбца составляет 4000 байт, у меня есть буфер приложения, который достаточно велик для его обработки.Но на данный момент у меня есть только 10 байтов данных в столбце.После выполнения IRow-> GetColumns (), не уверен, как скопировать только 10 байтов данных.Я делаю следующее, но получаю все 4000 байтов, поэтому, когда данные печатаются, это 10 символов фактических данных, дополненных 3990 пробелами.

retcode = WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)pDBColumnAccess[nCol].pData, -1, (char *)pReadBuf, pDBColumnAccess[nCol].cbDataLen, NULL, NULL);

Я думал, что pDBColumnAccess.cbDataLen будет иметь только 10, но имеет значение 4000.

Как прочитать точное количество байтов из столбца?

Спасибо.

Ответы [ 2 ]

0 голосов
/ 02 февраля 2012

Вы должны установить DBBINDING, который включает DBPART_LENGTH, чтобы получить длину поля.Чтобы проиллюстрировать это, я создал некоторые данные VARCHAR в SQL Server, используя следующий DDL:

CREATE TABLE NEWS
(
    ID INT NOT NULL,
    ARTICLE NVARCHAR(4000)
);
INSERT INTO NEWS (1, 'Today is a sunny day.');

Затем я использую следующий пример кода C ++ на основе ATL для чтения поля ARTICLE.Если вы установите точки останова в коде, вы увидите, что он вернется с

  • data.nArticleLength = 21
  • data.szArticle = "Сегодня солнечный день."

Вот пример кода:

#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <oledb.h>
#include <atlbase.h>

int _tmain(int argc, _TCHAR* argv[])
{
    HRESULT hr = S_OK;
    hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);

    // Connect to SQL Server.
    CComPtr<IDBInitialize> spIDBInitialize;
    hr = spIDBInitialize.CoCreateInstance(OLESTR("SQLNCLI"));
    CComPtr<IDBProperties> spIDBProperties;
    hr = spIDBInitialize->QueryInterface(IID_IDBProperties, (void**) &spIDBProperties);
    CComVariant varDataSource(OLESTR("InsertYourSQLServer"));
    CComVariant varCatalog(_T("InsertYourDatabase"));
    CComVariant varUserID(_T("InsertYourUserName"));
    CComVariant varPassword(_T("InsertYourPassword"));
    DBPROP rgProps[4] =
    {
        { DBPROP_INIT_DATASOURCE, DBPROPOPTIONS_REQUIRED, 0, DB_NULLID, varDataSource },
        { DBPROP_INIT_CATALOG, DBPROPOPTIONS_REQUIRED, 0, DB_NULLID, varCatalog },
        { DBPROP_AUTH_USERID, DBPROPOPTIONS_REQUIRED, 0, DB_NULLID, varUserID },
        { DBPROP_AUTH_PASSWORD, DBPROPOPTIONS_REQUIRED, 0, DB_NULLID, varPassword }
    };
    DBPROPSET propSet = {rgProps, 4, DBPROPSET_DBINIT};
    hr = spIDBProperties->SetProperties(1, &propSet);
    spIDBProperties = NULL;
    hr = spIDBInitialize->Initialize();

    // Execute the query.
    CComPtr<IDBCreateSession> spIDBCreateSession;
    hr = spIDBInitialize->QueryInterface(IID_IDBCreateSession, (void**) &spIDBCreateSession);
    CComPtr<IDBCreateCommand> spIDBCreateCommand;
    hr = spIDBCreateSession->CreateSession(NULL, IID_IDBCreateCommand, (IUnknown**) &spIDBCreateCommand);
    spIDBCreateSession = NULL;
    CComPtr<ICommandText> spICommandText;
    hr = spIDBCreateCommand->CreateCommand(NULL, IID_ICommandText, (IUnknown**) &spICommandText);
    spIDBCreateCommand = NULL;
    hr = spICommandText->SetCommandText(DBGUID_SQL, OLESTR("SELECT ID, ARTICLE FROM NEWS"));
    DBROWCOUNT cRowsAffected = 0;
    CComPtr<IRowset> spIRowset;
    hr = spICommandText->Execute(NULL, IID_IRowset, NULL, &cRowsAffected, (IUnknown**) &spIRowset);
    spICommandText = NULL;

    // Retrieve records.
    HROW hRow = NULL;
    HROW *rghRow = &hRow;
    DBCOUNTITEM cRowsObtained = 0;
    hr = spIRowset->GetNextRows(DB_NULL_HCHAPTER, 0, 1, &cRowsObtained, &rghRow);
    while (hr == S_OK && cRowsObtained == 1)
    {
        // Fetch the ARTICLE field.
        struct
        {
            DBSTATUS dbArticleStatus;
            ULONG nArticleLength;
            char szArticle[4000 + 4];
        } data = {0};
        DBBINDING Binding = {0};
        Binding.iOrdinal    = 2;
        Binding.obValue     = sizeof(DBSTATUS) + sizeof(ULONG);
        Binding.obLength    = sizeof(DBSTATUS);
        Binding.obStatus    = 0;
        Binding.pTypeInfo   = NULL;
        Binding.pObject     = NULL;
        Binding.pBindExt    = NULL;
        Binding.dwPart      = DBPART_STATUS | DBPART_LENGTH | DBPART_VALUE;
        Binding.dwMemOwner  = DBMEMOWNER_CLIENTOWNED;
        Binding.eParamIO    = DBPARAMIO_NOTPARAM;
        Binding.cbMaxLen    = 4000 + 1;
        Binding.wType       = DBTYPE_STR;
        Binding.dwFlags     = 0;
        Binding.bPrecision  = 0;
        Binding.bScale      = 0;
        CComPtr<IAccessor> spIAccessor;
        hr = spIRowset->QueryInterface(IID_IAccessor, (void**) &spIAccessor);
        HACCESSOR hAccessor = NULL;
        hr = spIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1, &Binding, 0, &hAccessor, NULL);
        hr = spIRowset->GetData(hRow, hAccessor, &data);
        DBREFCOUNT cRefCount = 0;
        hr = spIAccessor->ReleaseAccessor(hAccessor, &cRefCount);
        spIAccessor = NULL;

        // @@TODO: Do something with data.szArticle and data.nArticleLength
        // ...

        // Fetch next row of data.
        hr = spIRowset->ReleaseRows(1, rghRow, NULL, NULL, NULL);
        cRowsObtained = 0;
        hr = spIRowset->GetNextRows(DB_NULL_HCHAPTER, 0, 1, &cRowsObtained, &rghRow);
    }

    // Release everything
    spIRowset = NULL;
    spIDBInitialize = NULL;

    CoUninitialize();
    return 0;
}
0 голосов
/ 30 сентября 2011

Придумал способ для этого, не уверенный, является ли это реальным решением или просто обходным путем.

Если ANSI_PADDING установлен в OFF перед созданием таблицы, заполнение пробелов после фактических данных не произойдет. Вы можете увидеть значение свойства "TrimTrailingBlanks" в таблице sp_help.

Спасибо.

...