Where to perform final processing before application closes? - smart-mobile-studio

I have been trying to write out data to storage when the form closes or the application terminates and have NOT been successful.
I first tried from the Form unit
procedure TForm1.FinalizeObject;
begin
inherited;
SaveData;
end;
and
procedure TForm1.FinalizeObject;
begin
SaveData;
inherited;
end;
neither of these attempts worked, therefore I rrearranged my code and tried it from the project’s unit
procedure TApplication.ApplicationClosing;
begin
SaveData;
inherited;
end;
and
procedure TApplication.ApplicationClosing;
begin
inherited;
SaveData;
end;
I have a w3_showmessage as the first line of SaveData, and it never gets called ever....so, if i can verify that one of these 4 methods is triggered, i could use one of them
What am i doing wrong? Thanks

As of writing, Smart exposes two new events in the application object:
OnUnload
OnBeforeUnload
These will make it easier to handle shutdown sequences. The smart javascript bootstrap also calls application.terminate() automatically now, so your code should work fine.

Related

SQL Developer DBMS_OUTPUT without 'PL/SQL procedure successfully completed.'

In SQL Developer, when running some PL/SQL, when the procedure is completed, the message 'PL/SQL procedure successfully completed.' is returned.
The PL/SQL that is run may return error messages to the user if the operation could not be completed for any reason through DBMS_OUTPUT.PUT_LINE, however, the user will also see 'PL/SQL procedure successfully completed.', which could be misleading (especially if the Script Output window is small enough that the DBMS_OUTPUT is not visible).
Is there any way to have the DBMS_OUTPUT return what it should whilst also having the script not return 'PL/SQL procedure successfully completed.'?
If not, are there any alternatives in SQL Developer that I may be unaware of to provide instant personalised feedback to the user?
declare
testex exception;
begin
if 1=1 then
raise testex;
end if;
exception when testex then
dbms_output.put_line('Error msg');
end;
Below code works in my end. Did you try to run your code like below?
Copied text from a website to explain the SET FEEDBACK OFF command.
Source link: https://docs.oracle.com/cd/B19306_01/server.102/b14357/ch12040.htm
SET FEED[BACK] {6 | n | ON | OFF} -
Displays the number of records returned by a script when a script selects at least n records.
ON or OFF turns this display on or off. Turning feedback ON sets n to 1. Setting feedback to zero is equivalent to turning it OFF.
SET FEEDBACK OFF also turns off the statement confirmation messages such as 'Table created' and 'PL/SQL procedure successfully completed' that are displayed after successful SQL or PL/SQL statements.
Add a RAISE statement in the error handler to re-raise the exception so that any outer handler can deal with it:
declare
testex exception;
begin
if 1=1 then
raise testex;
end if;
exception when testex then
dbms_output.put_line('Error msg');
RAISE; -- re-raise the exception to an outer handler
end;
Best of luck.
You have coded it explicitly to complete successfully in the event of a testex exception. The code says: if this happens, then print a message and end. If you want it to actually fail then it needs to raise an exception.
I would just use something like this:
begin
if 1=1 then
raise_application_error(-20000, 'Bananas are not available on a Tuesday');
end if;
end;
/
begin
*
ERROR at line 1:
ORA-20000: Bananas are not available on a Tuesday
ORA-06512: at line 3
This will cause an actual error, rather than just printing out a message that happens to talk about an error, allowing you to control deployments and build scripts etc.
It will also roll back any uncommitted transactions within the block, which your current approach does not, and it will show the actual line number.

Database logging in logging procedure

Perhaps a silly question, but say I have a logging procedure like so (greatly simplified for brevity):
PROCEDURE LOGGER (
p_TYPEOFLOG IN VARCHAR2,
p_LOGSEVERITY IN VARCHAR2,
p_SESSIONID IN VARCHAR2)
AS
v_timestamp DATE := SYSDATE;
BEGIN
PRAGMA autonomous_transaction;
BEGIN
INSERT INTO Log (
TypeOfLog, LogSeverity, SessionID, TimeOfAction)
VALUES (
p_TYPEOFLOG, p_LOGSEVERITY, p_SESSIONID, v_timestamp);
COMMIT;
END;
END LOGGER;
Now, usually I would wrap the begin/end bit up with an exception handler, which would call this logger procedure. But what do I do if I'm already in the Logger? Do I simply do an exception if when others null and skip it? Do I try calling the Logger procedure again? What is standard here?
I don't believe that there is such a thing as "standard".
Personally, if my logging code failed, I'd let whatever exception was generated be thrown and propagate up the stack. If you can't write to the Log table, that implies that something terribly unfortunate has happened. I wouldn't want to catch and ignore such an exception. And given no other way to log the error, I'd raise the exception back to the caller and expect the caller to either display the message to a user (i.e. a stack trace in the front end web app) or to log the message to an application server log.

