Does on-select trigger fire during/after query-procedure trigger fires? - oracle

I have a form that I'm looking at, which makes use of stored procedures as data block source. I'm trying to find when/where the block gets populated.
The block as query data source type as Procedure, but the procedure listed as the data source name does nothing - literally nothing. The code in the procedure is
begin
null;
end;
Going through the list of procedures in the package responsible for handling the form, I found a procedure which does populates the data.
Searching for this procedure, I found that this procedure is invoked during ON-SELECT trigger.
So - does ON-SELECT trigger get fired during/after QUERY-PROCEDURE event? If not when does it get fired?
I'm using Oracle Forms10.1.2.3.0, 32-bit on Windows Vista.

From the Forms on-line help for ON_SELECT:
Fires when Oracle Forms would normally
execute the open cursor, parse, and
execute phases of a query, to identify
the records in the database that match
the current query criteria.
Use an On-Select trigger to open and
execute the database cursor.
Specifically, use this trigger when
you are retrieving data from a
non-ORACLE data source. The On-Select
trigger can be used in conjunction
with the On-Fetch trigger to replace
the processing that normally occurs in
the EXECUTE_QUERY built-in subprogram.

Related

ORACLE trigger before procedure execution

Is it possible to fire a trigger before a specific procedure starts execution?
For example I have a package "A", and a procedure "B" inside package "A".
So when I call A.B procedure i want to fire a trigger.
I'm using oracle 11gR2.
is it possible to fire a trigger before a specific procedure starts execution?
No, you cannot manually fire a trigger without any DML operation on the table. Triggers are designed to act implicitly on any DML action. Trigger is a (side)effect of an action and not an action in itself.
I don't think you need a trigger for your requirement. You could call a procedure before executing the procedure A.B. Put your business logic accordingly. PL/SQL is a procedural language. So, if you put another procedure say procedure C before A.B, then A.C will be executed before A.B.
Triggers cannot be called directly. Instead they are fired automatically when you perform an insert/update or delete on a table that has triggers. So like in your case, on calling A.B procedure, you can perform an insert / update or delete that will force a trigger to fire.
If you have an existing trigger on a table and you want its logic to be executed under other circumstances, then place the logic in a procedure and call that procedure from the trigger, and from any other code that needs to execute it.

Quick method to catch/capture Stored Procedure calls (with parameters) in Oracle?

I need to capture Oracle stored procedures calls (with parameters) to trace an application (which uses JDBC to connect to the DB). I need something like sp_trace_setevent for Rpc:Completed event in MS SQL SERVER.
I do not have access to this application, but have mostly all rights in the database. I would like to stay in PL/SQL (and Oracle SQL Developer 3.2.20).
I have tried:
Oracle SQL Developer UI "Tools"/ "RealTime SQL Monitoring" and "Tools"/ "Sessions" instruments but can't understand how to enabling accumulating information instead of capturing moment snapshot.
exploring v$sql - it seems there are no sp calls.
v$sqlarea differences (Oracle: is there a tool to trace queries, like Profiler for sql server? , mdj3884 reply) - there I am able to find my test call, but without parameters...
Suggestion from Tom's article : http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:767025833873. Particularly, it is looping through v$sqltext_with_newlines, but I can't understand what is a script result. Something more like moment snapshot; isn't it? But then why they call it tracking?
use DBMS_APPLICATION_INFO - as I understand using this I can add custom info to V$SESSION and V$SESSION_LONGOPS - it can be useful for monitoring tasks but I can't imagine how it can be used for accumulating information about sp calls and theirs parameters.
use DBMS_MONITOR for enabling tracing into file. but I can't find option to enable tracing only sp call events, also it requires access to the server files.
DBMS_PROFILER - collects as I understand by default it collects only statistics (min, max time); there should be possibility to add custom information to plsql_profiler_runs but I can't find this table (when DBMS_PROFILER is in place).
What to see next? What I have missed?
P.S. If the only one way is to change SP body (those SP which need to be traced) then what is the quickest and safest way to log sp parameters from sp body in Oracle? It could be logging to custom table, but may be I could choose between generating another types of events (that are not rollbacked, something like SQL Server custom trace events)?
It would be easy to add some custom functionality to do this (see below for most of what is required) or you could use sqltrace or the enterprise manager reports and search through them:
create package p_audit as
type t_param_type is table of varchar2(50) index by binary_integer;
procedure p_audit (p_procedure varchar2, l_param_type t_param_type);
end;
create table audit_table (procedure_name varchar2(50), parameters varchar2(500))
create or replace package body p_audit is
procedure p_audit (p_procedure varchar2, l_param_type t_param_type) is
pragma autonomous_transaction;
begin
insert into audit_table values (p_procedure,l_param_type(1));
commit;
end;
end p_audit;
declare
l_param_type p_audit.t_param_type;
begin
l_param_type(1):='parameter 1';
p_audit.p_audit('test procedure',l_param_type);
end;
I used DBMS_AUDIT trail to determine what kind of procedures/functions/packages used when a client side application executed. I would really recommend you to use it once, it really helps, but problem is that you cannot analise deeper in a package hierarchy, its function/procedure called (calls), but only its usage. If you want to know dependency of the package you can use ALL_DEPENDENCIES. It can be helpful.

