You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Oracle登录触发器存储过程获取v$session schema名称异常问题

登录触发器存储过程获取v$session.schemaname错误问题

我正在构建一个由系统登录触发器触发的存储过程DB_AUDIT_LOGON,用于记录会话生命周期之外的v$session信息。该存储过程大部分功能正常,但在记录刚登录会话(未执行任何命令)的schemaname时,返回的是存储过程所在的SYS schema,而非v$session中显示的登录SCHEMA_A。

存储过程代码如下:

CREATE OR REPLACE PROCEDURE DB_AUDIT_LOGON (p_sessionid number)
IS
 
   v_sessionid       number;   
   v_sid             number;   
   v_serialno        number;   
   v_username        VARCHAR2 (128); 
   v_schemaname      VARCHAR2 (128); 
   v_osuser          VARCHAR2 (128); 
   v_machine         VARCHAR2 (64); 
   v_terminal        VARCHAR2 (30); 
   v_program         VARCHAR2 (48); 
   v_logon           DATE; 
   v_clientid        VARCHAR2 (64); 
   v_authid          VARCHAR2 (128); 
   v_authmethod      VARCHAR2 (128);
   v_curruser        VARCHAR2 (128);
   v_proxyuser       VARCHAR2 (128);
   v_authtyp         VARCHAR2 (26);
   v_clientdrv       VARCHAR2 (30);
   v_clientver       VARCHAR2 (40);
  
BEGIN

-- Collection of userenv session variables

v_sessionid := p_sessionid;
v_authid := sys_context('USERENV', 'AUTHENTICATED_IDENTITY');
v_authmethod := sys_context('USERENV', 'AUTHENTICATION_METHOD');
v_curruser := sys_context('USERENV', 'CURRENT_USER');
v_proxyuser := sys_context('USERENV', 'PROXY_USER');

-- Collection of all information from v$session

select 
    sid,
    serial#,
    username,
    schemaname,
    osuser,
    machine,
    terminal,
    program,
    logon_time,
    client_identifier
into 
    v_sid,
    v_serialno,
    v_username,
    v_schemaname,
    v_osuser,
    v_machine,
    v_terminal,
    v_program,
    v_logon,
    v_clientid
from v$session where audsid = v_sessionid;

-- Collection of v$session_connect_info variables

select
    unique(authentication_type)
into
    v_authtyp
from v$session_connect_info
where sid = v_sid and serial# = v_serialno;    
    
select    
    unique(client_driver)
into    
    v_clientdrv
from v$session_connect_info
where sid = v_sid and serial# = v_serialno;

select
    unique(client_version)
into
    v_clientver
from v$session_connect_info
where sid = v_sid and serial# = v_serialno;

-- Insertion of collected session information into 
-- DB_AUDIT_LOG

insert into DB_AUDIT_LOG
(
    sessionid,
    sid,
    serialno,
    username,
    schemaname,
    osuser,
    machine,
    terminal,
    program,
    logon_time,
    client_identifier,
    authenticated_identity,
    authentication_method,
    current_user,
    proxy_user,
    authentication_type,
    client_driver,
    client_version)
values
(
    v_sessionid,
    v_sid,
    v_serialno,
    v_username,
    v_schemaname,
    v_osuser,
    v_machine,
    v_terminal,
    v_program,
    v_logon,
    v_clientid,
    v_authid,
    v_authmethod,
    v_curruser,
    v_proxyuser,
    v_authtyp,
    v_clientdrv,
    v_clientver);

END;
/

我使用的是Oracle 19C,存储过程位于SYS下,因授权v_$session和v_$session_connect_info查询权限时遇到复杂问题才放在此处。直接执行select * from v$session;能得到正确的SCHEMA_A,但存储过程中始终返回SYS,恳请告知问题所在及解决方法。


问题原因及解决方法

问题原因

  1. 定义者权限执行上下文:存储过程创建在SYS用户下,默认以**定义者权限(DEFINER RIGHTS)**执行,即存储过程会以SYS的身份访问v$session视图。而v$session的schemaname字段在会话初始化早期,SYS上下文查询时会返回当前执行身份(SYS),而非登录用户的默认schema。
  2. 动态视图过滤逻辑:v$session是v_$session的同义词,带有权限过滤逻辑。SYS用户查询时,会话刚建立的阶段,用户schema切换动作尚未完全完成,视图返回的schemaname未同步到真实登录用户的信息。

解决方法

方法1:改为调用者权限执行

在存储过程定义中添加AUTHID CURRENT_USER子句,让存储过程以登录用户的身份执行,这样查询v$session时就能获取到正确的用户schema信息。

修改后的存储过程开头:

CREATE OR REPLACE PROCEDURE DB_AUDIT_LOGON (p_sessionid number)
AUTHID CURRENT_USER
IS
-- 原变量定义和逻辑保持不变
...

同时需要给登录用户授权查询权限:

GRANT SELECT ON v_$session TO SCHEMA_A; -- 替换为目标用户或角色
GRANT SELECT ON v_$session_connect_info TO SCHEMA_A;

方法2:查询底层原始视图v_$session_raw

v_$session_raw是未经过过滤的底层会话视图,能在会话早期获取到真实的用户schema信息。将v$session的查询替换为v_$session_raw:

select 
    sid,
    serial#,
    username,
    schemaname,
    osuser,
    machine,
    terminal,
    program,
    logon_time,
    client_identifier
into 
    v_sid,
    v_serialno,
    v_username,
    v_schemaname,
    v_osuser,
    v_machine,
    v_terminal,
    v_program,
    v_logon,
    v_clientid
from v_$session_raw where audsid = v_sessionid;

方法3:直接通过SYS_CONTEXT获取默认schema

使用SYS_CONTEXT('USERENV', 'DEFAULT_SCHEMA')可以直接获取登录用户的默认schema,该值在会话建立时就已确定,不受执行上下文影响:

-- 替换从v$session获取schemaname的逻辑,直接赋值
v_schemaname := sys_context('USERENV', 'DEFAULT_SCHEMA');

内容的提问来源于stack exchange,提问作者SeanGaff

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 06:25:21