环境函数 SYS_CONTEXT 在 DM8 与 Oracle 中的差异
在 Oracle 数据库中,SYS_CONTEXT(namespace, parameter)
函数用于返回当前数据库会话的环境信息,例如用户、主机、实例、语言、会话 ID 等。这一机制在数据库审计、安全控制、运维脚本中非常实用。而在国产数据库达梦(DM8)中,虽然官方文档中并未明确介绍该函数,但经实测发现该函数依然可用,且与 Oracle 高度兼容。
基本语法:
SELECT SYS_CONTEXT('USERENV', '<参数名>') FROM dual;
DM8 版本
DM官网没有找到关于SYS_CONTEXT函数的介绍,在v$ifun函数定义中是能找到的,根据这一周的学习情况来看,很多Oracle上的SQL在DM上依旧通用,下面就用ORACLE常用的 userenv namespace 在DM8上 测试一下
版本:DM Database Server 64 V8--03134284368-20250430-272000-20149 Pack1
dmdba@DAMENG:5236 SQL> select top 1 banner || id_code from v$version;BANNER||ID_CODE -----------------------------------------------------------------DM Database Server 64 V8--03134284368-20250430-272000-20149 Pack1dmdba@DAMENG:5236 SQL> @fun contextdmdba@DAMENG:5236 SQL> select name,class$ from v$ifun where name like upper('%&1%');old value 1:select name,class$ from v$ifun where name like upper('%&1%');new value 1:select name,class$ from v$ifun where name like upper('%context%');NAME CLASS$ ----------------- ----------------CONTEXT_INDEX_DEF system functionCONTEXTDEF context functionSYS_CONTEXT context functionSYS_CONTEXT context functionused time: 1.860(ms). Execute id is 19911.dmdba@DAMENG:5236 SQL> dmdba@DAMENG:5236 SQL> @p COMPATIBLE_MODEdmdba@DAMENG:5236 SQL> select para_name,para_value,DEFAULT_VALUE,SESS_VALUE,FILE_VALUE,para_type,DESCRIPTION from v$dm_ini where para_name like upper('%&1%');old value 1:select para_name,para_value,DEFAULT_VALUE,SESS_VALUE,FILE_VALUE,para_type,DESCRIPTION from v$dm_ini where para_name like upper('%&1%');new value 1:select para_name,para_value,DEFAULT_VALUE,SESS_VALUE,FILE_VALUE,para_type,DESCRIPTION from v$dm_ini where para_name like upper('%COMPATIBLE_MODE%');PARA_NAME PARA_VALUE DEFAULT_VALUE SESS_VALUE FILE_VALUE PARA_TYPE DESCRIPTION -------------------- ---------- ------------- ---------- ---------- --------- --------------------------------------------------------------------------------------------------------COMPATIBLE_MODE 0 0 0 0 IN FILE Server compatible mode, 0:none, 1:SQL92, 2:Oracle, 3:MS SQL Server, 4:MySQL, 5:DM6, 6:Teradata, 7:PGCASE_COMPATIBLE_MODE 1 1 1 1 SYS Case compatible mode, 0:none, 1:Oracle(simple case), 2:Oracle(simple case new rule), 4:Oracle(bool case)XA_COMPATIBLE_MODE 0 0 0 0 SYS XA compatible mode, 0:none, 1:Oracle, 2:MySqlused time: 13.766(ms). Execute id is 19912.
DM8 vs Oracle 支持差异
测试出DM8 SYS_CONTEXT namespace可以用的userenv有16项,可能还有一些自定义的没有介绍。
参数名 | 中文说明 | DM8可用性 |
CURRENT_SCHEMA | 当前模式名 | ✅(PANDA)⭐ |
CURRENT_SCHEMAID | 当前模式ID | ✅(150995947) |
CURRENT_USER | 当前用户名 | ✅(PANDA)⭐ |
CURRENT_USERID | 当前用户ID | ✅(50331752) |
SESSION_USER | 当前会话用户名 | ✅(PANDA) |
SESSION_USERID | 当前会话用户ID | ✅(50331752)⭐ |
DB_NAME | 数据库名 | ✅(DAMENG)⭐ |
INSTANCE_NAME | 实例名 | ✅(DMORCL)⭐ |
HOST | 客户端主机名 | ✅(panda101)⭐ |
SERVER_HOST | 实例运行主机名 | ✅(panda101) |
IP_ADDRESS | 客户端IP地址 | ✅(::ffff:192.168.66.101)⭐ |
ISDBA | 当前用户是否为DBA | ✅(TRUE) |
LANG | 语言简写(CN/EN) | ✅(EN) |
LANGUAGE | 语言及编码方式 | ✅(ENGLISH.UTF8) |
NETWORK_PROTOCOL | 通信协议类型 | ✅(TCP/IP) |
SESSIONID / SID | 当前会话标识符 | ✅(195075224) |
TERMINAL | 当前终端或计算机名 | ❌(NULL) |
INSTANCE | 实例号(Oracle专用) | ❌ |
ENTRYID | 审计会话标识符 | ❌ |
NLS_TERRITORY | 当前地区设置 | ❌ |
NLS_CURRENCY | 货币符号 | ❌ |
NLS_CALENDAR | 日历类型 | ❌ |
NLS_DATE_FORMAT | 日期格式 | ❌ |
NLS_DATE_LANGUAGE | 日期语言 | ❌ |
NLS_SORT | 排序规则 | ❌ |
PROXY_USER | 代理用户 | ❌ |
PROXY_USERID | 代理用户ID | ❌ |
DB_DOMAIN | 数据库域名 | ❌ |
OS_USER | 操作系统用户名 | ❌ |
EXTERNAL_NAME | 外部认证用户名 | ❌ |
BG_JOB_ID | 后台作业ID | ❌ |
FG_JOB_ID | 前台作业ID | ❌ |
AUTHENTICATION_TYPE | 用户认证方式 | ❌ |
AUTHENTICATION_DATA | 用户认证附加信息 | ❌ |
更多 Predefined Parameters of Namespace USERENV 参照Oracle官网:https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/SYS_CONTEXT.html
OB V3.2.4 SYS_CONTEXT函数:https://www.oceanbase.com/docs/enterprise-oceanbase-database-cn-10000000000948086
应用场景
常用的有CURRENT_USER、DB_NAME、INSTANCE_NAME、IP_ADDRESS、SESSIONID / SID,这些函数信息可以用来判断会话信息、区分判断生产测试环境、在SQL、存储过程、PL/SQL、Shell中判断会话信息。
使用场景1 - 区分生产与测试环境(防误操作)
比如现在一套核心的营业系统有生产和测试两套环境,如果没有进行堡垒机或者环境分离(用同一套设备就可以登陆两套环境),我们再进行一些测试变更前可以通过SYS_CONTEXT函数进行二次确认,比如测试环境数据库名字叫做bcvxxx、cs_xxx、test_xxx可以用DB_NAME、INSTANCE_NAME、IP_ADDRESS这些区分生产和测试,防止造成不可挽回的操作,尤其是删表、删库这个高危操作,一定要确认环境信息。
可以使用如下语句区分环境:
SELECT SYS_CONTEXT('USERENV','DB_NAME') AS db_name,SYS_CONTEXT('USERENV','INSTANCE_NAME') AS instance_name,SYS_CONTEXT('USERENV','IP_ADDRESS') AS ip_addr,SYS_CONTEXT('USERENV','HOST') AS client_hostFROM dual;DB_NAME INSTANCE_NAME IP_ADDR CLIENT_HOST------- ------------- ------------------- -----------DAMENG DMORCL ::ffff:192.168.66.101 LAPTOP-xxxxxxx
使用场景2 - 结合会话视图动态过滤
用项目上常用的一个脚本举例,kill会话,通过v$sessions获取会话排除本会话:
select 'sp_close_session('|| sess_id||');--'||USER_NAME || '@' || CLNT_HOST || ' (' || APPNAME || ');' commands_to_verify_and_runfrom v$sessionswhere &1and sess_id != (select SYS_CONTEXT('USERENV','SESSIONID'));
在定位到行锁阻塞源的sid后可以直接生成kill脚本,并杀掉会话,执行示例:
dmdba@DAMENG:5236 SQL> @kill sess_id='195075224'COMMANDS_TO_VERIFY_AND_RUN -----------------------------------------------------sp_close_session(195075224);--PANDA@panda101 (disql);used time: 4.766(ms). Execute id is 19914.dmdba@DAMENG:5236 SQL> sp_close_session(195075224);--PANDA@panda101 (disql);DMSQL executed successfullyused time: 4.502(ms). Execute id is 19915.
会话连接超限,有部分异常用户或者用户正在执行批量DML可以根据用户名、sql_id进行匹配,批量kill,DM是单进程多线程结构不支持LOCAL=NO在操作系统层面杀,所以批量kill会话还是有必要的。
@kill <filter expression>@kill seee_id=150@kill +seee_id|user_name|CLNT_HOST|APPNAME|sql_id@kill "event like '%lock%'"
当然这是一种思路,在编写存储过程或者脚本时没有想要的字段,结合动态视图做连接,比如写一个存储过程记录所有会话的连接信息,将登录用户、来源主机、客户端 IP,写入操作日志表,通过DDL触发器记录记录执行过的sql信息,执行用户、执行时间、主机、客户端 IP、操作系统用户等。
DM8 测试结果
NULL表示不支持。
panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','TERMINAL') terminal;TERMINAL--------NULLused time: 0.253(ms). Execute id is 19822.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','LANGUAGE') language;LANGUAGE ------------ENGLISH.UTF8used time: 0.218(ms). Execute id is 19823.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','SESSIONID') sessionid;SESSIONID---------195075224used time: 0.199(ms). Execute id is 19824.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','SID') sessionid;SESSIONID---------195075224used time: 3.490(ms). Execute id is 19825.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','INSTANCE') instance;INSTANCE--------NULLused time: 0.395(ms). Execute id is 19826.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','ENTRYID') entryid;ENTRYID-------NULLused time: 0.282(ms). Execute id is 19827.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','ISDBA') isdba;ISDBA-----TRUEused time: 0.262(ms). Execute id is 19828.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','NLS_TERRITORY') nls_territory;NLS_TERRITORY-------------NULLused time: 0.338(ms). Execute id is 19829.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','NLS_CURRENCY') nls_currency;NLS_CURRENCY------------NULLused time: 0.290(ms). Execute id is 19830.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','NLS_CALENDAR') nls_calendar;NLS_CALENDAR------------NULLused time: 0.308(ms). Execute id is 19831.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','NLS_DATE_FORMAT') nls_date_format;NLS_DATE_FORMAT---------------NULLused time: 0.236(ms). Execute id is 19832.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','NLS_DATE_LANGUAGE') nls_date_language;NLS_DATE_LANGUAGE-----------------NULLused time: 0.279(ms). Execute id is 19833.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','NLS_SORT') nls_sort;NLS_SORT--------NULLused time: 0.833(ms). Execute id is 19834.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','CURRENT_USER') current_user;CURRENT_USER------------PANDAused time: 0.692(ms). Execute id is 19835.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','CURRENT_USERID') current_userid;CURRENT_USERID--------------50331752used time: 0.608(ms). Execute id is 19836.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','SESSION_USER') session_user;SESSION_USER------------PANDAused time: 0.800(ms). Execute id is 19837.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','SESSION_USERID') session_userid;SESSION_USERID--------------50331752used time: 1.145(ms). Execute id is 19838.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','PROXY_USER') proxy_user;PROXY_USER----------NULLused time: 0.765(ms). Execute id is 19839.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','PROXY_USERID') proxy_userid;PROXY_USERID------------NULLused time: 1.241(ms). Execute id is 19840.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','DB_DOMAIN') db_domain;DB_DOMAIN---------NULLused time: 1.467(ms). Execute id is 19841.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','DB_NAME') db_name;DB_NAME-------DAMENGused time: 0.854(ms). Execute id is 19842.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','HOST') host;HOST --------panda101used time: 0.903(ms). Execute id is 19843.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','OS_USER') os_user;OS_USER-------NULLused time: 1.175(ms). Execute id is 19844.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','EXTERNAL_NAME') external_name;EXTERNAL_NAME-------------NULLused time: 2.050(ms). Execute id is 19845.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','IP_ADDRESS') ip_address;IP_ADDRESS----------::1used time: 1.110(ms). Execute id is 19846.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','NETWORK_PROTOCOL') network_protocol;NETWORK_PROTOCOL----------------TCP/IPused time: 1.765(ms). Execute id is 19847.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','BG_JOB_ID') bg_job_id;BG_JOB_ID---------NULLused time: 1.223(ms). Execute id is 19848.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','FG_JOB_ID') fg_job_id;FG_JOB_ID---------NULLused time: 1.382(ms). Execute id is 19849.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','AUTHENTICATION_TYPE') authentication_type;AUTHENTICATION_TYPE-------------------NULLused time: 18.972(ms). Execute id is 19850.panda@DAMENG:5236 SQL> select SYS_CONTEXT('USERENV','AUTHENTICATION_DATA') authentication_data;AUTHENTICATION_DATA-------------------NULLused time: 0.609(ms). Execute id is 19851.