VC++实战OLEDB编程(十)——关于延迟提交新增行问题的澄清

来源:互联网 发布:易语言高仿qq2016源码 编辑:程序博客网 时间:2024/04/28 20:17

在“实战OLEDB编程”系列文章中,后面的几篇文章中讨论了一下关于延迟提交的问题,有网友回复说新插入的行无法延迟提交,并说是微软的一个bug,本着怀疑一切和刨根问底的精神,我对这个问题进行了深入的实验和研究,结果发现,这种说法很是不负责任的。现在可以肯定的说新插入行的延迟提交是完全没有任何问题的。

至于为什么有网友说不能延迟提交呢?我也分析了一下原因,结果发现,有个关键原因导致新插入行的延迟提交不可行:

其实最大的罪魁祸首就是绑定的错误,主要就是错误的绑定了第0列,我在“七”文章中发布的完整例子代码中就错误的绑定了第0列,结果我自己也被插入问题搞得焦头烂额,最后我仔细的阅读了OLEDB的帮助后发现,原来InsertRow在失败后,会在你插入数据的列Status中写入具体某一列值插入失败的原因。当时我看到第0列这个状态总是DBSTATUS_E_PERMISSIONDENIED,直译过来就可以理解为是不允许插入,为什么不允许插入呢?疯掉,然后我仔细的看了代码后发现,原来创建绑定结构的循环有问题,原来是:

rgBindings = (DBBINDING*)GRS_ALLOC(cColumns * sizeof(DBBINDING));

for( iCol = 0; iCol < cColumns; iCol++ )

{

  rgBindings[iCol].iOrdinal   = rgColumnInfo[iCol].iOrdinal;

  rgBindings[iCol].dwPart     = DBPART_VALUE

|DBPART_LENGTH|DBPART_STATUS;

  rgBindings[iCol].obStatus   = dwOffset;

  rgBindings[iCol].obLength   = dwOffset + sizeof(DBSTATUS);

  rgBindings[iCol].obValue    = dwOffset+sizeof(DBSTATUS)+sizeof(ULONG);

  rgBindings[iCol].dwMemOwner = DBMEMOWNER_CLIENTOWNED;

  rgBindings[iCol].eParamIO   = DBPARAMIO_NOTPARAM;

  rgBindings[iCol].bPrecision = rgColumnInfo[iCol].bPrecision;

  rgBindings[iCol].bScale     = rgColumnInfo[iCol].bScale;

  rgBindings[iCol].wType      = rgColumnInfo[iCol].wType;

  rgBindings[iCol].cbMaxLen   = rgColumnInfo[iCol].ulColumnSize;

 

  dwOffset = rgBindings[iCol].cbMaxLen + rgBindings[iCol].obValue;

  dwOffset = GRS_ROUNDUP(dwOffset);

}

大家可以注意下iCol的起始值,原来是0?!呵呵呵,看来我也是老糊涂了,怎么就绑到了第0列呢?哈哈哈,口口声声说第0列有特殊用途,结果自己还去绑定它。赶快改成如下模样:

rgBindings = (DBBINDING*)GRS_ALLOC(cColumns * sizeof(DBBINDING));

for( iCol = 1; iCol < cColumns; iCol++ )

{

       rgBindings[iCol - 1].iOrdinal   = rgColumnInfo[iCol].iOrdinal;

       rgBindings[iCol - 1].dwPart     = DBPART_VALUE|DBPART_LENGTH|DBPART_STATUS;

       rgBindings[iCol - 1].obStatus   = dwOffset;

       rgBindings[iCol - 1].obLength   = dwOffset + sizeof(DBSTATUS);

       rgBindings[iCol - 1].obValue    = dwOffset+sizeof(DBSTATUS)+sizeof(ULONG);

       rgBindings[iCol - 1].dwMemOwner = DBMEMOWNER_CLIENTOWNED;

       rgBindings[iCol - 1].eParamIO   = DBPARAMIO_NOTPARAM;

       rgBindings[iCol - 1].bPrecision = rgColumnInfo[iCol].bPrecision;

       rgBindings[iCol - 1].bScale     = rgColumnInfo[iCol].bScale;

       rgBindings[iCol - 1].wType      = rgColumnInfo[iCol].wType;

       rgBindings[iCol - 1].cbMaxLen   = rgColumnInfo[iCol].ulColumnSize;

 

       dwOffset = rgBindings[iCol - 1].cbMaxLen + rgBindings[iCol - 1].obValue;

       dwOffset = GRS_ROUNDUP(dwOffset);

}

这样一来都是从第一列开始绑定,但是这里有个问题,就是如果没有返回第0列那么这个循环就会少绑定一列,当然这难不倒我们,只需要判断rgColumnInfo[0].iOrdinal == 0就可以明确的知道有没有返回第0列,这样循环的上届无非就是最大列数或最大列数减1即可。这个就看实际编码的需要了,当然如何判断和组织这个绑定结构,大家应该不会再有疑问了。

将绑定修改后,我对插入部分做了如下测试:

pCurData    = (BYTE*)pData + (dwOffset * iRow);

//取得一行的数据

GRS_COM_CHECK(pIRowset->GetData(rghRows[iRow],phAccessor,pCurData));

//pCurData中已经包含了结果数据,显示或者进行处理

//......

//复制插入一些行:

pNewData = (BYTE*)GRS_ALLOC(dwOffset);

CopyMemory(pNewData,pCurData,dwOffset);

GRS_COM_CHECK(pIRowsetChange->InsertRow(NULL

,phAccessor,pNewData,&hNewRows));

       //使用相同的行缓冲再插入两行

GRS_COM_CHECK(pIRowsetChange->InsertRow(NULL

,phAccessor,pNewData,&hNewRows));

GRS_COM_CHECK(pIRowsetChange->InsertRow(NULL

,phAccessor,pNewData,&hNewRows));

在最后使用一个Update:

GRS_COM_CHECK(pIRowsetUpdate->Update(NULL,0

,NULL,&dwUpdateRows,&phUpdateRows,&pUpdateStatus));

GRS_COM_CHECK(pIRowset->ReleaseRows(dwUpdateRows

,phUpdateRows,NULL,NULL,NULL));

最后在数据表中就多出来3行相同的数据,至此插入行的延迟提交问题算是圆满的找到答案了,大家可以放心的使用新插入行的延迟提交了。

这里需要总结的就是如何找到插入失败时的问题,就是靠那个列状态,像下面这样查看插入失败后列的状态,然后对应找到DBSTATUS_开头的状态值的宏定义,就可以具体知道插入失败是为什么了:

DBSTATUS*pStatus = (DBSTATUS*)((BYTE*)pNewData + rgBindings[iCol].obStatus);

当然如果*pStatus是0,就说明该列正常,继续查看下一列即可,直到找到状态值不是0的列,找到宏定义,然后查看OLEDB帮助中的说明,就知道是为什么不能插入了。

(未完待续)

原创粉丝点击