Hi,
- In fact, the rows in the database store only the string contents, not the "capacity" and "length" fields. There is some (C and Pascal) code to do the mapping between the Pascal Records and the database contents both ways.
The FillChar question occurs when the code writes Pascal Records containing strings into the database, because the full contents (value of the Capacity field) of the string is written to it.
For example, if I have a String(10) variable containing 'ABC', 10 characters are written to the database. If there is "garbage" in the remaining 7 characters, it will be written too. And when the record will by retrieved, the garbage will be part of the string because the string length is taken from the database schema.That's why I hoped FillChar() was working for strings...
At the early stages of the conversion, I tried "Array[1..x] Of Char" but I lost almost all of the GPC facilities for strings manipulation, and the automatic blank padding when comparing them generated problems. I also tried my own schemata, similar to the String but with no "Capacity" field. It was worse: I lost all string facilities and more, I was unable to assign contents directly as "MyStr := 'ABC';" (I was unable to implement a custom assignment operator ":=") so I adopted the String() type.
- Thanks for the answer to my question regarding the Capacity field after a call to FillChar. It is clearer for me now. So, do not spend your precious time to test the result of an operation which should not be done. However, I wouldn't call "a low-level trick" the call to FillChar() ;-)
- As Gale Paeper suggested I tried Extended Pascal's initial-state-specifier and since I do not use variant records in records, this works pretty well and I found no bug in my case. However I decided to generate initialization procedures automatically anyway since the existing code needs more than first-time initialization: FillChar() is potentially called many times on the same variable (between database accesses for example).
Thank a lot for your help.
Pascal Viandier pascal@accovia.com
Pascal Viandier wrote:
2- Records initialization. This is most of the FillChar() calls. The
records
(around 600 of them) are used to map on rows of tables in an Informix database. They contain various data types and strings as well. These
strings
are SUN Pascal Varying[n] Of Char. Internally, there are 4 bytes
indicating
the current string length and an Array of n Char. Since FillChar() is
called
with Chr(0) on them, this actually sets the current string length to 0 and fill them with zeroes.
If you only want to set the length to 0, you can just assign the empty string (S := ''), which is more efficient than overwriting all characters. Unless you require the (unused) characters to be Chr(0) for some particular reason ...
But if you mean by "map" that the data structure must correspond to your database, then probably an EP string won't do anyway, because of the Capacity field. You can build you own data structure, containing a length field and a character array then.
In this case, I think the best approach will be to generate procedures to
do
the records initialization field by field and call them instead of FillChar(). With a moderate amount of work, my translation program should
be
able to take care of this.
Also, when trying some ways to solve my problem, I encountered a behaviour that I don't clearly understand regarding the "Capacity" field: If I FillChar() a String with Chr(0), the Capacity field is set to 0 - as expected - that's my problem :-(. Then, if I pass this string as Var parameter to a procedure, I cannot put anything in it. There is no runtime error or warning, but the string stays empty, WriteLn() does not show anything - in the procedure or after returning from it -. But, If I re-initialize the string directly (S10 := 'AAAAA' for example): 1- the Capacity field stays 0 - that's normal 2- but I can now use WriteLn() on it and it shows what I put in it ('AAAAA').
What is exactly the role of the "Capacity" field? Is this an expected behaviour?
The behaviour is undefined, as Capacity (and other schema discriminants) must not be written to. Normally GPC prohibits that, but with low-level tricks such as FillChar you can bypass normal checks. That's why such low-level tricks must be used with care.
As for the exact behaviour you observed, it might be that for direct access to the variable (not as a paramater) the compiler uses the constant known discriminant value instead of reading the actual value. If you send a test program, I could check it, but it probably won't matter much, as it's undefined behaviour anyway.
Gale Paeper wrote:
It seems to me that Extended Pascal's initial-state-specifier would be the ideal solution for your problem. Initial-state-specifiers are designed to exactly what you're try to accomplish here with you're hackish use of FillChar() and have the additional benefit of correctly initializing a variable of any Pascal type without needing to worry about the implementation pecularities.
Yes, if you actually want to initialize the character array, this could be a rather easy solution.
I believe Extended Pascal's initial-state-specifiers are supported in the latest GPC version but I haven't actual tested it.
Mostly yes. However, the feature is rather new, so please test a bit more carefully and report any bugs found.
There's one case that doesn't fully work yet: Initializers of (structures containing) variant records. There are some hairy issues there. Some cases may work, but there are still problems. So for now, better consider them not working. I'll announce in the release notes of a future version (not the next one, though) when they will really work.
Frank