本文源于最近修正的一个关于psqlodbc的bug,该bug在近期的psqlodbc的git上也有人提交了修正。

关于该bug的修正代码可以看这里:

https://git.postgresql.org/gitweb/?p=psqlodbc.git;a=commit;h=85f6fade3

说道这个bug,我们要提ODBC提供的两个API函数:SQLBulkOperations 和 SQLSetPos

关于这两个函数,它们的用处是:

SQLBulkOperations执行大容量插入和大容量书签操作(包括update、 delete和fetch)。
SQLSetPos函数设置在行集中的游标位置,并允许应用程序刷新行集中的数据或用于更新或删除在结果集中的数据。当利用SQLSetPos删除数据时,操作设置为 SQL_DELETE并且将RowNumber设置为要删除的行号(当设置RowNumber为0时删除结果集中的所有数据)

说白了就是你先用SQLExecute或者SQLExecDirect函数执行SQL文获取一个结果集,然后对这个结果集进行操作。bug发生的场景是DELETE的时候,即我们对结果集中的数据进行删除时发生。在对结果集的数据进行删除时,会调用Adddeleted()函数将结果集中被删除的数据的行号、状态信息和oid,ctid等做记录,保存在一个结构体数组中。而结构体数组在设计是要求按照递增的顺序进行存储的,所以你进行每一次删除可能就要对这个结构体数组做排序操作。问题就在这个排序过程中,排序的时候本应该是依次遍历数组,每次for循环结束count+1,结果它这里直接是count+num_field(这个是结果集的列数),所以,只要返回的结果集的列数大于1,bug就应该发生。

似乎就是这样清楚明白。

我们按照以下的构造再现程序:

(1)	调用SQLSetStmtAttr函数设置SQL文的SQL_ATTR_ROW_ARRAY_SIZE属性值大于1;
(2) 调用SQLExecute或者SQLExecDirect函数执行SQL文;
(3) 调用SQLFetch或SQLFetchScroll函数获取结果集;
(4) (3)中返回的结果集的列数大于1;
(5) (3)中返回的结果集的行数大于1;
(6) 调用ODBC的API函数SQLSetPos或者SQLBulkOperations删除(2)中返回的结果集中的数据;
(7) (6)中删除的记录行数超过一行

说明:SQL_ATTR_ROW_ARRAY_SIZE

指定每次调用SQLFetch或SQLFetchScroll函数返回的结果集行数。 它也用于指定SQLBulkOperations函数的大容量书签操作中的书签数组中的行数。 默认值为 1。

让程序返回了50条数据,但是我们就是再现不出来。无奈,无意中我把返回的结果集增大到了200,结果居然在现了。

奇怪,这个bug和结果集的行数无关啊。

带着这个疑问,我调试了代码:

在AddDeleted()函数的开头,有这样的语句:

	if (!QR_get_cursor(res))
return TRUE;

当结果集函数较小时,直接在这里就返回了。。。也就是说这个时候没有游标了。可是使用SQLExecute()执行SQL、文是默认有游标打开的,程序从游标中获取数据的。不服输的我又在测试程序开头显示地指定了游标:

SQLSetCursorName(hstmt, "C1", SQL_NTS);

还是一模一样的结果。很奇怪。于是我打开了ODBC数据源的mylog和commonlog:

发现:

这个游标居然被关闭了!!!

不可思议。

于是我查询了相关资料,得到以下的认识:

3.ODBC数据源的cache size

每次执行SQLExecute或者SQLExecDirect函数执行SQL文时,程序底层是调用游标一次性返回cache size大小行数的结果集到ODBC数据源的缓存。如果SQL文返回的结果集行数不超过cache size(即ODBC数据源的缓存能缓存下SQL文的所有结果集),那么ODBC数据源会关闭该游标。否则ODBC数据源会保持该游标。

也就是说,这个是ODBC自己的缓存机制。

于是我修改再现程序:

(1)	调用SQLSetStmtAttr函数设置SQL文的SQL_ATTR_ROW_ARRAY_SIZE属性值大于1;
(2) 调用SQLExecute或者SQLExecDirect函数执行SQL文;
(3) (2)中SQL文返回的行数大于ODBC数据源的cache size;
(4) 调用SQLFetch或SQLFetchScroll函数获取结果集;
(5) (4)中返回的结果集的列数大于1;
(6) (4)中返回的结果集的行数大于1;
(7) 调用ODBC的API函数SQLSetPos或者SQLBulkOperations删除(2)中返回的结果集中的数据;
(8) (7)中删除的记录行数超过一行

再现了该bug。

