Oracle APEX : How to show error message in dynamic action - plsql

I am trying to display a success/error message with a dynamic action but nothing is showing up.
Here is my code for the true condition of my action.
declare
v_complete number;
begin
select count(task_status) into v_complete from IT_TASK where TASK_STATUS != 3 AND REQUEST_ID = :P32_ID ;
if v_complete > 0 then
apex_application.g_print_success_message := '<span style="color:red">Not all Task are complete!</span>';
rollback;
end if;
if v_complete = 0 then
apex_application.g_print_success_message := '<span style="color:green">All Task are complete!</span>';
rollback;
end if;
end;
However, no message appears after my condition is met.
Can anyone tell me why?

apex_application.g_print_success_message is only used by the Apex engine when rendering the page - after the page has been rendered, any dynamic actions that change it will have no effect.
A simple way you might achieve your goal is to add a display-only item to your page, e.g. P1_RESULT, and in your dynamic action set its value. Your dynamic action could also show and/or hide the display item as needed.

you need to initialize v_complete to 0 when declaring
declare
v_complete number := 0;
begin..
.......

Run the query in sqlplus or sqldeveloper and see the results. Add a third condition for v_complete < 0 with a different message. Also, turn on debugging and see if it's getting to the true condition. Also, best practice is to avoid putting anonymous PL/SQL blocks into APEX apps. This should be in a stored function and called to enhance reuse and maintenance.

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

APEX Collection Loading in Pre-Rendering Process: Error: WWV_FLOW_COLLECTIONS_UK