PL/SQL Rollback Transaction with multiple package calls

I am new to Oracle PL/SQL and am trying to adjust from SQL Server with C# to a Oracle custom web application using PL/SQL for multiple layers of the application.
I currectly am having issues with rolling back a transaction. Since I am using to writing reusable code, I have written my PL/SQL code using packages and methods within those classes. My update procedure first completes validation and if validated successfully, calls a succession of various package methods to complete the save. Unfortunately, my rollback in the EXCEPTION portion of the update procedure does not rollback everything when the Rollback function is called. I'm at a loss as to why it is doing this. My basic code (although not exact due to legal issues) is as follows:
PROCEDURE SaveApplicationData(
variableName IN VARCHAR2 DEFAULT NULL,
--...
seq_id OUT INT )
AS
BEGIN
SET TRANSACTION NAME 'Transaction Name';
--Save initial program record
SaveNewRecord(variableName, seq_id);
IF (seq_id != 0) THEN
--If saved successfully, seq_id represents record ID
package_class.secondarySaveMethod(variableName, seq_id);
second_package_class.anotherSaveMethod(variableName, seq_id);
END IF;
COMMIT;
htp.p('Sequence ID: ' || seq_id);
htp.p('Saved the record"' || programName || '" successfully!');
EXCEPTION
WHEN OTHERS THEN
utilityPackage.rollbacktransaction;
END SaveApplicationData;
The utilityPackage.rollbacktransaction includes a ROLLBACK as well as the custom error exception handling package used by our organization.
Essentially, it will roll back the section that causes the error, but as soon as it rolls the section back, it continues with the rest of the transaction (and does not roll back previously executed blocks of code).
Please let me know if this does not make sense - and thank you in advance for your help!
Coming from a SQL Server environment before Oracle I can understand the confusion. Oracle does not use a BEGIN TRANSACTION. Instead, a transaction is implicitly started for you.
Thus, I believe in your case SET TRANSACTION NAME is not what you are looking to do, see
SET TRANSACTION.
I recommend removing the rollback code from your package and placing it in C#. It should be the responsibility of the caller to commit. Use a transaction in C# to guarantee the the transaction is committed upon successful execution of the package(s).
Ideally, your package structure should look more like this.
declare
ex_custom EXCEPTION;
PRAGMA EXCEPTION_INIT( ex_custom, -20001 );
begin
--Save initial program record
SaveNewRecord(variableName, seq_id);
IF (seq_id != 0) THEN
--If saved successfully, seq_id represents record ID
package_class.secondarySaveMethod(variableName, seq_id);
second_package_class.anotherSaveMethod(variableName, seq_id);
ELSE
-- seq_id invalid throw an exception
RAISE_APPLICATION_ERROR(-20001,'Custom error')
END IF;
htp.p('Sequence ID: ' || seq_id);
htp.p('Saved the record"' || programName || '" successfully!');
EXCEPTION
WHEN ex_custom THEN
-- if needed we log it
utility.log_exception;
-- Raise it for the client to handle
raise;
END SaveApplicationData;

Is it possible to set user defined session/connection flag for use in trigger?

Consider a trigger that sets an id-column to an Oracle-sequence (next-)value on-insert. Now I want to extend it with some extra debugging actions. But they should be only active for certain connection/sessions (i.e. debugging ones).
Pseudo-Code on client side:
Open connection to oracle database
set mydebugflag=yes for that connection only
insert some stuff
close connection
Pseudo-Code on server-side (inside the trigger):
set id = someseq.next_val
if mydebugflag=yes then { do_some_extra_sanity_checks(); diagnostics();}
else: finished
How to implement such logic for an Oracle database?
Which Oracle features should I use for this?
There are a couple of ways to do this.
One is to create a package, create a package global variable (which will have session scope) in the package, and then have your client set the package variable and your trigger read it. Something like
CREATE OR REPLACE PACKAGE pkg_debug_mode
AS
PROCEDURE set_debug_mode( p_debug_mode IN NUMBER );
FUNCTION get_debug_mode
RETURN NUMBER;
DEBUG_MODE_ON constant number := 1;
DEBUG_MODE_OFF constant number := 2;
END;
CREATE OR REPLACE PACKAGE BODY pkg_debug_mode
AS
g_debug_mode NUMBER := DEBUG_MODE_ON;
PROCEDURE set_debug_mode( p_debug_mode IN NUMBER )
AS
BEGIN
g_debug_mode := p_debug_mode;
END;
FUNCTION get_debug_mode
RETURN NUMBER
IS
BEGIN
RETURN g_debug_mode;
END;
END;
The client calls pkg_debug_mode.set_debug_mode to set the debug mode and the trigger calls pkg_debug_mode.get_debug_mode to determine the current debug mode for the session.
create or replace context my_ctx using pkg_debug_mode;
CREATE OR REPLACE PACKAGE BODY pkg_debug_mode
AS
PROCEDURE set_debug_mode( p_debug_mode IN NUMBER )
AS
BEGIN
dbms_session.set_context( 'MY_CTX', 'DEBUG_MODE', p_debug_mode );
END;
FUNCTION get_debug_mode
RETURN NUMBER
IS
BEGIN
RETURN SYS_CONTEXT( 'MY_CTX', 'DEBUG_MODE' );
END;
END;
Your trigger can either call the get_debug_mode function or it can directly reference the context by putting the SYS_CONTEXT call in the trigger.

