Subject | Re: [IBO] Absolute unique value/generator/SP problem |
---|---|
Author | Helen Borrie |
Post date | 2004-06-22T13:14:02Z |
At 05:32 AM 22/06/2004 -0700, you wrote:
application, somehow. There's simply no way you could get duplicate
numbers from a generator.
resources. Use an explicit transaction for hit-and-run.
First to read a singleton from a TIB_Cursor that is a SELECT.
But don't use a SELECT statement for a SP that returns asingleton - use an
EXECUTE PROCEDURE statement, call Execute, and read the field value
immediately following the Execute. Commit immediately after you have the
value. Even better, use a TIB_DSQL to do the same thing with about a
quarter of
the overhead.
[..]
us - possibly some flaw in the way you are converting the integer to
string, which you don't show here.
But I'd like to recommend a more elegant way to do this task.
function TdmSalesInq.GetPermNo(idtype: string): integer;
begin
{
qryGetID is a TIB_Cursor with the SQL of :
EXECUTE PROCEDURE SP_GET_NEXTID(:idtype)
and it has its own ReadCommitted transaction !!
}
with qryGetID do
begin
ib_transaction.StartTransaction;
If NOT Prepared then Prepare;
ParamByName('IDType').AsString := idtype;
Execute;
Result := FieldByName('NextID').AsString;
Commit;
end;
Now, your various methods that want their particular generator number all
call the same function:
e.g. for the ORDERNO:
function TdmSalesInq.GetPermOrderNo: String;
begin
If NOT (qryOH.State in [dssEdit, dssInsert]) then
qryOH.Edit;
qryOH.FieldByName('OrderNo').AsString := IntToStr(GetPermNo('ORDERNO'));
PostChanges(qryOH);
Global.RefreshQry(qryOD, False);
Global.RefreshQry(qryODC, False);
end;
Helen
>Greetings,Greetings, Kevin
>I have an order entry system that requires an absolutely unique order numberTrue.
>to be issued when sales people enter an order.
>
>In remembering all the posts over the years, using a generator is the way to
>go as it's my understanding it "operates" outside of the transaction thus
>assuring a unique value.
>I am getting reports of duplicate order numbers being issued (a very badYup. One thing you can be certain of, the error is happening in your
>thing).
application, somehow. There's simply no way you could get duplicate
numbers from a generator.
>Here's how I get the next generator value via a function in a data module:It does matter. You have a "hit-and-run" operation that is holding
>
>function TdmSalesInq.GetPermOrderNo: String;
>begin
>{
>qryGetID is a TIB_Cursor with the SQL of : select * from
>sp_get_nextid(:idtype)
> this cursor is hooked up to a TIB_Transaction set to autocommit = true
>which should not matter (I think)
>}
resources. Use an explicit transaction for hit-and-run.
> with qryGetID doBad. TIB_Cursor doesn't have the Active property or Open or Close. Use
> begin
> If Active then Close;
> If NOT Prepared then Prepare;
> ParamByName('IDType').AsString := 'ORDERNO';
> Open;
> Result := FieldByName('NextID').AsString;
> Close;
> end;
First to read a singleton from a TIB_Cursor that is a SELECT.
But don't use a SELECT statement for a SP that returns asingleton - use an
EXECUTE PROCEDURE statement, call Execute, and read the field value
immediately following the Execute. Commit immediately after you have the
value. Even better, use a TIB_DSQL to do the same thing with about a
quarter of
the overhead.
[..]
>//~~~~~~~~~~~~~~~~~~~~~~The cause of the duplicate numbers is somewhere in code you haven't shown
>sp_get_nextid looks like this:
>CREATE PROCEDURE SP_GET_NEXTID(
> IDTYPE VARCHAR(15))
>RETURNS (
> NEXTID INTEGER)
>AS
>BEGIN
> if (IDType = 'QUOTE') then
> NextID = GEN_ID(GEN_QUOTES, 1);
>
> if (IDType = 'ORDERNO') then
> NextID = GEN_ID(GEN_ORDERNO, 1);
>
>/* many more of these */
>Suspend; <----------NO!!! <----------because you want to EXECUTE this
>end
>//~~~~~~~~~~~~~~~~~~~~~~
>
>Any ideas of my problem would be GREATLY appreciated.
us - possibly some flaw in the way you are converting the integer to
string, which you don't show here.
But I'd like to recommend a more elegant way to do this task.
function TdmSalesInq.GetPermNo(idtype: string): integer;
begin
{
qryGetID is a TIB_Cursor with the SQL of :
EXECUTE PROCEDURE SP_GET_NEXTID(:idtype)
and it has its own ReadCommitted transaction !!
}
with qryGetID do
begin
ib_transaction.StartTransaction;
If NOT Prepared then Prepare;
ParamByName('IDType').AsString := idtype;
Execute;
Result := FieldByName('NextID').AsString;
Commit;
end;
Now, your various methods that want their particular generator number all
call the same function:
e.g. for the ORDERNO:
function TdmSalesInq.GetPermOrderNo: String;
begin
If NOT (qryOH.State in [dssEdit, dssInsert]) then
qryOH.Edit;
qryOH.FieldByName('OrderNo').AsString := IntToStr(GetPermNo('ORDERNO'));
PostChanges(qryOH);
Global.RefreshQry(qryOD, False);
Global.RefreshQry(qryODC, False);
end;
Helen