Subject | Re: [IBO] TIBOQuery inserts a null record |
---|---|
Author | Helen Borrie |
Post date | 2006-09-04T00:56:59Z |
At 04:17 AM 4/09/2006, you wrote:
WHERE SESSION_ID = :session_id
Architecturally, it's a bad decision in any case to provide "static"
SQL for a statement that has search values that are going to
change. Even in the best case (where the timing is taken care of) it
causes an enormous amount of overhead because the whole query,
including structures related to the XxxxSQL statements, get
invalidated and the statement itself has to be unprepared and re-prepared.
In this case, where you are depending on OnMacroSubstitute to alter
the value in SESSION_ID, you're almost certainly encountering a
timing issue. If you need to apply a pre-execution change to a
search value, use a parameter and apply the change in the BeforePost event.
you're actually doing a kind of emulated positioned update (which the
engine itself doesn't allow via DSQL). In order for this emulation
to work for updates and deletes, the XxxxxSQL has to target exactly
one row. This is done by expressing the uniqueness by the
KeyFields. IBO surfaces the KeyFields array for you in KeyLinks.
Considering the simple "select x,y,z from foo", if RequestLive is
true AND x, y and/or z contain the primary key AND KeyLinksAutoDefine
is true, then you will transparently get the "hidden" behaviour that
you are used to in the VCL. However, because IBO enables you
participate in determining the KeyLinks, you can (almost always)
update certain sets that the VCL can't.
I can't see from either of your statements what is the primary key of
this table. Possibly you are relying on a trigger, or you have
GeneratorLinks for it, but it's not evident....
Anyway, after all that didactic, the principal problem here is
macrotising that search clause. The biggest breakthrough comes when
you accept the concept that substitutable (replaceable) parameters
are *not* variables. There are several ways to come to grief when
you treat them as though they were....
Helen
>1) The TIBOQuery I'm using has the following items set (I'veDon't use macros to try to define parameters - use the correct syntax, viz.
>redacted some of the fields for brevity):
>
>RequestLive = true
>
>OnMacroSubstitute = (a global routine to substitute a value for
> <<SESSIONID>>).
>
>SQL =
>SELECT "Date", "Code", "Serv ID", "Description", "Qty",
> "Amount", "Base Price", "Tax
>Code", "Tax", "Extended", "Crew",
> "Zone", "Route", "Cost", "Scheduled", "Qty Used", "Man
>Hours",
> "Old Date", "Old Code", "Old Serv ID", "Old Qty", "Old
>Amount",
> "Old Base Price", "Old Tax Code", "Old Tax", "Old Qty Used",
> "Old Man Hours", SESSION_ID FROM EDITINV
> WHERE SESSION_ID = <<SESSIONID>>
>
>InsertSQL =
>insert into EDITINV
>("Date", "Description", "Code", "Qty", "Amount", "Tax
> Code", "Extended", "Serv ID", "Base
>Price", "Tax", "Crew", "Zone",
> "Route", "Cost", "Scheduled", "Qty Used", "Man Hours", "Old
>Date", "Old
> Code", "Old Serv ID", "Old Qty", "Old Amount", "Old Base
>Price", "Old
> Tax Code", "Old Tax", "Old Qty Used", "Old Man
>Hours", "SESSION_ID")
>Values (:"Date", :"Description", :"Code", :"Qty", :"Amount", :"Tax
> Code", :"Extended", :"Serv ID", :"Base
>Price", :"Tax", :"Crew", :"Zone",
> :"Route", :"Cost", :"Scheduled", :"Qty Used", :"Man
>Hours", :"Old Date",
> :"Old Code", :"Old Serv ID", :"Old Qty", :"Old Amount", :"Old
>Base
> Price", :"Old Tax Code", :"Old Tax", :"Old Qty Used", :"Old Man
>Hours",
> :"SESSION_ID")
>
>In the normal course of events, this query gets activated, and the
>code sets appropriate values in the various fields, e.g.,
>
>Q.Append;
>.....
>Q.FieldByName('Description').AsString := 'Some Description';
>.....
>Q.Post;
>
>
>Using the debugger, I can step up to the Post and see that the
>field named Description has the stuff that I expect in it.
>
>Here's what the IBMonitor says:
>03 Sep 2006 13:32:17:710 [ INFO] /*---
>PREPARE STATEMENT
>TR_HANDLE = 39547168
>STMT_HANDLE = 39591772
>
>insert into EDITINV
>("Date", "Description", "Code", "Qty", "Amount", "Tax
>Code", "Extended", "Serv ID", "Base Price", "Tax", "Crew", "Zone",
>"Route", "Cost", "Scheduled", "Qty Used", "Man Hours", "Old
>Date", "Old
>Code", "Old Serv ID", "Old Qty", "Old Amount", "Old Base
>Price", "Old
>Tax Code", "Old Tax", "Old Qty Used", "Old Man Hours", "SESSION_ID")
>Values (? /* "Date" */ , ? /* "Description" */ , ? /* "Code"
>*/ , ? /*
>"Qty" */ , ? /* "Amount" */ , ? /* "Tax Code" */ , ? /* "Extended"
>*/ ,
>? /* "Serv ID" */ , ? /* "Base Price" */ , ? /* "Tax"
>*/ , ? /* "Crew"
>*/ , ? /* "Zone" */ , ? /* "Route" */ , ? /* "Cost" */ , ? /*
>"Scheduled" */ , ? /* "Qty Used" */ , ? /* "Man Hours"
>*/ , ? /* "Old
>Date" */ , ? /* "Old Code" */ , ? /* "Old Serv ID" */ , ? /* "Old
>Qty"
>*/ , ? /* "Old Amount" */ , ? /* "Old Base Price" */ , ? /* "Old Tax
>Code" */ , ? /* "Old Tax" */ , ? /* "Old Qty Used" */ , ? /* "Old
>Man
>Hours" */ , ? /* "SESSION_ID" */ )
>
>FIELDS = [ Version 1 SQLd 0 SQLn 64 ]
>----*/
>03 Sep 2006 13:32:24:069 [ INFO] /*---
>EXECUTE STATEMENT
>TR_HANDLE = 39547168
>STMT_HANDLE = 39591772
>PARAMS = [ Version 1 SQLd 28 SQLn 28
> [DATE] = <NULL>
> [DESCRIPTION] = <NULL>
> [CODE] = <NULL>
> [QTY] = <NULL>
> [AMOUNT] = <NULL>
> ["Tax Code"] = <NULL>
> [EXTENDED] = <NULL>
> ["Serv ID"] = <NULL>
> ["Base Price"] = <NULL>
> [TAX] = <NULL>
> [CREW] = <NULL>
> [ZONE] = <NULL>
> [ROUTE] = <NULL>
> [COST] = <NULL>
> [SCHEDULED] = <NULL>
> ["Qty Used"] = <NULL>
> ["Man Hours"] = <NULL>
> ["Old Date"] = <NULL>
> ["Old Code"] = <NULL>
> ["Old Serv ID"] = <NULL>
> ["Old Qty"] = <NULL>
> ["Old Amount"] = <NULL>
> ["Old Base Price"] = <NULL>
> ["Old Tax Code"] = <NULL>
> ["Old Tax"] = <NULL>
> ["Old Qty Used"] = <NULL>
> ["Old Man Hours"] = <NULL>
> [SESSION_ID] = <n> 0 ]
>
>INSERT COUNT: 1
>
>
>As you can see, Description and for that matter, all of the other
>fields are now null. What could cause this?
WHERE SESSION_ID = :session_id
Architecturally, it's a bad decision in any case to provide "static"
SQL for a statement that has search values that are going to
change. Even in the best case (where the timing is taken care of) it
causes an enormous amount of overhead because the whole query,
including structures related to the XxxxSQL statements, get
invalidated and the statement itself has to be unprepared and re-prepared.
In this case, where you are depending on OnMacroSubstitute to alter
the value in SESSION_ID, you're almost certainly encountering a
timing issue. If you need to apply a pre-execution change to a
search value, use a parameter and apply the change in the BeforePost event.
>2) The fields as they occur in the select are in a different orderIt's not an issue. You can submit DML fields in any order you like.
>from that in the insert. I didn't think that was an issue. Am I
>incorrect?
>3) In the past, I seem to recall being able to treat a straightCheck your KeyLinks. When you perform DML from a Delphi dataset,
>query like this (e.g., select x,y,z from foo) almost as though it
>were a table provided I set RequestLive. In other words, I can do
>Append, FieldByName().AsValue, Post without having to provide any
>InsertSQL. When I first tried it with this query, it wouldn't
>automatically produce the InsertSQL so I constructed some. I
>thought this might have to do with the select including a WHERE
>clause. Should this have been an issue? Am I misremembering the
>situation with live queries?
you're actually doing a kind of emulated positioned update (which the
engine itself doesn't allow via DSQL). In order for this emulation
to work for updates and deletes, the XxxxxSQL has to target exactly
one row. This is done by expressing the uniqueness by the
KeyFields. IBO surfaces the KeyFields array for you in KeyLinks.
Considering the simple "select x,y,z from foo", if RequestLive is
true AND x, y and/or z contain the primary key AND KeyLinksAutoDefine
is true, then you will transparently get the "hidden" behaviour that
you are used to in the VCL. However, because IBO enables you
participate in determining the KeyLinks, you can (almost always)
update certain sets that the VCL can't.
I can't see from either of your statements what is the primary key of
this table. Possibly you are relying on a trigger, or you have
GeneratorLinks for it, but it's not evident....
Anyway, after all that didactic, the principal problem here is
macrotising that search clause. The biggest breakthrough comes when
you accept the concept that substitutable (replaceable) parameters
are *not* variables. There are several ways to come to grief when
you treat them as though they were....
Helen