Subject | IBO, TDataset and TParams |
---|---|
Author | Jason Wharton |
Post date | 2003-11-22T23:34:32Z |
There are essentially two issue going on here. I'll take them one at a time.
First of all, let me share some general information that could help bring
clarity to this area of dataset interaction. (I hope)
Calling Params.Clear will simply remove and free the parameter objects that
you have declared.
Calling Params[n].Clear will set the value of a particular parameter to
unassigned and reset its Bound property to false.
These are very different operations that you need to be distinctly clear
about which you use.
Also, I don't think there is any event notification on the change of TParams
or the values of TParam so my dataset isn't able to do anything fancy like
unprepare the dataset if TParams.Clear is called.
How and when are parameters created?
IBO cooperates with the TParams.ParseSQL() method which will create
parameter objects without the dataset needing to be prepared. I have change
events tied to the SQL property such that as you make changes to your SQL
statement then the TParam objects will be provided for you in this manner:
TParams.ParseSQL( <the new SQL statement>, <a temporary TParams
collection> )
I go through the existing params and the ones for the new statement in the
temporary TParams collection and do a merge such that existing params remain
if they are also in the new statement. Ones not in the new statement are
deleted and new params in the new statement are added in. I also maintain
proper order based on the new statement. This makes it such that if you
stored an external pointer variable to a TParam it will remain valid. Before
I had state pointers when it wasn't necessary because all params would get
dumped and replaced with new instances.
Output params are ignored in this merge process and simply bumped towards
the end of the list if they are already defined. (as of 4.3 Aa soon to be
released) Before they were getting removed when they shouldn't have, in the
case that you explicitely put them there. IBO would still re-generate them
when they were needed later on so most people probably never noticed.
Anyway, without the need to prepare the dataset, TParams will parse the SQL
and give you input params. However, these don't have any specific
information about the datatype. So, when IBO does prepare the statement and
gets back from the server the parameter datatypes I go ahead and modify the
TParams objects to properly reflect the data types.
I used to argue that you must prepare the statement before you can work with
input parameters and this is true of the native IBO dataset/statement
components. However, with the TDataset based datasets it is now possible to
work with parameters once your SQL statement is plugged in.
Also, I put a fair amount of effort into allowing you to explicitly control
your param objects. If you set ParamCheck to false and define your own input
parameters using the design editors at design-time or in your application
code, I will not mess with them. I even made it fairly flexible about naming
them or just relying upon them to numerically match up and be used purely by
index.
This brings us to the other parameter types of ptOutput, etc. How are these
handled?
These are generally for stored procedures that return a single row of data
as a result of calling the ExecProc method. If you want multiple records,
just use a TIBOQuery. It is standard convention that these singleton results
be returned via the parameter objects since there isn't an actual dataset to
read data from. I also use this for cases where ExecSQL is called and data
is returned, like with a singleton select statement. Thus, on your Params
you can have parameters of type ptOutput, ptInputOutput and ptResult.
ptInputOutput is when you have an input parameter name that is the same as
an output parameter in the result row. ptResult isn't used by
interbase/firebird. It's use is intended for a result code or status code.
I made it so that you can have more flexible usage of the TIBOStoredProc
component as well as more efficient execution. It used to be that I would
not allow it to be Opened. Now I do allow it to be opened and simply deliver
a single record result set.
I hope some of this information helps to clear up questions about this.
I know some of you are going to feel like this work is perhaps causing bugs
but please rest assured I am making IBO operate at a higher level of
standard behavior and flexibility. I'm interested in knowing all cases
people have that used to work that don't now. There are often things I can
do to make sure they either know about it sooner or to emulate the past
behavior where possible. If nothing else, my release notes can be more
useful with this kind of information.
Another aspect that was impacted in the latest version (4.3A) is the
handling of the TParam.Bound property. I used to totally ignore this
property. Frankly, I didn't know about it. It took a very patient person who
did know about it to get me on the same page with him. What IBO was doing
was blindly looking for columns in the master dataset that were named the
same as input parameters in the child dataset and plug the value in.
However, it was the person's argument if they put their own value in the
input parameter that it should be left alone. Once I finally caught on and
realized how this was accomplished I went ahead and implemented it.
So, IBO now has a feature it didn't have before that is correct but
potentially unexpected. If somehow you put a value in a parameter you want
to work for master-detail, your master-detail linkage will be broken. Now,
most people won't ever put a line of code in an application to set a param
value when they want master-detail usage so chances of this being a problem
are rare. However, a more likely problem is encountered due to the way
TParams are stored in the DFM. Due to me ignoring the Bound property the
parameters were getting their value set in a way that left the Bound
property set to true. (When a value is put in based on MD linking the Bound
is set back to false after the value is plugged in.) So, in this state the
value was flagged as bound and thus stored in the form or datamodules DFM.
As a result, there are many applications out there with DFM's loaded with
TParam values stored. When these are loaded in the Bound gets set to true
and the parameter doesn't work in a master-detail relationship. So, people
moving to IBO 4.3 and higher will need to clean their DFM's of TParam.Value
entries.
As for the boolean parameter issue, Christopher Hart submitted a fix for
that and I have it ready to go in the next sub-release.
Kind regards,
Jason Wharton
http://www.ibobjects.com
First of all, let me share some general information that could help bring
clarity to this area of dataset interaction. (I hope)
Calling Params.Clear will simply remove and free the parameter objects that
you have declared.
Calling Params[n].Clear will set the value of a particular parameter to
unassigned and reset its Bound property to false.
These are very different operations that you need to be distinctly clear
about which you use.
Also, I don't think there is any event notification on the change of TParams
or the values of TParam so my dataset isn't able to do anything fancy like
unprepare the dataset if TParams.Clear is called.
How and when are parameters created?
IBO cooperates with the TParams.ParseSQL() method which will create
parameter objects without the dataset needing to be prepared. I have change
events tied to the SQL property such that as you make changes to your SQL
statement then the TParam objects will be provided for you in this manner:
TParams.ParseSQL( <the new SQL statement>, <a temporary TParams
collection> )
I go through the existing params and the ones for the new statement in the
temporary TParams collection and do a merge such that existing params remain
if they are also in the new statement. Ones not in the new statement are
deleted and new params in the new statement are added in. I also maintain
proper order based on the new statement. This makes it such that if you
stored an external pointer variable to a TParam it will remain valid. Before
I had state pointers when it wasn't necessary because all params would get
dumped and replaced with new instances.
Output params are ignored in this merge process and simply bumped towards
the end of the list if they are already defined. (as of 4.3 Aa soon to be
released) Before they were getting removed when they shouldn't have, in the
case that you explicitely put them there. IBO would still re-generate them
when they were needed later on so most people probably never noticed.
Anyway, without the need to prepare the dataset, TParams will parse the SQL
and give you input params. However, these don't have any specific
information about the datatype. So, when IBO does prepare the statement and
gets back from the server the parameter datatypes I go ahead and modify the
TParams objects to properly reflect the data types.
I used to argue that you must prepare the statement before you can work with
input parameters and this is true of the native IBO dataset/statement
components. However, with the TDataset based datasets it is now possible to
work with parameters once your SQL statement is plugged in.
Also, I put a fair amount of effort into allowing you to explicitly control
your param objects. If you set ParamCheck to false and define your own input
parameters using the design editors at design-time or in your application
code, I will not mess with them. I even made it fairly flexible about naming
them or just relying upon them to numerically match up and be used purely by
index.
This brings us to the other parameter types of ptOutput, etc. How are these
handled?
These are generally for stored procedures that return a single row of data
as a result of calling the ExecProc method. If you want multiple records,
just use a TIBOQuery. It is standard convention that these singleton results
be returned via the parameter objects since there isn't an actual dataset to
read data from. I also use this for cases where ExecSQL is called and data
is returned, like with a singleton select statement. Thus, on your Params
you can have parameters of type ptOutput, ptInputOutput and ptResult.
ptInputOutput is when you have an input parameter name that is the same as
an output parameter in the result row. ptResult isn't used by
interbase/firebird. It's use is intended for a result code or status code.
I made it so that you can have more flexible usage of the TIBOStoredProc
component as well as more efficient execution. It used to be that I would
not allow it to be Opened. Now I do allow it to be opened and simply deliver
a single record result set.
I hope some of this information helps to clear up questions about this.
I know some of you are going to feel like this work is perhaps causing bugs
but please rest assured I am making IBO operate at a higher level of
standard behavior and flexibility. I'm interested in knowing all cases
people have that used to work that don't now. There are often things I can
do to make sure they either know about it sooner or to emulate the past
behavior where possible. If nothing else, my release notes can be more
useful with this kind of information.
Another aspect that was impacted in the latest version (4.3A) is the
handling of the TParam.Bound property. I used to totally ignore this
property. Frankly, I didn't know about it. It took a very patient person who
did know about it to get me on the same page with him. What IBO was doing
was blindly looking for columns in the master dataset that were named the
same as input parameters in the child dataset and plug the value in.
However, it was the person's argument if they put their own value in the
input parameter that it should be left alone. Once I finally caught on and
realized how this was accomplished I went ahead and implemented it.
So, IBO now has a feature it didn't have before that is correct but
potentially unexpected. If somehow you put a value in a parameter you want
to work for master-detail, your master-detail linkage will be broken. Now,
most people won't ever put a line of code in an application to set a param
value when they want master-detail usage so chances of this being a problem
are rare. However, a more likely problem is encountered due to the way
TParams are stored in the DFM. Due to me ignoring the Bound property the
parameters were getting their value set in a way that left the Bound
property set to true. (When a value is put in based on MD linking the Bound
is set back to false after the value is plugged in.) So, in this state the
value was flagged as bound and thus stored in the form or datamodules DFM.
As a result, there are many applications out there with DFM's loaded with
TParam values stored. When these are loaded in the Bound gets set to true
and the parameter doesn't work in a master-detail relationship. So, people
moving to IBO 4.3 and higher will need to clean their DFM's of TParam.Value
entries.
As for the boolean parameter issue, Christopher Hart submitted a fix for
that and I have it ready to go in the next sub-release.
Kind regards,
Jason Wharton
http://www.ibobjects.com