13

The purpose is to send extra information to triggers like current user id from a web application. Since a connection pool is used, and same user id is used for all connections how do I pass the original web user id to trigger? This I need to implement without touching application code. It is a java based application.

John

3 Answers 3

16

You can use the client_identifier session variable to pass an application user to a trigger.

Set it after connecting to the database like this:

  CALL dbms_session.set_identifier('<<username>>');

and retrieve it inside the trigger:

  SELECT sys_context('USERENV','CLIENT_IDENTIFIER') INTO username FROM DUAL;

More info can be found in the Oracle docs

Sign up to request clarification or add additional context in comments.

3 Comments

This works if you just need to pass one of a handful of relatively common attributes to the trigger. Vincent's approach of using contexts, however, allows the passing of arbitrary parameters.
Thanks, helped a lot when I was stuck! Just want to mention, use of the word 'USERNAME' in all-caps in the first code line is a bit confusing. It looks like it's meant to be taken literally, but really, it's a stand-in for the logged-in app user's user ID that you want to send over to the trigger. The second code line though is meant to be literal, assuming you want 'username' to be the variable holding the logged-in app user's user ID.
You're right. Better late than never: I've corrected it.
9

you could use Oracle Contexts:

SQL> CREATE OR REPLACE PACKAGE test_pkg AS
  2     PROCEDURE set_context(p_attribute VARCHAR2, p_value VARCHAR2);
  3  END test_pkg;
  4  /

Package created
SQL> CREATE OR REPLACE PACKAGE BODY test_pkg AS
  2     PROCEDURE set_context(p_attribute VARCHAR2, p_value VARCHAR2) IS
  3     BEGIN
  4        dbms_session.set_context('test_ctx', p_attribute, p_value);
  5     END;
  6  END test_pkg;
  7  /

Package body created

SQL> create context test_ctx using test_pkg;

Context created

SQL> exec test_pkg.set_context ('user_id', 'Vincent');

PL/SQL procedure successfully completed

SQL> select sys_context('test_ctx', 'user_id') from dual;

SYS_CONTEXT('TEST_CTX','USER_I
--------------------------------------------------------------------------------
Vincent

Comments

1

You can use a package to keep track of the web user:

create package web_user_pkg is

    procedure set_username (p_username varchar2);

    function username return varchar2;

end;

create package body web_user_pkg is

    g_username varchar2(30);

    procedure set_username (p_username varchar2)
    is
    begin
        g_username := p_username;
    end;

    function username return varchar2 is
    begin
        return g_username;
    end;

end;

In the web page call web_user_pkg.set_username with the current user's ID before performing any DML or other package calls.

In the trigger use web_user_pkg.username to get the web user name.

3 Comments

Seems to be a good solution. Is this package variable shared among other connections?
No, it is unique to the connection. Connection pooling would be unusable if different end-users were sharing the same database state!
Just to clarify, if there are 10 database sessions, then there are a maximum of 10 concurrent database states even if you have 50 application end users. The point of a connection pool is to share those database sessions. The application would grab one connection/session for the duration of a transaction. It would not necessarily use the same connection for a subsequent transaction by the same application end user.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.