Subject Re: [IBO] aggregate fields? Persistant fields?
Author Paul Vinkenoog
Hi James,

>> Fields are "persistent" from the moment the dataset is prepared
>> until it is unprepared. What I often do (in C++ Builder) is the
>> following. Suppose I have a query qryPersons returning two
>> columns: Name and Address. I don't want to use FieldByName all the
>> time and in loops it could even slow things down. So I make an
>> AfterPrepare handler for the query with this code (or calling a
>> function with this code):
>>
>> ...
>> colName = qryPersons->FieldByName( "Name" );
>> colAddr = qryPersons->FieldByName( "Address" );
>> ...

> Iam following this thread to learn more about IBO. I am surprise to
> see something like what you have done here, but it sounds great
> =). May I know what is the advantage of using the FieldByName over
> the colName=qryPersons->FieldByName("name");?

If you access the same field from several places in your code, it's
easier to write "colAddr->AsString" a couple of times than
"qryPersons->FieldByname( "Address" )->AsString". Of course you have
to invest first by setting up colAddr as shown above. If you only
access a column from one or two spots in your code, there's no gain in
setting up such a TIB_Column var. At least no *typing* gain.

Another thing is that everytime you use ParamByName, the function
GetParamByName (iirc) is executed to find the right column pointer.
But everytime it finds the same pointer of course (as long as the
dataset remains Prepared)! If this is done outside a loop, there's
not much harm done. But within a loop body that's executed many times
you can speed up the execution by caching the column pointer in a
variable. BTW, if you *only* use such a var for this reason, and in
one loop, it doesn't have to be a global var or a Form data field. You
can just make it local to the procedure that contains the loop:

function DoSomething()
{
// ...stuff...
TIB_Column *colName = qryPersons->FieldByName( "Name" );
TIB_Column *colAddr = qryPersons->FieldByName( "Address" );
for ( qryPersons->First(); ! qryPersons->Eof; qryPersons->Next() )
{
colAddr->AsString = colName->AsString + " Street";
}
}

(of course if you run through a set like this you would rather use a
TIB_Cursor, and APIFirst/Next; but it works the same as far as the
column pointer caching is concerned).


> am I right to say that if I'll be using this kind of technique I
> have to assign all the fields that I will be using in afterprepare
> event? and declare a TIB_Column variable for each field that I will
> be using?

You need a variable for each field that you want to refer to in this
way. Not necessarily for all the fields you use. And you have to
assign the value *somewhere*. I have found AfterPrepare a great place
to do this, because that's when the TIB_Column has just become valid,
so you don't risk accessing the variable while it's NULL or has a
random value. But you can do it in any place that's convenient for
you.


Greetings,
Paul Vinkenoog