Oracle debugging techniques

I'm having difficulty debugging triggers in Oracle. Currently I'm using Oracle's Sql Developer tool.
To test a trigger I write inserts or deletes in a test window but I can't see what is happening inside the trigger. I would like to step through the trigger and see what is happening as the trigger fires. Is there any way to use select statements to display variable values inside the triggers?
Firstly, don't "start from here", or more specifically, don't use triggers. Triggers are going to force switching to row-level processing if the triggers are going to fire for each row. It's better to put the logic in a stored procedure which you call. You've then got a start (where you validate inputs) and an end and a logic path all the way through. Stored procedures are a lot easier to debug as you follow one path.
Second, never test for an error you don't know how to handle. If you don't catch it, it bubbles up to the client who gets an error report saying what went wrong (error message) and where (i.e. the error/call stack). If you try to catch it, you have to know what to do with it (and if you don't know the tendency is to ignore it - which is BAD).
Finally, you can't readily see each 'layer' of a select. The explain plan will generally tell you how its going about things. v$session_longops MAY indicate what it is currently doing. The current wait event MAY give clues as to what table/block/row it is currently working on.
A rough-and-ready simple method if you must debug triggers is to use DBMS_OUTPUT.
e.g.
SQL> CREATE OR REPLACE TRIGGER mytrigger
BEFORE UPDATE ON mytable
FOR EACH ROW
...
BEGIN
DBMS_OUTPUT.put_line('mytrigger STARTING');
... do some logic ...
DBMS_OUTPUT.put_line('old=' || :OLD.mycolumn);
DBMS_OUTPUT.put_line('new=' || :NEW.mycolumn);
DBMS_OUTPUT.put_line('mytrigger FINISHED');
END;
/
SQL> SET SERVEROUT ON
SQL> UPDATE mytable SET mycolumn = mycolumn + 1;
2 rows updated.
mytrigger STARTING
old=10
new=11
mytrigger FINISHED
mytrigger STARTING
old=20
new=21
mytrigger FINISHED
Application
I use a program from Quest called TOAD available at www.quest.com/toad/toad-for-oracle.aspx.
As mentioned above, DBMS_OUTPUT is very handy. In your editor, make sure you enable the Output window.
PL/SQL works on "blocks" of code and you can catch it with an EXCEPTION keyword.
(Please forgive my formatting, not sure how to format for web)
DECLARE
C_DATE_FORMAT VARCHAR2(20) := 'DD-Mon-YYYY';
C_TIME_FORMAT VARCHAR2(20) := 'HH24:MI:SS';
C_NOT_IMPLEMENTED_CODE CONSTANT NUMBER(5) := -20200;
C_NOT_IMPLEMENTED_MESSAGE CONSTANT VARCHAR2(255) := 'Not implemented';
not_implemented EXCEPTION; -- user defined exception
BEGIN
--RAISE not_implemented; -- raise user defined exception
RAISE_APPLICATION_ERROR(C_NOT_IMPLEMENTED_CODE, C_NOT_IMPLEMENTED_MESSAGE); -- user defined exception
EXCEPTION -- exception block
WHEN not_implemented THEN -- catch not_implemented exception
DBMS_OUTPUT.PUT_LINE('Error: Not implemented');
WHEN OTHERS THEN -- catch all other exceptions
DBMS_OUTPUT.PUT_LINE('Error occured.');
DBMS_OUTPUT.PUT_LINE('Date: ' || TO_CHAR(SYSDATE, C_DATE_FORMAT));
DBMS_OUTPUT.PUT_LINE('Time: ' || TO_CHAR(SYSDATE, C_TIME_FORMAT));
DBMS_OUTPUT.PUT_LINE('Error code: ' || SQLCODE);
DBMS_OUTPUT.PUT_LINE('Error message: ' || SQLERRM); --deal with error
RAISE; -- raise to calling object
END;
Follow below steps to DEBUG trigger in Oracle PL/SQL
Open your trigger using Edit option. Set breakpoint by clicking on line number (See below).
Open Test Window as shown below.
Write Insert/Update query for your table. (Note: Your trigger could be set on update/insert or both)
Click Start debugger button.
As soon as value will be updated in your Table. Debugger will take you to trigger. Where you can continue your debugging.