Subject Re: [IBO] More Params info
Author Ryan Nilsson-Harding
Thanks Helen for the (as always!) detailed description.
I am beginning to get this now, but I would like to clarify a couple
of things, as this is a feature which I have obviously implemented
poorly from the beginning, and it is spread throughout my app in
various ways.


> Yes, it will AV if you intervene in what the SQL parser is doing -
which is
> just what you do when you try to set SQLWhere yourself. Whether
you have
> something that "worked properly before" or not, it was not a good
approach
> to go in there and mess around with SQLWhere, since SQLWhereItems
surfaces
> the right way (from the parser's point of view) to safely change
the WHERE
> clause.

OK, it's now clearer as to why accessing SQLWhere directly causes
AV's.
Also, I much rather use the tools the way they are intended, instead
of coming up with an "OK workaround". Hence, I am now going to truly
get this concept burnt into my skull.


> You haven't explained what event the code below happens in so, for
> simplicity, let's assume it's a button click on MyEventButton.

Your assumption is correct, it's tied to an action item (button &
menu)


> >if (currentView = vwCurrent) then
> >qry.ParamByName('rp_id').AsInteger := posHISTORY;
> >else begin
> >qry.DisableControls;
> >qry.SQLWhere.Clear;
> >qry.SQLWhere.Add('WHERE Q.RP_ID = :rp_id');
> >if not qryQuote.Prepared then
> >qry.Prepare; <== This is never called...
> >
> >qry.Params[0].AsInteger := posHISTORY; <== AV caused here
> >{If I use ParamByName('rp_id'), I get an error stating there is no
> >such field 'rp_id'}
> >
> >qry.Open;
> >qry.EnableControls;

Regarding your code suggestions below, could you please answer a
couple of brief questions (below your code)

> procedure MyForm.MyEventButtonClick(Sender: TObject);
> begin
> .... stuff...
> with dm.qry do
> begin
> Close;
> DisableControls;
> if (currentView <> vwCurrent) then
> InvalidateSQL; // signals IBO to reprepare
> EnableControls;
> Open;
> end;
> end;
>
> // this proc only gets called if the SQL is invalidated
>
> procedure dm.qryPrepareSQL(Sender: TIB_Statement);
> var
> condition: integer;
> begin
> if [xxx] then
> condition := 1
> else if [yyy] then
> condition := 2
> else
> condition := 3;
> qry.SQLWhereItems.Clear;
> case condition of
> 1: qry.SQLWhereItems.Add('q.RP_ID = :rp_id');
> 2: qry.SQLWhereItems.Add('q.YYY = :yyy');
> 3: qry.SQLWhereItems.Add('q.ZZZ = :zzz');
> end;
> end;
>
> procedure dm.qryBeforeOpen(IB_Dataset: TIB_Dataset);
> begin
> if not Prepared then Prepare;
> qry.Params[0].Value := posHISTORY;
> end;

1- Is InvalidateSQL all that's needed to trigger OnPrepare? I
thought I read somewhere that InvalidateSQL should be accompanied by
a refresh. But now that doesn't make sense as the query is closed,
then opened.

2- What is the reason you explicitly call close on the query (in the
button event)? Does InvalidateSQL not do this?

3- You explicitly call SQLWhereItems.Clear in OnPrepareSQL, but it
states in the GSG that this is done automatically in this event and
is unnecessary. Is this necessary?

4- Confirmation please: I have only one parameter, but the column
the parameter refrences may change. (There are three fields the user
can select to narrow down the WHERE)
4a- When the parameter value changes, BUT the referenced column is
the same, all I need to do is:
myQry.Params[0].Value := xxx;
This seems to do the refresh, and it's clean & quick (i.e. I don't
need Disable/Enable controls to prevent flickering) Is my
understanding of this correct?
4b- (Last one!!) When the referenced column DOES change (or the
number of parameters changes) is this the only time I use
InvalidateSQL. Is my understanding of this correct?

Thanks again for your help. I have been a little verbose, but this
HAS to be properly understood by me before I move on.

Thanks, and kind regards,
-Ryan