从一个bug谈谈psqlodbc游标的一点认识的更多相关文章

  1. 由一个bug引发的SQLite缓存一致性探索

    问题 我们在生产环境中使用SQLite时中发现建表报“table xxx already exists”错误,但DB文件中并没有该表.后面才发现这个是SQLite在实现过程中的一个bug,而这个bug ...

  2. 是uibutton跟tableviewcell同步使用一个bug

    这个问题是uibutton跟tableviewcell同步使用一个bug,不关delay一点毛事,证据就是点击事件没问题,so,搜到一个方法解决了这个问题.uibutton分类symbian2+ios ...

  3. 有人向我反馈了一个bug

    我是一个前端开发者,但我想这个故事对任何开发者都会引起共鸣的有人向你反馈了一个 bug. “26 楼会议室的灯亮着.它需要被熄灭.”bug 的备注里写道“你应该能在 5 分钟内搞定,只要按一下开关就好 ...

  4. 从修复 testerhome(rubychina)网站的一个 bug 学习 ruby&rails on ruby

    前言 testerhome: http://testerhome.com/topics/1480 对于一个差点脱离前沿技术人,想要学习ruby,就意味着要放弃熟悉的操作系统windows,熟悉的ide ...

  5. 写了一个bug,最后却变成了feature,要不要修呢?

    事情是这样子的,前不久接到一个需求,为一个游戏开发礼包码功能 通常一款游戏运营期间会搞各种各样的活动吸引玩家,其中最常见的就是发放礼包,  玩家可以通过礼包码兑换礼包. 用礼包码兑换礼包有个一限制,游 ...

  6. NDK中使用pthread多线程中自己写的一个BUG

    在使用pthread进行NDK中的多线程开发时,自己写了一个BUG, void *darkGrayThread(void *args) { ThreadParam *param = (ThreadPa ...

  7. 一个Bug 差点让服务器的文件系统崩溃

    昨天,公司的美国客户发邮件给我,说我的软件出问题了,我查来查去,发现居然是服务器上一个目录无法删除,一删除就报 cannot read from the source file or disk. 如果 ...

  8. puppet的一个Bug

    前篇文章写了使用puppet管理500多台服务器,当然只是一部分,最主要的还是puppet脚本的编写,这个我会在以后的文章中一点一点写出来. 今天要写的是puppet的一个bug,版本是puppet ...

  9. 发现护考上机考试的一个bug:附软件截图(模拟软件)

    目录: 一.文章主旨 二.问题发现的起因 三.bug(问题)描述 四.软件截图 五.我的思考 六.一点期盼 一.文章主旨: 2019年5月18.19.20日,又是一年一度的护资考试(上机考),考试前夕 ...

随机推荐

  1. 稀疏矩阵乘法 · Sparse Matrix Multiplication

    [抄题]: 给定两个 稀疏矩阵 A 和 B,返回AB的结果.您可以假设A的列数等于B的行数. [暴力解法]: 时间分析: 空间分析: [思维问题]: [一句话思路]: 如果为零则不相乘,优化常数的复杂 ...

  2. quartz cron表达式demo

    1.每天0点5分开始,以后每隔15分钟启动一次,23:50停止: 0 5/15 0-23 * * * cron表达式,由于从5分开始,每15分钟执行一次,到了23点的最后一次执行时间正好是23:50. ...

  3. VC++知识点整理

    1.内联函数        定义:定义在类体内的成员函数,即函数的函数体放在类体内        特点:在调用处用内联函数体的代码来替换,用于解决程序的运行效率问题.一定要在调用之前定义,并且内联函数 ...

  4. 阿里云OSS-js分片上传

    使用 aliyun-oss-sdk-4.4.4.min.js 方式一 客户端授权 https://help.aliyun.com/document_detail/32069.html 通过new OS ...

  5. CSS实现图片阴影效果

    <title>无标题文档</title> <style type="text/css"> /*方法一:使用一个GIF文件的方法*/ .gifsh ...

  6. Uploadify多文件上传插件.NET使用案例+PHP使用案例

    ploadify是一个非常好用的多文件上传插件 插件下载:http://www.uploadify.com 下载后需要用到的文件: 接下来就是直接添加代码: Default.aspx代码 <%@ ...

  7. [转]Clean up after Visual Studio

    本文转自:https://weblogs.asp.net/psheriff/clean-up-after-visual-studio As programmer’s we know that if w ...

  8. OpenGl中的Nurbs B样条曲面的封装的GLU的NURBS的接口

    OpenGl中的Nurbs B样条曲面的封装的GLU的NURBS的接口 创建一个NURBS对象: GLUnurbs* gluNewNurbsRenderer (void); //创建一个NURBS对象 ...

  9. 深水划水队项目---七天冲刺之day4

    由于有一名队员回家了,所以今天的站立式会议改成微信群线上讨论 工作进度: 1.游戏界面进一步美化中. 2.游戏基本功能已经初步实现. 3.计划今天内商讨出如何实现游戏中的难度选择功能与道具功能. 工作 ...

  10. An error "Host key verification failed" when you connect to other computer by OSX SSH

    Here's quick way to remove all entries in the host file: In an OSX terminal, type rm -f ~/.ssh/known ...