Oracle:如何在已连接的SYS会话中修改USER变量?
在SYS会话中解决第三方代码依赖USER变量的问题
核心结论
无法在已连接的SYS会话中修改USER变量的值。USER是Oracle内置的只读函数,返回当前会话的登录用户,这个值在会话建立后就固定了。ALTER SESSION SET CURRENT_SCHEMA仅改变对象解析的默认模式,不会影响USER的返回结果。
可行解决方案
1. 创建定义者权限的存储过程
通过创建以第三方模式为定义者的存储过程,让SYS调用时以该模式身份执行代码,此时USER变量会返回第三方模式名称。
- 步骤1:以第三方模式(如
APP_USER)登录,创建存储过程:
CREATE OR REPLACE PROCEDURE app_user.run_dependent_code AUTHID DEFINER -- 执行时使用存储过程定义者的身份 IS BEGIN -- 插入第三方应用的代码逻辑,例如: INSERT INTO some_table VALUES (USER, SYSDATE); -- 其他第三方代码... END; /
- 步骤2:给SYS授予该存储过程的执行权限:
GRANT EXECUTE ON app_user.run_dependent_code TO sys;
- 步骤3:在SYS会话中调用存储过程:
EXEC app_user.run_dependent_code;
2. 使用代理用户连接(可选,需提前配置)
如果允许切换会话,可以通过代理用户方式,从SYS会话直接切换到第三方模式,无需输入密码:
- 提前授权SYS作为第三方模式的代理用户:
ALTER USER app_user GRANT CONNECT THROUGH sys;
- 在SYS会话中切换到第三方模式:
CONNECT sys[app_user]/sys密码@数据库实例;
此时会话的USER变量会变为APP_USER,但原SYS会话会被终止,新会话以APP_USER身份运行。
3. 使用DBMS_SCHEDULER以目标用户身份执行
创建一个以第三方模式为所有者的定时任务,立即执行代码,执行时USER为目标模式:
BEGIN DBMS_SCHEDULER.CREATE_JOB( job_name => 'SYS.RUN_APP_JOB', job_type => 'PLSQL_BLOCK', job_action => 'BEGIN /* 第三方代码逻辑 */ DBMS_OUTPUT.PUT_LINE(USER); END;', start_date => SYSTIMESTAMP, enabled => TRUE, auto_drop => TRUE, job_class => 'DEFAULT_JOB_CLASS', comments => '以APP_USER身份执行代码' ); DBMS_SCHEDULER.SET_ATTRIBUTE('SYS.RUN_APP_JOB', 'LOGGING_LEVEL', DBMS_SCHEDULER.LOGGING_OFF); END; /
注意:需要确保SYS有创建任务的权限,且任务执行时的权限足够。
内容的提问来源于stack exchange,提问作者bernhard.weingartner
相关产品推荐
相关产品推荐