"who_called_me" equivalent for Hibernate

We know that it is possible to dynamically figure out the name of the procedure or package that is currently executing as explained here and here. This generally applies to statements being executed from other stored procedures (compiled) in the database.
The problem:
We have been trying to log all UPDATE activity on a specific column (called STATE) by placing a trigger on the table and invoking who_called_me from within the trigger. The purpose of doing this is apparently as per the application design the column STATE could get updated by multiple pieces of code (residing in the database) based on certain business conditions. In addition to that, the column could also get updated by the application which is a hibernate based application and at times when the update happens by a hibernate query the who_called_me function returns nothing. There are multiple parts in the application that could also UPDATE the column STATE based on certain conditions.
The who_called_me strategy is working well for us in cases where a stored procedure (which resides in the database) issues the UPDATE statement and who_called_me is successfully capturing the corresponding owner, name, line no. etc. of the stored procedure. But in case the UPDATE happens from hibernate, the function captures no details.
Is there a way to capture which hibernate query UPDATEd the row through the trigger? Or is there any other way?
Note: The trigger code is similar to the answer posted on this question.
you can track the query with ora_sql_text function, e.g. this is the function I use for that:
-- getting sql code, which is calling the current event, as clob
function getEventSQLtext
return clob
is
sqllob clob;
sql_text ora_name_list_t;
dummy integer;
begin
dummy := ora_sql_txt(sql_text);
dbms_lob.createtemporary(sqllob,false);
for i in 1..sql_text.count loop
dbms_lob.writeappend(sqllob,length(sql_text(i)),sql_text(i));
end loop;
return sqllob;
if dummy is null then null; end if; -- removing warning of non-used variable :)
end;
This will be a query which is generated by hibernate and this is the only information you can get because this should be the only thing hibernate can do with DB.
It turns out, the who_called_me approach works better for stored procedure calls where the stack trace can point exactly which line invoked a DML. In, case of hibernate it is possible that the code may not call a stored procedure but in-turn may have individual DMLs which get invoked based on certain conditions. As opposed to other answer given by #simon, the ora_sql_txt function may only work in system event triggers or I may be wrong, but either way it is not capable of capturing the SQL Statement issued by Hibernate (tested that it does not works and retunrs a NULL value).
So at the end of the day, to find what SQL Hibernate is using, DB Trace files and Hibernate debug level logs is the only way for now.

FRM-40401 no changes to save after WHEN-CREATE-RECORD trigger

I googled this but, unfortunately, could not find any solution.
I have a simple form (Oracle Forms Builder 10g) with a single block. The form is written in Oracle EBS style, that is, the block is based on a view that fetches the base table fields together with the rowid and DML events (on-insert, on-update etc. triggers) are handled by a table handler package.
The functionality I wanted to add was the following: when a user creates a new record, the form automatically suggests values for all fields in the form. So, I created a WHEN-CREATE-RECORD trigger that calculates the field values and assigns them. All, except the primary key wich is based on a Sequence and is handled by the package.
Everything runs OK when I create the new record but when I attempt to save it, all I get is a FRM-40401 "no changes to save" error and nothing happens.
I tried to trace the error and it seems like the form considers the record as NEW with no changes on it. This happens even if I try to explicitly alter the record status to INSERT.
I already tried to change the default behaviour to STANDARD.COMMIT (created an ON-COMMIT trigger for that) but this did not dfix anything.
For the record, I tried to make the form table-based, getting rid of table handlers and leaving all DML to Forms. I still get FRM-40401.
I can't understand what is going wrong, any ideas please?
The record status is reset to NEW after the when-create-record trigger completes. This normally makes sense, since you are effectively setting the default values for items, but the user hasn't actually entered any data yet.
You need something to mark the record for insert after the trigger has finished - normally the user would do this when they enter some data into the record. If you want the user to be able to save the record without changing anything in it, you could perhaps add something to the save button to do a no-change assignment, e.g.
:MYBLOCK.ANYITEM := :MYBLOCK.ANYITEM;
This would cause the record to be marked for insert.
OK, for the time being I used the classic TIMER workaround and everything works as it should:
PACKAGE body form_timers IS
PROCEDURE CREATE_NEW_RECORD;
procedure do_create(name varchar2) is
timer_id TIMER;
Begin
timer_id := CREATE_TIMER(name,1,NO_REPEAT);
End;
procedure expired is
expired_timer CHAR(20);
BEGIN
expired_timer:=GET_APPLICATION_PROPERTY(TIMER_NAME);
IF expired_timer='CREATE_NEW_RECORD' THEN
CREATE_NEW_RECORD;
-- ELSIF expired_timer='T2' THEN
-- /* handle timer T2 */ NULL;
ELSE
NULL;
END IF;
END;
PROCEDURE CREATE_NEW_RECORD IS
/* create record logic goes here */
END;
END;
... but still, I'd like to know why this behaviour occurs.

