Invalid cursor exception in 2nd iteration - plsql

I am getting invalid cursor exception while iterating for 2nd time.
LOAD_TABLE_REF_CURSOR(V_TARIFF_TABLE_ROWS); -- V_TARIFF_TABLE_ROWS is a sys_refcursor.
when I am doing iteration like below.
LOAD_TABLE_REF_CURSOR(V_TARIFF_TABLE_ROWS);
LOOP
FETCH V_TARIFF_TABLE_ROWS INTO TAK_ROW;
EXIT WHEN V_TARIFF_TABLE_ROWS%NOTFOUND;
END LOOP;
The control inside the loop is going for 1st time fine and throwing exception as invalid cursor exactly at FETCH statement for the 2nd time.
Could someone tell whats wrong with 2nd iteration.

invalid cursor error is produced when;
FETCH cursor before OPENING the cursor.
FETCH cursor after CLOSING the cursor.
CLOSE cursor before OPENING the cursor.
LOAD_TABLE_REF_CURSOR(V_TARIFF_TABLE_ROWS);
open V_TARIFF_TABLE_ROWS;
-- use V_TARIFF_TABLE_ROWS
close V_TARIFF_TABLE_ROWS;

Related

UI Dialogue popping up in automated testing

As a total newbie to AL, I'm trying to set up some automated tests for an upcoming upgrade to BC19. As a proof-of-concept I'm still working in the Cronus sample database, but it's giving me a problem. I'm trying to test the Item Card; I want to create a new item, give it an unacceptable value for a couple of fields, and have it error at me.
The test seems to work just fine, except for one element - whenever I run it, I get a Confirm dialogue asking if I want to rename the record. Regardless of what I select, the test completes successfully; it doesn't report an Unhandled UI error.
I've tried adding a ConfirmHandler and a MessageHandler; I've already got a ModalPageHandler that works great. When I add the ConfirmHandler or MessageHandler though, it errors out, telling me that the handlers weren't called.
Here's my code:
[Test]
[HandlerFunctions('HandleConfigTemplates')]
Procedure AddBadTypeItem()
var
pgeItem: TestPage "Item Card";
begin
pgeItem.OpenNew();
pgeItem."No.".SetValue('zzzzz');
pgeItem."Description".SetValue('zzzzz');
Asserterror pgeItem."Type".SetValue('zzzz');
end;
[ModalPageHandler]
Procedure HandleConfigTemplates(
var ConfigTemplates: TestPage "Config Templates")
begin
ConfigTemplates.OK.Invoke();
end;
[ConfirmHandler]
Procedure HandleConfirmNo(Question: Text[1024]; var Reply: Boolean)
begin
Reply := False;
end;
Here's the dialogue I see:
And the error I see if I try to include the handlers:
The following UI handlers were not executed: HandleConfirmDialogue,MessageHandler

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

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

NetLogo: Can't "stop" forever button from another procedure?

I have simplified my problem below. I want to stop the execution of the forever button "go" when there's no robots, and I want to call this from another procedure ("test" in this case) like so:
to go
test
end
to test
if not any? robots [ stop ]
end
The reason for this is that I want to call stop where the robot dies such that I can send an appropriate user message.
Sadly, you must re-organize your code so that the you call if not any? robots [ stop ] in your go in order for the following to be true:
See the documentation:
A forever button can also be stopped from code. If the forever button
directly calls a procedure, then when that procedure stops, the button
stops. (In a turtle or patch forever button, the button won’t stop
until every turtle or patch stops – a single turtle or patch doesn’t
have the power to stop the whole button.)
Ref:http://ccl.northwestern.edu/netlogo/docs/programming.html#buttons
stop This agent exits immediately from the enclosing procedure, ask,
or ask-like construct (e.g. crt, hatch, sprout). Only the enclosing
procedure or construct stops, not all execution for the agent.
Ref: http://ccl.northwestern.edu/netlogo/docs/dict/stop.html
One alternative hacky solution which I'm tempted to not post may be to do the following where you raise an error in which then stops.
to go
carefully[test][error-message stop]
end
to test
if not any? robots [ error "no more robots!" ]
end

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).

Ada entry and when statement usage

I am a newbie in Ada programming language and I am working on concurrent programming, but I am having a problem with one implementation. This might be very dummy question. The code is:
type status is array(1..6) of boolean; --boolean values for each track
track_available :status:=(others=>true); --true if track is available
protected track_handler is
entry track_req(n:in track_part_type); --n is track number
entry track_rel(n:in track_part_type); --n is track number
end track_handler;
protected body track_handler is
--implement entries
entry track_req(n: in track_part_type) when track_available(n) is --here where the error occurs
begin
req(n);
end track_req;
entry track_rel(n: in track_part_type) when track_available(n) is
begin
rel(n);
end track_rel;
end track_handler;
procedure req(nr : track_part_type) is
begin
--null;
track_available(nr):=false;
end req;
procedure rel(nr : track_part_type) is
begin
--null;
track_available(nr):=true;
end rel;
Here I get a compilation error for "when track_available(n)" statement saying that "n is undefined". I think variable n is out of scope, but I also need to check if the n'th index of the array is true or false. How can I overcome this problem?
Thank you.
You can't actually use an entry's parameters in its own guard. You got that much, I gather.
The way guards work, all of them are evaluated before the wait starts, and only the ones that are active at that time will be available. They don't get periodicly re-evaluated or dynamicaly read or anything.
This means it will be tough to get the logic for your guards right, unless you write your code so that only other entries in your protected object modify the guards. If you want to use some data from outside of your protected object to control its behavior, you will probably need to use some mechanisim other than guards to do it. Like check just inside the entry and exit immediately or something.
There is one possibility for what you are trying to do though: Entry families. You should be able to use an entry family index in a guard.
The spec would change to:
entry track_req(track_part_type);
entry track_rel(track_part_type);
And the body would change to
entry track_req(for n in track_part_type) when track_available(n) is
begin
req(n);
end track_req;
entry track_rel(for n in track_part_type) when track_available(n) is
begin
rel(n);
end track_rel;
end track_handler;
In the code below you are trying to use track_available(n), before it has been fully defined by (n: in track_part_type).
entry track_req(n: in track_part_type) when track_available(n) is
See also http://en.wikibooks.org/wiki/Ada_Programming/Tasking#Protected_types
NWS

Resources