What is the difference between Do and Do on error in Progress 4gl? - openedge

I have observed that in both cases, statements under these two blocks will execute the same. I do not understand what the difference is. Please can you explain.

Not surprisingly ON ERROR has to do with error handling. You should read up on this in the online help/manual since there's lots of ways on what to do.
DO is basically just a block. Without anything else it really doesn't do a lot. Paired with statements like TRANSACTION or ON ERROR it can greatly change how your program executes. You should check out the NO-ERROR statement as well. It also effects error handling.
In the below examples I force an error by trying to cast the string HELLO to an integer, this doesn't work of course.
DO ON ERROR, RETRY
This will repeat the block if there's an error and setting RETRY to true. If you don't LEAVE in the RETRY-block you will have a loop.
DO ON ERROR UNDO, RETRY:
IF RETRY THEN DO:
DISPLAY "RETRY".
/* Do some cleanup or what else */
LEAVE.
END.
i = INTEGER("HELLO").
END.
DO ON ERROR, THROW
A perhaps more modern approach when THROW - CATCH is used. Note that this also supresses the error from appearing (a bit like NO-ERROR).
DEFINE VARIABLE i AS INTEGER NO-UNDO.
DO ON ERROR UNDO, THROW:
i = INTEGER("HELLO").
END.
CATCH error AS Progress.Lang.Error :
MESSAGE "We had an error".
END CATCH.
DO:
The program will just halt on error
DEFINE VARIABLE i AS INTEGER NO-UNDO.
DO:
i = INTEGER("HELLO").
END.

The ON ERROR statement gives you control on what happens when the block fails. If you are using ROUTINE-LEVEL error handling for example, errors at the block level are not caught by default, so you can
DO ON ERROR UNDO,THROW:
END.
This will make sure the error is trapped. If you are using BLOCK-LEVEL error handling then this would be trapped by default.
This is just an example, and there are many things you can use ON ERROR for. Have a look at this documentation: https://help.consultingwerkcloud.com/openedge/117/rfi1424919692411.html

Related

tSQLt - How to output a custom failure or success message?

We are using the tSQLt framework and have the below code in the test.
IF #count>0
EXEC tsqlt.fail;
else EXEC tSQLt.AssertEquals 1,1;
I am interested to know how we can display a custom test success or failure message when this test gets executed?
tSQLt.fail takes up to 10 parameters that all get concatenated into a custom failure message.
You also do not need the call to tSQLt.AssertEquals as it, in your case, literally does nothing.
BTW, asserting a count is in almost all cases a bad idea, as it does not really tell you anything about the result. If you get the correct count back, you could still have wrong data. And if you get the incorrect count, you don't have any additional info on what went wrong.
Have a look at tSQLt.AssertEqualsTable or tSQLt.AssertEmptyTable instead.

Catching errors from procedures outside of processing block

