Subject Re: [firebird-support] Can't get Generator to work.
Author Helen Borrie
At 04:44 PM 11/09/2004 +1000, you wrote:
>Hope someone can help.
>
>FB 1.5 WinXP Marathon GUI.
>
>I'm using the Marathon program to create all the tables and set settings.
>I'm having trouble with 'auto-increment' type fields. I've just read a
>heap of past messages containing keywork 'generators' but none really
>helped, only confused me as to why I can't get it to work.
>
>My understanding is, in order to create a unique number, a generator is
>created, link or attach that to a trigger and finally at the table end, that
>trigger is called in 'before insert'.
>
>When attempting to insert data using Marathon an error message is returned
>"Trip_ID" field must have a value. "Trip_ID" field is an integer (not
>null) and is suppose to have been populated with an incremented (unique)
>number. This is not occurring.
>
>Is my understanding correct or am I missing something. (I'm coming from a
>MS Access background)
>
>Any help would be appreciated.

You're only encountering a rule encapsulated in Delphi (the back-end of
Marathon) that makes all non-nullable values "required fields". So, that
interface won't be any use to you for inserting rows into any tables that
depend on a trigger to fill in the "required field", since the tool has no
knowledge whatsoever of the trigger.

One way to work around this problem is to omit the PK column from the list
of input columns for the insert statement. Once the statement is posted to
the server, the trigger will take over and do its stuff - provided, of
course, that you wrote a "safe" trigger, of the form:

if (new.MyPK is null) then
new.MyPk = gen_id(MyGenerator, 1);

To use the Marathon interface for inserts "into a dataset", you are usually
working with a method that is operating on a set that includes the primary
key, typically "SELECT * FROM...". For many reasons, this is standard and
desirable in desktop admin tools. You'll have to work around this another
way.
One way would be to change your trigger as follows:

ALTER TRIGGER MyTrigger
as
begin
if (new.MyPK is Null or new.MyPK < 0) then
new.MyPK = gen_id(MyGenerator, 1);
end

Then, when inserting from Marathon's dataset grid, give it a negative value
for MyPK. You then keep Delphi/Marathon happy *and* ensure that the
trigger does its nice job for you.

When your write your own apps, e.g. with Delphi, you will typically have
some mechanism to get that generator value into your app *before* the
Insert is posted. You can write a function that does "select
gen_ID(MyGenerator, 1) from RDB$Database". With IB Objects, it will all be
done for you automagically if you use the GeneratorLinks property, or call
IBO's client-side function Gen_ID().

The important fact here is that generator values are delivered
independently of any transaction so, unlike "auto-increment types" in some
other dbmses, we have absolute control over the timing of the key value
generation.

./heLen