在我的应用程序中,我试图从VARCHAR(4000)列中读取数据。由于列是4000字节,我有一个足够大的应用程序缓冲区来处理它。但目前我在列中只有10个字节的数据。在做了IRow-> GetColumns()之后,不确定如何只复制10个字节的数据。我执行以下操作,但获取所有4000个字节,因此在打印数据时,它是用3990个空格填充的实际数据的10个字符。
retcode = WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)pDBColumnAccess[nCol].pData, -1, (char *)pReadBuf, pDBColumnAccess[nCol].cbDataLen, NULL, NULL);
我认为pDBColumnAccess.cbDataLen只有10,但它的值为4000。
如何从列中读取确切的字节数?
感谢。
答案 0 :(得分:0)
找出一种方法,不确定这是实际的解决方案还是只是一种解决方法。
如果在创建表之前将ANSI_PADDING设置为OFF,则不会在实际数据之后填充空格。您可以在表的sp_help中看到属性值“TrimTrailingBlanks”。
感谢。
答案 1 :(得分:0)
您应该设置包含DBPART_LENGTH的DBBINDING以获取字段的长度。为了说明这一点,我使用以下DDL在SQL Server中创建了一些VARCHAR数据:
CREATE TABLE NEWS
(
ID INT NOT NULL,
ARTICLE NVARCHAR(4000)
);
INSERT INTO NEWS (1, 'Today is a sunny day.');
然后我使用以下基于ATL的C ++代码示例来读取ARTICLE字段。如果在代码中放置断点,您将看到它将以
返回以下是代码示例示例:
#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;
}