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,恳请告知问题所在及解决方法。
问题原因及解决方法
问题原因
- 定义者权限执行上下文:存储过程创建在SYS用户下,默认以**定义者权限(DEFINER RIGHTS)**执行,即存储过程会以SYS的身份访问v$session视图。而v$session的
schemaname字段在会话初始化早期,SYS上下文查询时会返回当前执行身份(SYS),而非登录用户的默认schema。 - 动态视图过滤逻辑: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
相关产品推荐
相关产品推荐

