Analysis and Repair of Two Bugs in Delphi
When using Delphi 7 for three-layer database development, two small problems have encountered two small problems. By repeated trial, two small bugs in Delphi 7 are found and repaired (it also has the same BUG in Delphi 6), write This article shares the joy of success with everyone. I am also a beginner Delphi. There must be a lot of places in the text, and you will also ask your friends to correct.
Bug1. The Chinese truncated question:
BUG reproduction method:
In the background with SQL Server 2000, there is a xshetong meter for tests, you can adjust according to your actual situation.
Create a data server first: New project, create a remote data module, place the Adoconnection, Adodataset, DataSetProvider, and do the corresponding settings, where the adodataset's ComamndText leaves, and sets the PoallowCommandText in its option to TRUE. Compile operation.
Create a client program: New project, place DCOMCONNECTION on the form, connect the data server created in front, then place a clientDataSet, set its connection to the DCOMCONNECTION here, and set its providentname to the above server The name of the DataSetProvider. Finally, place the DataSource and DBGRID and make the appropriate settings for viewing results, then place a Button for testing.
Write down the following code in Button's OnClick (here I use xshetong table and its two fields Hth (char 15), GCMC (VARCHAR 100), you can adjust according to your actual test):
WITH Close; CommandText: = 'INSERT INTO XSHETONG (HTH, GCMC) VALUES (: hth,: gcmc)'; params [0] .sstring: = '12345'; params [1] .sstring: = ' Truncated Chinese word '; Execute; Close; CommandText: =' SELECT * from xshetong '; Open; End;
Run the program, click the button, see the record being inserted, unfortunately the result is not correct, "the Chinese words will be truncated" becomes "will truncation", but there is no Chinese "12345" is correct.
Bug Analysis and Repair:
For the sake of control, I tried to use an Adoconnection and AdoCommand, and adotable for C / S architecture test, the result is correct, the Chinese word will not be cut off. This shows that this bug appears only on the three-layer architecture.
Submitting the statement running on SQL Server with SQL Server Event Profiler, found that the two-layer architecture and the three-layer framework are below:
Two-layer frame: Exec sp_executesql n'insert into xshen (hth, gcmc) Values (@ p1, @ p2) ', n' @ p1 varchar (15), @ p2 varchar (100) ',' 12345 ',' will truncation Chinese word '
Three-layer architecture: Exec sp_executesql n'insert into xshetong (hth, gcmc) Values (@ p1, @ p2) ', n' @ p1 varchar (5), @ p2 varchar (7) ',' 12345 ',' will truncation Obviously, when the two layers, the length of the parameter is transmitted by the actual library structure, the length of the parameter is transmitted by the string of the actual parameters, and the actual string length seems to be wrong, no One Chinese is handled by two character lengths.
There is no way to track debugging, in order to debug Delphi's VCL library, you need to select "Use Debug DCUS" in "Compiler Options" in the project option.
First track client program, after ClientDataSet1.Execute, has gone through the TCustomClientDataSet.Exectue, TCustomeClientDataSet.PackageParams, TCustomClientDataSet.DoExecute and a series of functions, until AppServer.AS_Execute (ProviderName, CommandText, Params, OwnerData); submit a request to the server There is no abnormal situation, it seems that the problem is in the server side.
After tracking the server, after repeated test, I focus on the TCUSTomadodataset.pssetCommandText function, after repeated and meticulous tracking, the goal is getting more accurate: tcustomadataset.pssetParams, TParameter.Assign, TParameter.SetValue, VardataSize. Finally found the source of the bug: VARDATASIZE function, below is its code:
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 = Varolestr1 Begin Result: = Length (PWIDESTRING (@tvardata (value) .volestr) ^); // Outline row if Result = 0 THEN Result: = -1; Else Result: = SizeOf (Olevariant);
Take the length of the argument in this function, it takes the value of the value in the value in Value, and the length of the pointer to a WideString, resulting in the string of "truncated Chinese words" The length becomes 7, not 14.
The problem is found, and it is not difficult to solve it. Tvardata (value) .volestr) ^); // is okay.
However, this will result in the length of the English string, so it can also be changed to: result: = length (value); this, whether Chinese or English or the mixed string of the Chinese-English mix It can be obtained correctly. This is still a problem that I still don't understand, why is Borland to see the length of the value value by pointer around a circle? Which friend knows, please explain it, thank you very much!
Some friends may have questions, why don't you produce this string truncated when you don't pass the three-layer architecture? The answer is not complicated. When you send a command directly to SQL Server directly through Adocommand, it determines the length of the parameter according to the table structure. It will send one to SQL Server first
Set fmtonly on SELECT HTH, GCMC from xshetong set fmtonly off
Come get a table structure. Under the three-layer architecture, although the TCUSTomadodataset is also used to send commands with a Tadocommand object, but it does not use this value as a passage length, but re-use the actual parameters to calculate the length. The error will result in errors.
Bug2.clientDataSet's Lookup field problem:
BUG reproduction method:
New project, placed two clientDataSets, which are CDS1 and CDS2, which are arbitrary, where CDS1 is the main data set, add a new lookup field, this lookup field according to a character pattern in CDS1 Value to CDS2 to find the corresponding value.
Operating procedures, generally normal, but once the CDS1 has a single quotes "'" by the value in the Lookup field (you can modify or add a record, enter single quotes to try), immediately cause an error: Unterminated string constant (unbed string constant).
Bug Analysis and Repair:
The cause of this bug is much more significant than the previous one, and it must be caused by the side effects caused by the correct handling of single quotes.
Similarly, let's track the source code of VCL:
Opening the program, open the Call Stack window (in the View-> Debug Windows) menu, check the function call situation, some calls in front are obvious, no problem, we start checking the cause from the place related to Lookup, the first Function calls related to lookup are Tfield.calClookupValue, we set breakpoints in this function, re-run the program, and interrupt it, make single-step debugging.
TcustomClientDataSet.lookup-> tcustomClientDataSet.locateRecord
After calling above, very fast, we set the target in the LocateRecord process, in which it generates the corresponding filtering criteria according to the setting of the Lookup field, then goes to the target data set. Value is found, the wrong is wrong to generate the filter condition. For example, we have to press the CUSTID field value to find the corresponding CUSTID field value by pressing the value of the CUST field (assuming is 001) to CDS2. The condition of the generated should be [Custid] = '001', but if the value of the CUST is aa'bb, it will become [Custid] = 'aa'bb', which is clearly not ended. String constance. Usually we solve the case of single quotes in single quotes, just write the quotation marks in the quotation marks, it is also the same, as long as the generated conditions become [Custid] = 'aa''bb' will not be wrong. . So you can modify the source code like this:
Find the following code during the LocateRecord:
FTString, fTfixedchar, ftwideString, ftguid if (i = fields.count - 1) and (loPartialKey in option) Then Valstr: = format ('' '% s *' '", [VARTOSTR (Value)] Else Valstr: = Format ('' '% s' '', [VARTOSTR (Value)]);
Change to:
FTString, ftfixedchar, ftwidestring, ftguid: if (i = fields.count - 1) and (loPartialKey in option) Then Valstr: = format ('' '% s *' '", [StringReplace (VARUE),' ' '', '' '' '', [RFREPLACEALL])]) Else Valstr: = Format ('' '% s'' ", [StringReplace (Value), '' ',' '' '' , [RFREPLACEALL])]);
That is, the single quotes in the filter filter value in the filter condition string are generated two.
In order to ensure the correctness of this modification, I viewed the corresponding LocateRecord process in the TCUSTomadodataSet (Will not be erroneous when using the Lookup field in tadodataset, only in the single quasclientDataSet), its processing method TcustomClientDataSet is slightly different, it is constructed by the getFilterstr function, but in GetFilterstr, it has handled the problem of single quotes correctly. So, in this way, there is no problem with the correct processing of single quotes in the LocateRecord of TCUSTOMCLIENTDATASET, which is indeed a non-small omission.