大雀软件园

首页 软件下载 安卓市场 苹果市场 电脑游戏 安卓游戏 文章资讯 驱动下载
技术开发 网页设计 图形图象 数据库 网络媒体 网络安全 站长CLUB 操作系统 媒体动画 安卓相关
当前位置: 首页 -> 技术开发 -> Script -> Delphi中两个BUG的分析与修复

Delphi中两个BUG的分析与修复

时间: 2021-07-31 作者:daque

 Delphi中两个BUG的分析与修复

  在运用delphi 7举行三层数据库开拓时,遇到了两个小题目,经过重复考查,毕竟找到了delphi 7中的两个小bug并举行了建设(犹如delphi 6中也有沟通的bug),撰写此文与大师一道瓜分胜利的欣喜。我也是入门delphi,文中确定生存不少说的不对的场合,还请诸位伙伴多多教正。

  bug1.传参时华文被截断的题目:

  bug表现的本领:

  后盾用sql server 2000,内里有一个xshetong表用来考查,您不妨按照您的本质情景举行安排。

  先创造一个数据效劳器:兴建名目,创造一个长途数据模块,上头安置adoconnection、adodataset、datasetprovider各一,并做好相映树立,个中adodataset的comamndtext留空,并把它的option中的poallowcommandtext树立为true。编写翻译运转。

  再创造存户端步调:兴建名目,在窗体上安置dcomconnection,连上前方上创造的数据效劳器,再安置一个clientdataset,把它的贯穿设成这边的dcomconnection,并树立它的providername为上头的效劳器上的datasetprovider的名字。结果安置datasource和dbgrid各一并作相映树立用来察看截止,再安置一button用来尝试。

  在button的onclick中写下一致于底下的代码(这边我用了xshetong的表和它的两个字段hth(char 15)、gcmc(varchar 100),您不妨按照你的本质尝试情景举行安排):

  with clientdataset1 do  begin   close;   commandtext := 'insert into xshetong(hth, gcmc) values(:hth,:gcmc)';   params[0].asstring := '12345';   params[1].asstring := '会截断的中笔墨';   execute;   close;   commandtext := 'select * from xshetong';   open;  end;

  运路途序,点击按钮,看到记载被插入了,怅然截止并不精确,“会截断的中笔墨”形成了“会截断”,但没有华文的“12345”倒是精确的插入了。

  bug领会与建设:

  为了比较起见,我试着径直用一个adoconnection和adocommand、adotable举行c/s构架尝试,截止是精确的,中笔墨不会被割断。这说领会此bug只在三层构架上展示。

   用sql server事变探查器探查提交到sql server上运转的语句,创造两层构架与三层构架的情景有以次各别:

  两层构架:  exec sp_executesql n'insert into xshetong(hth, gcmc) values(@p1,@p2)', n'@p1 varchar(15),@p2 varchar(100)', '12345', '会截断的中笔墨'

  三层构架:  exec sp_executesql n'insert into xshetong(hth, gcmc) values(@p1,@p2)', n'@p1 varchar(5),@p2 varchar(7)', '12345', '会截断

  明显,两层构架时,参数的长度是按本质库构造传的,三层构架时,参数长度是按本质参数的字符串长度传的,而本质字符串长度又犹如是算错了,没有把一个华文当两个字符长度处置。

  没有方法只好举行盯梢调节和测试,为了调节和测试delphi的vcl库,须要在工程选项的“compiler options”当选上“use debug dcus”。

  先盯梢存户端步调,clientdataset1.execute后,先后体验了tcustomclientdataset.exectue、tcustomeclientdataset.packageparams、tcustomclientdataset.doexecute等一系列因变量,从来到appserver.as_execute(providername, commandtext, params, ownerdata); 把乞求提交到效劳器均没有什么特殊情景,可见题目出在效劳器端。

  对效劳器举行盯梢,重复考查后,我把中心落在了tcustomadodataset.pssetcommandtext因变量身上,过程重复精致的盯梢,目的越来越透彻:tcustomadodataset.pssetparams、tparameter.assign、tparameter.setvalue、vardatasize。毕竟找到了bug的泉源:vardatasize因变量,底下是它的代码:

  function vardatasize(const value: olevariant): integer;  begin   if varisnull(value) then    result := -1   else if varisarray(value) then    result := vararrayhighbound(value, 1) + 1   else if tvardata(value).vtype = varolestr then    begin     result := length(pwidestring(@tvardata(value).volestr)^); //出题目的行     if result = 0 then      result := -1;    end   else    result := sizeof(olevariant);  end;

  即是在这个因变量入彀算实参的长度的,它把value中的值掏出地方,并把它动作一个widestring的南针去求字符串长度,截止就引导了“会截断的中笔墨”这个字符串的长度形成了7,而不是14。

  题目找到了,处置起来也就不艰巨了,只有大略的把  result := length(pwidestring(@tvardata(value).volestr)^); //出题目的行  改成  result := length(pansistring(@tvardata(value).volestr)^); //没题目了  就不妨了。

  然而如许就会引导求英笔墨符串的长度时间长度度被更加了,以是也不妨把这一条龙改成:  result := length(value);

  如许,尽管是华文仍旧英文仍旧中英搀和的字符串就都可求得精确的长度了。这就我于今仍大惑不解的题目,干什么borland要绕个圈子经过南针去求参数值的长度呢?哪位伙伴领会的话还请给我证明一下,特殊感动!

  有些伙伴大概会有疑义,干什么在不经过三层构架来做的功夫不爆发这个字符串被截断的题目呢?谜底并不搀杂,在径直经过adocommand来向sql server发送吩咐时,它是按表构造来确定参数长度的。它会先向sql server发一条

  set fmtonly on select hth,gcmc from xshetong set fmtonly off

  来获得表构造。而在三层构架下,tcustomadodataset里面固然也是用tadocommand东西来发吩咐,但它却在博得表构造的后,并不必这个值来动作传参长度,而是从新去按本质参数来计划长度,截止就引导了缺点。

 

  bug2.clientdataset的lookup字段的题目:

  bug表现的本领:

  兴建工程,在上头安置两个clientdataset,辨别为cds1和cds2,它的数据根源大肆,个中cds1为主数据集,在内里减少一个新的lookup字段,这个lookup字段按照cds第11中学的一个字符型的字段值到cds第22中学找到对应值来。

  运路途序,普遍来说是平常的,然而一旦cds1的被lookup字段中的值展示了一个单引号"'"(您不妨窜改或新增一条记载,输出单引号试试),登时会引导堕落: unterminated string constant(未中断的字符串恒量)。

  bug领会与建设:

  这个bug的爆发因为要比上一个鲜明得多,确定是没有精确处置单引号带来的副效率惹起的。

  同样的,咱们来盯梢vcl的源码:

  运路途序,堕落时翻开call stack窗口(在view->debug windows)菜单中,察看因变量挪用情景,前方的少许挪用是不言而喻的,没有题目,咱们从跟lookup相关的场合发端查因为,第一个与lookup相关的因变量挪用是tfield.calclookupvalue,咱们在这个因变量中树立断点,从新运路途序,阻碍下来后,举行单步伐试。

  tcustomclientdataset.lookup->tcustomclientdataset.locaterecord

  过程上头的几次因变量挪用,很快的,咱们就把目的定在了locaterecord进程中,在这个进程中,它按照lookup字段的树立情景,天生相映的过滤前提,而后到目的数据会合把对应的值找到,错就错在过滤前提的天生上了。比方,咱们要按cds第11中学cust字段(假如是001)的值到cds第22中学按custid字段值找到对应的custname字段值。那天生的前提就该当是[custid] = '001',但即使cust的值是aa'bb,按天生的前提就会形成[custid] = 'aa'bb',明显引导了一个未中断的字符串恒量。

  常常咱们处置单引号中又展示单引号的情景,只需把引号中的引号写两就行了,这边也是一律,只有让天生的前提形成[custid] = 'aa''bb'就不会堕落了。以是不妨如许窜改源代码:

  在locaterecord进程中找到底下的代码:

  ftstring, ftfixedchar, ftwidestring, ftguid   if (i = fields.count - 1) and (lopartialkey in options) then    valstr := format('''%s*''',[vartostr(value)]) else    valstr := format('''%s''',[vartostr(value)]);

  改成:

  ftstring, ftfixedchar, ftwidestring, ftguid:   if (i = fields.count - 1) and (lopartialkey in options) then    valstr := format('''%s*''',[ stringreplace(vartostr(value),'''','''''',[rfreplaceall])])   else    valstr := format('''%s''',[ stringreplace(vartostr(value),'''','''''',[rfreplaceall])]);

  也即是在天生过滤前提字符串时把前提的过滤值中的单引号十足一个变两。

  为了保证如许窜改的精确性,我察看了tcustomadodataset中的对应的locaterecord进程(在用tadodataset中的lookup字段时不会因单引号堕落,只在用tcustomclientdataset时有如许的情景),它的处置本领与tcustomclientdataset稍有各别,它是经过getfilterstr因变量来结构过滤前提的,但在getfilterstr中,它精确处置了单引号的题目。以是如许来看,没有在tcustomclientdataset的locaterecord中精确处置单引号的题目,真实是borland一个不大不小的忽视。

热门阅览

最新排行

Copyright © 2019-2021 大雀软件园(www.daque.cn) All Rights Reserved.