I have following code (it's simplified for illustration purposes). I'm creating records in different DB tables in proc1, proc2, and proc3. What I'm trying to achieve is...if I encounter an error while looping through temp-tables at any point (even after I created a bunch of DB records already), I want to roll everything back so no records are created. It catches errors if proc1, proc2, and proc3 with no issues but I cannot figure out how to pass those errors to the main processing block so it understands it and rolls everything back. In other words, the message ('error # main trans block') never pops up so the already created records stay in the DB. As a matter of fact, nothing gets rolled back.
DO TRANSACTION ON ERROR UNDO, THROW:
FOR EACH tt1:
RUN proc1.
FOR EACH tt2 WHERE tt2.field1 EQ tt1.field1:
RUN proc2.
FOR EACH tt3 WHERE tt3.field2 EQ tt2.field2:
RUN proc3.
END.
END.
END.
CATCH e AS PROGRESS.Lang.AppERROR:
MESSAGE 'error # main trans block'
VIEW-AS ALERT-BOX INFO BUTTONS OK.
END CATCH.
END.
PROCEDURE proc1.
DO TRANSACTION ON ERROR UNDO, THROW:
/* creating some DB records */
CATCH e AS PROGRESS.Lang.ERROR:
RETURN ERROR 'Proc1 ' + e:getmessage(1).
END CATCH.
END.
END PROCEDURE.
PROCEDURE proc2.
DO TRANSACTION ON ERROR UNDO, THROW:
/* creating some DB records */
CATCH e AS PROGRESS.Lang.ERROR:
RETURN ERROR 'Proc2 ' + e:getmessage(1).
END CATCH.
END.
END PROCEDURE.
PROCEDURE proc3.
DO TRANSACTION ON ERROR UNDO, THROW:
/* creating some DB records */
CATCH e AS PROGRESS.Lang.ERROR:
RETURN ERROR 'Proc3 ' + e:getmessage(1).
END CATCH.
END.
END PROCEDURE.
TIA
There are a couple of potential issues.
First, your temp-tables tt1 and tt2 need to be defined without the NO-UNDO flag.
Second, the FOR EACH blocks are using their default error handling behavior, which is ON ERROR UNDO, NEXT. So errors raised within the FOR EACH blocks will cause the current iteration to be undone, not the whole transaction.
I recommend adding the
BLOCK-LEVEL ON ERROR UNDO, THROW .
to the top of the program. Or at least
ROUTINE-LEVEL ON ERROR UNDO, THROW .
in combination with an ON ERROR UNDO, THROW option on all the FOR EACH blocks.
The BLOCK-LEVEL error handling option is available since OpenEdge 11.3 (or so).

Why must I remove [close_out out_channel]?

I wrote the code to send the message in ocaml.
let out_channel = Unix.out_channel_of_descr sockfd in
Marshal.to_channel out_channel message [];
flush out_channel;
close_out out_channel
However, I got warning.
GLib-WARNING **: poll(2) failed due to: Bad file descriptor.
I knew the warning was due to [close_out out_channel], and I didn't get the warning when I remove [close_out out_channel] from the code. I don't know why I must remove [close_out out_channel]. Could you tell why?
You are making an OCaml channel from sockfd. When you close the channel, you close sockfd. This will confuse whatever layer created sockfd. So things go wrong after that. Whoever is in charge of sockfd is also in charge of closing it. Just leaving out close_out out_channel is actually the right thing to do, I think. But flush out_channel is good.

CreateIndexBuffer() crashes,some kind of pointer error.What could be causing this?

I get
Unhandled exception at 0x004687b4 in D3DTest.exe: 0xC0000005: Access violation reading location 0x00000000.
the error is at:
m_d3dDevice->CreateIndexBuffer(sizeof(short)*CHUNK_PRIMITIVES*3,D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &m_ib, NULL);
Now I checked m_d3dDevice and it's all OK,everything works properly if I don't create the buffer.
m_ib is also propery created before being used in that function:
LPDIRECT3DVERTEXBUFFER9 m_vb;
m_vb = NULL;
I don't think anything else could be causing the problem.I'm confused.
Try enabling the debug runtime from the DirectX control panel that will show you warnings and errors if you have any and always check the return codes from DX functions.
Showing the code for the whole function that creates the index buffer would help too.

ASP.NET Unexpected and Different Behavior in Different Environments

I have an ASP.NET site (VB.NET) that I'm trying to clean up. When it was originally created it was written with no error handling, and I'm trying to add it in to improve the User Experience.
Try
If Not String.IsNullOrEmpty(strMfgName) And Not String.IsNullOrEmpty(strSortType) Then
If Integer.TryParse(Request.QueryString("CategoryID"), i) And String.IsNullOrEmpty(Request.QueryString("CategoryID"))
MyDataGrid.DataSource = ProductCategoryDB.GetMfgItems(strMfgName, strSortType, i)
Else
MyDataGrid.DataSource = ProductCategoryDB.GetMfgItems(strMfgName, strSortType)
End If
MyDataGrid.DataBind()
If CType(MyDataGrid.DataSource, DataSet).Tables("Data").Rows.Count > 0 Then
lblCatName.Text = CType(MyDataGrid.DataSource, DataSet).Tables("Data").Rows(0).Item("mfgName")
End If
If MyDataGrid.Items.Count < 2 Then
cboSortTypes.Visible = False
table_search.Visible = False
End If
If MyDataGrid.PageCount < 2 Then
MyDataGrid.PagerStyle.Visible = False
End If
Else
lblCatName.Text &= "<br /><span style=""fontf-size: 12px;"">There are no items for this manufacturer</span>"
MyDataGrid.Visible = False
table_search.Visible = False
End If
Catch
lblCatName.Text &= "<br /><span style=""font-size: 12px;"">There are no items for this manufacturer</span>"
MyDataGrid.Visible = False
table_search.Visible = False
End Try
Now, this is trying to avoid generating a 500 error by catching exceptions. There can be three items on the query string, but only two matter here. In my test environment and in Visual Studio when I run this site, it doesn't matter if that item is on the query string. In production, it does matter. If that third item isn't present (SubCategoryID) on the query string, then the "There are no items for this manufacturer" displays instead of the data from the database.
In the two different environments I am seeing two different code execution paths, despite the same URLs and the same code base.
The site is running on Server 2003 with IIS 6.
Thoughts?
EDIT:
In response to the answer below, I doubt it's a connection error (though I see what you're getting to), as when I add the SubCategoryID to the query string, the site works correctly (displaying data from the database).
Also, if please let me know if you have any suggestions for how to test this scenario, without deploying the code back to production (it's been rolled back).
I think you should try to print out the exception details in your catch block to see what the problem is. It could anything for example a connection error to your database.
The error could be anything, and you should definitely consider printing this out or logging it somewhere, rather than making the assumption that there's no data. You're also outputting the same error message to the UI for two different code paths, which makes things harder to debug, especially without knowing if an exception occurred, and if so, what it was.
Generally, it's also better not to have a catch for all exceptions in cases like this, especially without logging the error. Instead, you should catch specific exceptions and handle these appropriately, and any real exceptions can get passed up the stack, ideally to a global error handler which can log it and/or send out some kind of error notification.
I discovered the reason yesterday. In short it was because when I copied my files from my computer into my dev-test environment, I missed a file, which ironically caused it to work, rather than not. So in the end it would have functioned the same in both environments.

Resources