views:

420

answers:

3

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

A: 

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.

Tony Andrews
Seems to be a good solution. Is this package variable shared among other connections?
John
No, it is unique to the connection. Connection pooling would be unusable if different end-users were sharing the same database state!
Tony Andrews
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.
Gary
+8  A: 

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

FRotthowe
+1 This seems to be the "right" way to do it!
Tony Andrews
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.
Justin Cave
+5  A: 

Hi John,

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
Vincent Malgrat