Logging stored procedure access in Oracle - oracle

Is there an convenient way to log access to stored procedures from withing Oracle? I am a web developer and presently we are required to pass a variety of user info to many stored procedures so that those procedures can in turn call another procedure that logs access to the original stored procedure in a table.
For example if I want to call a procedure called get_movie(id) that will return a row from the movie table based on id, I would have to do something like this get_movie(username, domain, ip, id) so that the procedure can log the user/domain/ip of the web user who initiated the call to the procedure.
It seems like there must be a better way but my knowledge of Oracle is limited.

I would set the common parameters using a procedure and sys_context every time you get your connection
e.g:
CREATE OR REPLACE PROCEDURE set_context
(
v_userid IN VARCHAR2,
v_domain IN VARCHAR2,
v_ip IN VARCHAR2,
v_id IN VARCHAR2
)
AS
BEGIN
DBMS_SESSION.SET_CONTEXT('SESSIONCONTEXT', 'username', v_userid);
DBMS_SESSION.SET_CONTEXT('SESSIONCONTEXT', 'domain', v_domain);
DBMS_SESSION.SET_CONTEXT('SESSIONCONTEXT', 'ip', v_ip);
DBMS_SESSION.SET_CONTEXT('SESSIONCONTEXT', 'id', v_id);
END;
and to query the values:
SELECT SYS_CONTEXT('SESSIONCONTEXT', 'username') FROM dual;
see: http://download.oracle.com/docs/cd/E14072_01/server.112/e10592/functions182.htm
and
Is there a way to communicate application context to a DB connection in non-Sybase DB servers (similar to set_appcontext in Sybase)?

It is probably impossible to do that. (warning many assumptions upcoming)
Primarily because the user from oracle's perspective is probably whatever user is connecting from your application to the database. Oracle certainly knows about the user connecting, but I would venture to guess that most if not all of your queries to the db are done through a single user configured in a properties file somewhere.
That is why these values need to be passed in, because the application has a connection to those users and can know their ip. However, the db doesn't as it is (hopefully) sectioned off from users connecting directly.

Other option is to open an oracle user for every "end user" and grant them access to the schema where the business logic is. USe public synonyms.

Related

How to view/execute granted stored procedure in Oracle SQL developer

The user that I use to access a particular DB has been granted EXECUTE privilege for a stored procedure managed by another user. Is there any way to view or run that stored procedure in Oracle SQL developer like a regular stored procedure? At the moment I don't see it in the Procedure tab in connections to right click and run. I am executing the stored procedure in java but I need to be able to test it in SQL developer.
The procedure won't appear in the tree list immediately under your connection, as those are only ever the ones that the user you are connected as owns themselves. (If you right-click and choose 'Filter', there is an option to 'override schema filter', but even with a filter and that flag set you don't see other users' procedures.)
But right at the bottom of the list of objects types under your connection is an 'Other Users' entry. If you expand that, find the owner of the procedure and expand that, and then expand the list of procedures under that user - you'll see all of their procedures that you have permission to view/execute.
You can then run it from there the same way you would run your own procedures.
You can also right-click on your connection and choose 'Schema Browser'; then in the tab that appears you can more easily change user, and change the object type to 'Procedures'. You might find that faster than navigating the tree.
#thatjeffsmith has a post about navigating via the tree or the dropdowns (of course - should have looked their first...)
If you have a procedure "test_procedure" in your shema you would execute it like this:
begin
test_procedure;
end;
If you have it in another schema, lets say "parent" then you would call it like this:
begin
parent.test_procedure;
end;

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.

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.

Can GRANT be used inside an Oracle Store Procedure?

When trying to place a GRANT statement in an Oracle 11 stored procedure, it reports that GRANT is an unexpected symbol. Does GRANT need to be prefaced by something, or does Oracle simply disallow running GRANTS inside SPs?
It's a bad idea to use DDL (like GRANT) inside stored procedures.
You will have to use dynamic SQL (EXECUTE IMMEDIATE) to do this, but, honestly, I don't see why would you want to do this inside a stored proc.
Here's a PL/SQL stored procedure that grants object privileges (SELECT, UPDATE, etc.) on all tables owned by the current user to another user, e.g. - "appuser".
CREATE OR REPLACE PROCEDURE grant_privs
IS
CURSOR ut_cur IS SELECT table_name from user_tables;
ut_rec ut_cur%rowtype;
BEGIN
FOR ut_rec IN ut_cur
LOOP
EXECUTE IMMEDIATE 'GRANT ALL ON ' || ut_rec.table_name || ' TO appuser';
END LOOP;
END;
/
It was executed automatically after deploying database changes for a web application. The current user owns the database tables. After deploying any database changes, the stored procedure was executed to ensure that "appuser" could run SQL statements on all of the tables. The web application connected as "appuser", which had only limited system privileges, for security reasons.
This is both a solution to the problem and a solid use case for the solution.

How may I see the data in the Oracle view like I see it through the application?

When I navigate through the Oracle application with my application user and the right responsibility, I see the data.
I use the "record history" menu to see which table/view is used by application.
So, I got PA_EXPEND_ITEMS_ADJUST2_V.
When I'm connected with apps user in a sqlplus session,
SELECT * FROM PA_EXPEND_ITEMS_ADJUST2_V
gives me 0 rows.
I guess that there's something is misconfigurated with the apps but what ?
How may I view the rows of PA_EXPEND_ITEMS_ADJUST2_V using apps user in a sqlplus session ?
How may I see the data in the Oracle view like I see it through the application ?
There is probably some row-level security happening here. Possibly based on views, possibly the built-in RLS/FGAC/VPD (or whatever acronym they give it with that version). That's where the database rewrites the query behind the scenes to add in filters.
Generally there are based on SYS_CONTEXT values.
In Oracle Applications you have to execute the APPS.FND_GLOBAL.apps_initialize procedure to have the same context in a SQL*Plus session. I use the following script to start a session:
SET SERVEROUTPUT ON
DECLARE
l_user_id NUMBER;
l_resp_id NUMBER;
l_app_id NUMBER;
l_resp_name VARCHAR2(100) := '<Name of your responsibility>';
l_login VARCHAR2(30) := '<USERLOGIN>'
BEGIN
SELECT user_id INTO l_user_id FROM fnd_user WHERE user_name = l_login;
SELECT application_id, responsibility_id
INTO l_app_id, l_resp_id
FROM fnd_responsibility_vl
WHERE responsibility_name = l_resp_name;
apps.fnd_global.apps_initialize(l_user_id, l_resp_id, l_app_id);
dbms_output.put_line('l_user_id = '||l_user_id);
dbms_output.put_line('l_resp_id = '||l_resp_id);
dbms_output.put_line('l_app_id = '||l_app_id);
END;
/
You will need to log into oracle with the same user ( or a user with the same rights/roles ) as what the application is using.
You need to talk to your DBA.
Another possibility (apart from row-level security, which may be involved) is that the view is based on one or more global temporary tables - which means you won't see the data unless you query from within the same session that inserts it.
Or, perhaps, the app is deleting the data after it's finished with it ;)

Resources