I am running a delete/creation of an APEX Collection from pre process (code below) and am running into the following error once in a blue moon.
I saw a couple posts on this error, but they seem to be related to a different issue. There were some comments about the error being caused by the user multi clicking a button that runs this process twice, but this is an on load PL/SQL process.
Has anyone been able to fix this error consistently?
ORA-00001: unique constraint (FLOWS_030000.WWV_FLOW_COLLECTIONS_UK)
violated
IF APEX_COLLECTION.COLLECTION_EXISTS('DWLOAD') then
APEX_COLLECTION.DELETE_COLLECTION (
'DWLOAD');
end if;
APEX_COLLECTION.CREATE_COLLECTION_FROM_QUERY_B(
p_collection_name => 'DWLOAD',
p_query => 'select a.seq,
b.PWSID,
b.pws_pop_served_count
from RELATED_PWS a, SYSTEM_INFO b
where a.fk_pwsid = b.pwsid and seq= ' || :P77_SEQ || '');
Execution options for the Pre Process > "Once per page visit"
Thanks,
Update::
So I was able to replicate it by rapid clicking on the link to load the page. So then the page load runs multiple times. I am looking to see if I can show processing on the href link. For button page submissions I added a DA with Show Processing Page submit which seems to block the multi click.
maybe use server-side condition will solve the problem.
plsql -> IF APEX_COLLECTION.COLLECTION_EXISTS('collection_name') then
return false;
ELSE
return true;
END IF;

Why doesn't my SQLite database add data until I close my application?

My Delphi application is using FireDac and an SQLite database. I've noticed that updates are being saved in a journal file and the database file is not actually updated until I close my application.
The application is making lots of 'batch updates' to the database. Each individual update is inside a TFDQuery.StartTransaction ... TFDQuery.Commit pair. Despite this, it seems all updates are held in the journal file until the application ends.
How can I force SQLite to update the database after each batch of updates rather than when my application finishes?
I've tried changing the SQLite db to WAL but the same thing happens.
Despite using 'StartTransaction' and 'Commit' the data stays in the journal until the application ends.
try
Query.Connection := FDConnection1;
FDConnection1.Open;
FDConnection1.StartTransaction;
Query.SQL.Text := 'select 1 from t_Manufacturers where m_Name = ' + QuotedStr(ManString);
Query.Open;
if Query.RecordCount = 0 then begin
{ not found, so add }
Query.SQL.Text := 'insert into t_Manufacturers (m_Name, m_ManUID) values (:Name, null)';
Query.ParamByName('Name').AsString := ManString;
Query.ExecSQL;
{ save m_ManUID for logging }
Query.SQL.Text := 'select m_ManUID from t_Manufacturers where m_Name = ' + QuotedStr(ManString);
Query.Open;
end;
Result := Query.FieldByName(m_ManUID).AsInteger;
FDConnection1.Commit;
except
on E : EDatabaseError do begin
MessageDlg('Database error adding manufacturer: ' + E.Message, mtError, [mbOk], 0);
FDConnection1.Rollback;
end;
No error messages or issues. Providing the application finishes OK, the database is updated as expected, so I'm happy that my programming and SQL is doing exactly what I need in that respect.
It is very dubious that "it seems all updates are held in the journal file until the application ends". SQLite3 is very serious about writing data - more serious than most DB engines I know. Just check https://www.sqlite.org/atomiccommit.html
I suspect you are somewhat confused by the presence of the journal file. After a transaction, the journal file is still kept there on disk, ready for any new write operation. But the data is actually written in the main file.
Just write some data, then kill the application before closing it (using the task manager). Then re-open the file (re-start the app): I am almost sure you will see the data properly stored.
FireDAC is "cheating" with the default journalization mode, for best performance. It uses some default values which may be confusing. As stated by FireDAC documentation: Set LockingMode to Normal to enable shared DB access. Set Synchronous to Normal or Full to make committed data visible to others.
You are using FDConnection1.StartTransaction; In this state condition, the transaction is still on the memory (cache) without any end. Therefore, you need to end your transaction with commit command such like FDConnection1.Commit;
OK, I went back to basics and wrote a test application with all the database activity confined to a single procedure fired by a button click. In that procedure I added multiple rows to a table using a for loop.
The for loop is surrounded by StartTransaction and Commit calls. Running through the code in the debugger, the journal file is created on the first call to ExecSQL. However, the file remains there after the loop has completed and Commit has been called.
The database is only updated and the journal file deleted when Close is called at the end of the procedure.
procedure TForm1.Button1Click(Sender: TObject);
var
Query : TFDQuery;
Index : Integer;
begin
FDConnection1.DriverName := 'SQLite';
FDConnection1.Params.Values['Database'] := 'C:\Testing\test.db';
FDConnection1.Open;
Query := TFDQuery.Create(nil);
Query.Connection := FDConnection1;
try
FDConnection1.StartTransaction;
for Index := 1 to 10 do begin
Query.SQL.Text := 'insert into Table1 (Name, IDNum) values (:Name, :IDNum)';
Query.ParamByName('Name').AsString := 'Test_Manufacturer_' + IntToStr(Index);
Query.ParamByName('IDNum').AsInteger := Index;
Query.ExecSQL;
end;
FDConnection1.Commit;
except
on E : EDatabaseError do begin
MessageDlg('Database error adding manufacturer: ' + E.Message, mtError, [mbOk], 0);
FDConnection1.Rollback;
end;
end;
Query.Destroy;
FDConnection1.Close;
end;
I'm suspecting that I have another connection to the database open within my application and that might be stopping the update until the application closes. However, I'm still not understanding why the call to Commit isn't updating the database at the end of the transaction block.

Opening and closing database connections in multiuser environment

This is a multiuser application (multithreaded) where various departments will access their own database.The database is SQLite and I am using FireDac.For each department I have assigned a separate ADConnection so I dont get any unexpected locks.
Which connection will be activated (active) depends solely on the number produced by the ADQuery3. This is done on MainForm Show because it needs to be this way (which gets shown after successfull login). I would like to be able to close every connection on FormClose but I run into some bad issues when multiusers use the same database and log in and out.So I would like to ask if this is the right programming logic I am doing or this could be done in a better way?
Also I have never used this many begin end else and I am wondering how to proceed with this?
I mean when I need to check the if the number of another department came up, like
if DataModule1.ADQuery3.FieldByName('DEPARTMENT').AsString = '12' where does the next ELSE come up?
procedure TMainForm.FormShow(Sender: TObject);
begin
if DataModule1.ADQuery3.FieldByName('DEPARTMENT').AsString = '13'
then begin
try
if DataModule1.1_CONNECTION.Connected = true then
DataModule1.1_CONNECTION.Connected := False
else
DataModule1.1_CONNECTION.DriverName:= 'SQLite';
DataModule1.1_CONNECTION.Params.Values['Database']:= ExtractFilePath(Application.ExeName)+ 'mydatabase.db';
DataModule1.1_CONNECTION.Connected := true;
DataModule1.ADTable1.TableName :='DEPT_13';
DataModule1.DEPT_13.Active:=True;
cxGrid1.ActiveLevel.GridView := DEPT_13;
except
on E: Exception do begin
ShowMessage('There was an error... : ' + E.Message);
end;
end;
end;

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