What is happening in this code ??

melvin12

New Member
Hi

It is my first message on forum.

I tested error that occurs when creating a duplicate entry in unique index and i am surprised because it don't work like i though.

Code:
def temp-table t
    field a as inte
    index ia is unique a.

def var va as inte no-undo.

session:appl-alert-boxes = true.

create t.
assign t.a = 123.

run pr.

message "after".

procedure pr:

    va = va + 1.

    create t.
    assign t.a = 1.

    va = va + 1.

    create t.
    assign t.a = 1.

    va = va + 1.
end.

Well it shows warnings about duplicate index. But curious is that i shows them also after the message "after".
I can't understand that.
As far as i knew progress, there is an error in procedure. Default action in procedure is undo, retry but this will be infinite loop so it leaves procedure.
If there's transaction I works like I thing it should.
 

Attachments

This error message about "Duplicate Index" appearing the 2nd time or even the 3rd time happens at the end of your procedure. I am not sure why, but it could be that the error is serious enough that Progress wants to inform you again when it exits the procedure. Or it could be a minor quirk of Progress.

Rest assured that it is not running Procedure Pr twice.
 
Since the TRANSACTION keyword corrects this issue, the conclusion would be: It is a Progress Error Handling bug.
I've stripped unnecessary instructions:

Code:
DEF TEMP-TABLE t
    FIELD a AS INTE
    INDEX ia IS UNIQUE a.

CREATE t.
ASSIGN t.a = 123.

MESSAGE "before"
    VIEW-AS ALERT-BOX INFO BUTTONS OK.

RUN pr.

MESSAGE "after"
    VIEW-AS ALERT-BOX INFO BUTTONS OK.

PROCEDURE pr:
    DO /*TRANSACTION*/ :    
        CREATE t.
        ASSIGN t.a = 1.    
        CREATE t.
        ASSIGN t.a = 1.
    END.
END.
 
In the original code the transaction is scoped to the main procedure block. The entire process is a single transaction.

Compile with the LISTING option to see the transaction scope.

Adding TRANSACTION to the "pr" procedure is a good step but you should also add a DEFINE BUFFER t FOR t. statement to prevent the scope of the record being "borrowed" from the main procedure. The naked CREATE & ASSIGN in the main block should also be ensconced in a transaction. Preferably in a strong scoped block:

Code:
do for T transaction:
  CREATE t.
  ASSIGN t.a = 123.
end.
 
Thanks for replies.

I have more questions about it.

How to compile with the LISTING option ? How to see the transaction scope ?

I wrote some code.

Code:
def temp-table t
    field a as inte
    index ia is unique a.

create t.
assign t.a = 123.

run pr.

message t.a.

procedure pr:
  def buffer t for t.

  do for t:
        
    create t.
    assign t.a = 1.
    
    create t.
    assign t.a = 1.
  end.
end.

It reports only one warning about duplicate index. But I see there no transaction.
I suppose that it works because the record t is in scope of the procedure pr.
But I still don't know why i have to use "do fot t" construction.

I know how to write program that works but I am interested in knowledge why that code that i wrote worked.

I found another solution.
Code:
def temp-table t
    field a as inte
    index ia is unique a.

create t.
assign t.a = 123.

/* uncomment no-error and message t.a will execute */
run pr /* no-error */ .

message t.a.

procedure pr:                   
 def buffer t for t.

 do on error undo, return error "blad":

    create t.
    assign t.a = 1.
    
    create t.
    assign t.a = 1.

 end.
end.

It's strange for me. I don't know how to explain this. Could anyone know ?
 
To create a listing file:
Code:
COMPILE xyzzy.p LISTING "xyzzy.lis".

You don't see a transaction because you don't understand record and transaction scope.

The "DO FOR tablename" construction is called strong scoping. It limits the scope of the tablename buffer to the DO FOR block.

The "DEFINE BUFFER tablename FOR tablename." statement creates a buffer scoped to the internal procedure and cleverly gives it the same name as the default buffer for that table. This prevents the record scope from accidentally leaking out of the internal procedure and inadvertently raising the scope of any references to that record in the main procedure. You should still use strong scoped blocks inside the IP but if you forget the damage is limited.

The NO-ERROR, when present, is suppressing the return of the error status from the internal procedure and preventing the error condition from being raised in the main procedure.
 
Here is the listing .

Code:
.\konstr\podw.p                       05/05/2009 22:24:37   PROGRESS(R) Page 1   

{} Line Blk
-- ---- ---
      1     def temp-table t
      2         field a as inte
      3         index ia is unique a.
      4     
      5     
      6     create t.
      7     assign t.a = 123.
      8     
      9     run pr /* no-error */ .
     10     
     11     message t.a.
     12     
     13     procedure pr:
     14                             
     15      def buffer t for t.
     16     
     17   1  do on error undo, return error "blad":
     18   1 
     19   1     create t.
     20   1     assign t.a = 1.
     21   1     
     22   1     create t.
     23   1     assign t.a = 1.
     24   1 
     25      end.
     26     
     26     end.
.\konstr\podw.p                       05/05/2009 22:24:37   PROGRESS(R) Page 2   

     File Name       Line Blk. Type   Tran            Blk. Label            
-------------------- ---- ----------- ---- --------------------------------
.\konstr\podw.p        13 Procedure   No   Procedure pr                     
    Buffers: t

.\konstr\podw.p        17 Do          No                                    
.\konstr\podw.p         0 Procedure   No                                    
    Buffers: t

Well I don't see transaction here.
 
Back
Top