Is there a way to communicate application context

2019-05-08 06:24发布

问题:

Sybase has a way for the application to communicate "context" data - such as application's end-user name, etc.. - to the database connection session. Context data is basically just a set of key-value pairs which is stored/retrieved via set_appcontext/get_appcontext stored procs.

QUESTION:

Do other major DB servers (MSSQL/Oracle/MySQL) have a facility for communicating app context to the session similar to Sybase's set_appcontext?

Details:

One specific practical use of app context is when you have an application with middle tier connecting to the database as a very specific generic database user (examples include "webuser"/"http" for a web app back-end running on web server or "myappserver" user for an app server).

When that happens, we still want for the database session to know who the END user (e.g. actual user using the app client) is, either for access control or (more relevant to my interest), for an audit/history trigger to be able to determine which end user made the change and log that end user info into an audit table.

Please note that the info is set at the session level, which means that any inserts/updates/deletes executed within that session are able to use the context data without it being passed to each individual SQL statement - this is VERY important for, say, a trigger.

As a very specific example of why it's useful, let's say you have an app server starting a DB session on behalf of a client within which you insert/update/delete rows in 5 distinct tables. You want to have audit tables for each of those 5 tables, which include "which end user made each change" info.

Using context data, you can simply retrieve "end user" data from app context using the trigger and stored it as part of Audit table record. Without using the app context, your will need to (1) Add "end user" column to every one of those 5 tables (instead of to only audit tables) and (2) Change your app server to insert or set-on-update the value of that column in EVERY SQL statement that the app server issues. Oh, and this doesn't even get into how this can be done if you're deleting a row.

回答1:

Oracle has a couple of different ways of accomplishing this. First off, you have the DBMS_APPLICATION_INFO package. Although you can use this to set arbitrary context information, it is generally used for tracing an application. You would normally set the module to be the name of the application and the action to be a description of the particular business process. You can then reference this information from V$SESSION and monitor long-running operations via V$SESSION_LONGOPS.

Oracle also has the ability to create a database object called a context. This is a more flexible way to populate session-level context. You can create a new context and then create whatever attributes you'd like within that context. And all of your code can simply reference the context. For example

SQL> create context my_ctx
  2    using pkg_ctx;

Context created.

SQL> create package pkg_ctx
  2  as
  3    procedure set_context;
  4  end;
  5  /

Package created.

SQL> create or replace package body pkg_ctx
  2  as
  3    procedure set_context
  4    as
  5    begin
  6      dbms_session.set_context( 'MY_CTX', 'USERNAME', 'Justin Cave' );
  7    end;
  8  end;
  9  /

Package body created.

SQL> exec pkg_ctx.set_context;

PL/SQL procedure successfully completed.

SQL> select sys_context( 'MY_CTX', 'USERNAME' )
  2    from dual;

SYS_CONTEXT('MY_CTX','USERNAME')
-------------------------------------------------------------------------------
Justin Cave


回答2:

For PostgreSQL you can create a custom variable class which is a configuration setting in postgresql.conf. Something like this:

custom_variable_classes = 'myvars'

(Setting this requires a server restart if I'm not mistaken)

Now from through SQL you can read and write this in the following way:

set myvars.some_flag = 'true';
select current_setting('myvars.some_flag');

Note that you can "dynamically" defined new "variables" that are all prefixed with myvars. The individual values do not need to be declard in postgresql.conf

Originally this was intended for add-on modules to allow the definition of custom configuration options so it it a slight abuse of the feature but it should work nevertheless.