Insert, delete ,update when using Stored Procedure component

We have an application written in Delphi 2010 which connects to SQL Server Database. Now we're in the process of migrating to Oracle. With SQL Server it was very easy to perform insert, update, delete right from a dbgrid connected to a Stored Procedure.
It's because stored procedures in SQL Server can easily act as a table so that you can do any operation on it, providing it returns the necessary columns within the resultset. Now with Oracle I don't know how do do it. I connect a DBGrid to a DataSource, dataset of which is a Stored Procedure object,but I can't edit the grid. Just Select is possible.
What do I have to do to to achieve this?I use UniDac component suite to connect to Oracle database.
Oracle does not support such functionality. IOW, in Oracle you cannot edit result set provided by a stored procedure or include stored procedure into INSERT INTO <name>, UPDATE <name> or DELETE FROM <name>.
While it is traditional for SQL Server developers to "always" use stored procedures (due to many reasons), it is not traditional for Oracle developers. But it is possible with Oracle too. Search for "REF CURSOR" to see how to fetch data using SP. And use normal or packaged (preferred) SP to post updates to a DB. These procedure will receive old / new field values through arguments.
I cannot say precisely about UniDAC, I can say about AnyDAC. But I will expect UniDAC has similar functionality. To use SP for posting updates you will need to use TXxxUpdateSQL component.
OK,here I'm answering the question though I can see very few are dealing with Delphi recently. Let's say we have a stored proc in Oracle database:
CREATE OR REPLACE PROCEDURE GET_EMPLOYEES
(V_CUR IN OUT SYS_REFCURSOR)
AS
BEGIN
OPEN V_CUR FOR SELECT * FROM EMPLOYEES;
END GET_EMPLOYEES;
Now, in Delphi you pick a stored procedure component (probably from ODAC or UniDac component suite).Set its StoredProcName GET_EMPLOYEES. Then you can add all the fields that the procedure returns in a cursor.If you run the application and activate the stored procedure you'll be able to see all the records. But if you try to insert, modify or delete anything you'll fail to do so. Now, there's a very tricky thing. If you check, you'll see that ReadOnly property of all fields are set to True. Even after you set them to False nothing will change in the real database, although you can edit the DBGrid.
So, we've come to the main part. How did the old Delphi-SQL Server partnership work so that you could do any operation right from a DBGrid? Well, we must understand that there's no magic. If it's SQL, then SQL has only one way of INSERTING,UPDATING and DELETING records-it's with the appropriate SQL statements.With Delphi-SQL Server there seems to be an implicit SQL statement that we never paid attention. But with Oracle, we have to provide our own statements for each operation.
If you use UniDac or ODAC then there's SQLInsert,SQLUpdate,SQLDelete properties in a StoredProc object.If you want to insert a record through DBGrid, then you should edit its SQLInsert property to
INSERT INTO EMPLOYEES VALUES(:EMPLOYEEID,:EMPLOYEENAME)
where variables following : are corresponding to te fields of the stored procedure.They're simply bind variales.When updating and deleting though you'll need some unique value to represent a specific record. Primary key is one option(maybe the only option as I haven't been able to figure out how to use ROWID for the same purpose).So the sql statements for UPDATE and DELETE would be
DELETE FROM EMPLOYEES WHERE EMPLOYEEID=:EMPLOYEEID
and
UPDATE EMPLOYEES SET EMPLOYEENAME=:EMPLOYEENAME WHERE EMPLOYEEID=:EMPLOYEEID
P.S. I just found a way to use ROWID for update and delete statements. In your stored procedure if you choose ROWID too and give it an alias then you can construct your UPDATE and DELETE Statements like such:
UPDATE EMPLOYEES SET EMPLOYEENAME=:EMPLOYEENAME,..... WHERE ROWID=:RECORD_ROWID
DELETE FROM EMPLOYEES WHERE ROWID=:RECORD_ROWID
In the preceding statements RECORD_ROWID is the fieldname returned from stored procedure as a result of aliasing ROWID. If you use :ROWID instead you'll get "ORA-01745: invalid host/bind variable name" error. This is because in a binding variable a colon cannot be followed by a reserved word. And ROWID is a reserved word.

Resources