Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion CN/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@
**** xref:master/6.3.2.adoc[OUT 参数]
**** xref:master/6.3.4.adoc[%TYPE、%ROWTYPE]
**** xref:master/6.3.5.adoc[NLS 参数]
*** xref:master/6.4.adoc[国标GB18030]
*** 内置函数
**** xref:master/6.4.1.adoc[sys_context]
**** xref:master/6.4.2.adoc[userenv]
*** xref:master/6.5.adoc[国标GB18030]
** Oracle兼容功能列表
*** xref:master/7.1.adoc[1、框架设计]
*** xref:master/7.2.adoc[2、GUC框架]
Expand Down
88 changes: 88 additions & 0 deletions CN/modules/ROOT/pages/master/6.4.1.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@

:sectnums:
:sectnumlevels: 5


= **功能概述**

IvorySQL提供兼容Oracle内置函数`SYS_CONTEXT('namespace', 'parameter' [, length ])`,
返回当前时刻与给定上下文关联参数的值,可以在SQL和PLSQL语言中使用。

== 实现原理

SYS_CONTEXT的实现原理是通过动态查询系统表与postgres的内置函数,确保结果的实时性,
使用 SECURITY INVOKER 确保函数以调用者的权限执行,避免权限提升问题。
该方法的实现逻辑如下:
```sql
CREATE OR REPLACE FUNCTION sys.sys_context(a varchar2, b varchar2)
RETURNS varchar2 AS $$
DECLARE
res varchar2;
BEGIN
IF upper(a) = 'USERENV' THEN
CASE upper(b)
WHEN 'CURRENT_SCHEMA' THEN
SELECT current_schema() INTO res;
WHEN 'LANG' THEN
SELECT sys.get_lang() INTO res;
...
ELSE
RAISE EXCEPTION 'invalid USERENV parameter: %', b;
END CASE;
ELSIF upper(a) = 'SYS_SESSION_ROLES' THEN
CASE upper(b)
WHEN 'LOGIN' THEN
SELECT CASE WHEN rolcanlogin = 't' THEN 'TRUE' ELSE 'FALSE' END INTO res FROM pg_roles WHERE oid = current_user::regrole::oid;
...
ELSE
RAISE EXCEPTION 'invalid SYS_SESSION_ROLES parameter: %', b;
END CASE;
ELSE
SELECT current_setting(a||'.'||b, true) INTO res;
END IF;
RETURN res;
END;
$$ LANGUAGE plisql SECURITY INVOKER;
```
== USERENV支持的参数
[cols="2,8"]
|====
|*参数名称*|*返回值*
|CURRENT_SCHEMA | 当前活动默认模式的名称。在会话期间,可以通过 ALTER SESSION SET CURRENT_SCHEMA 语句更改该值。该值也可能在会话期间发生变化,以反映任何活动定义者权限对象的所有者。如果直接在视图定义的正文中使用,那么将返回在执行使用视图的游标时使用的默认模式。
|CURRENT_SCHEMAID | 当前活动的默认模式的标识符。
|SESSION_USER | 当前session的用户
会话用户(登录用户)的名称。在数据库会话期间,随着 Real Application Security 会话的附加或分离,该名称可能会发生变化。对于企业用户,返回模式。对于其他用户,返回数据库用户名。如果数据库会话当前附加了 Real Application Security 会话,则返回用户 XS$NULL。
|SESSION_USERID | 当前session的用户ID。
|PROXY_USER | 代表 SESSION_USER 打开当前会话的数据库用户名称。
|PROXY_USERID | 代表 SESSION_USER 打开当前会话的数据库用户的标识符。
|CURRENT_USER | 当前会话中执行操作的用户。
|CURRENT_USERID | 当前会话中执行操作的用户标识符。
|CURRENT_EDITION_NAME | 当前版本的名字。
|CLIENT_PROGRAM_NAME | 客户端程序的名称。
|====
[cols="2,8"]
|====
|*参数名称*|*返回值*
|IP_ADDRESS | 客户端的IP地址。
|HOST | 客户端主机的名称。
|ISDBA | 如果当前用户是数据库管理员,则返回TRUE。
|LANG | 语言的缩写名称,比现有的 “LANGUAGE ”参数更简短。
|LANGUAGE | 当前会话的使用的语言和地区,以及数据库字符集,格式为:language_territory.characterset。
|NLS_DATE_FORMAT | 当前session的日期格式。
|PLATFORM_SLASH | 在用户的平台上用作文件路径分隔符的斜线字符(Unix或Linux是’/’,Windows是’\’)。
|DB_NAME | 当前连接的CDB的名称。
|SID | 当前会话的系统标识符。
|SESSIONID | 审计会话标识符。不能在分布式 SQL 语句中使用此属性。
|CLIENT_INFO | 返回最多 64 字节的用户会话信息,应用程序可使用 DBMS_APPLICATION_INFO 包存储这些信息。
|ENTRYID | 当前审计条目编号。审计条目编号序列在细粒度审计记录和常规审计记录之间共享。不能在分布式 SQL 语句中使用此属性。只有通过标准或细粒度审计的审计处理程序才能看到正确的审计条目标识符。
|TERMINAL | 当前会话客户端的操作系统标识符。在分布式 SQL 语句中,该属性返回本地会话的标识符。在分布式环境中,仅支持远程 SELECT 语句,不支持远程 INSERT、UPDATE 或 DELETE 操作。(此参数的返回长度可能因操作系统而异)。
|====
== SYS_SESSION_ROLES支持的参数
[cols="2,8"]
|====
|*参数名称*|*返回值*
|DBA | 如果当前用户是数据库管理员,则返回TRUE。
|LOGIN | 如果当前用户是登录角色,则返回TRUE。
|CREATEROLE | 如果当前session的用户具有创建角色的权限,则返回TRUE。
|CREATEDB | 如果当前session的用户具有创建数据库的权限,则返回TRUE。
|====
57 changes: 57 additions & 0 deletions CN/modules/ROOT/pages/master/6.4.2.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

:sectnums:
:sectnumlevels: 5


= **功能概述**

IvorySQL提供兼容Oracle内置函数`USERENV('parameter')`,用于返回当前会话的相关信息。
这是一个遗留函数,建议使用 SYS_CONTEXT 函数及其内置的 USERENV 命名空间来获取当前功能。

== 实现原理

`USERENV` 通过Bison规则解析函数调用,检查参数合法性并映射到对应的具体SQL函数。
解析规则在 `ora_gram.y` 中实现,逻辑如下:
```c
USERENV '(' Sconst ')'
{
char *normalized_param = downcase_identifier($3, strlen($3), true, true);

#define CHECK_AND_CALL(param, func_name) \
if (strcmp(normalized_param, param) == 0) \
$$ = (Node *) makeFuncCall(OracleSystemFuncName(func_name), NIL, COERCE_EXPLICIT_CALL, @1);

CHECK_AND_CALL("client_info", "get_client_info")
else CHECK_AND_CALL("entryid", "get_entryid")
else CHECK_AND_CALL("terminal", "get_terminal")
else CHECK_AND_CALL("isdba", "get_isdba")
else CHECK_AND_CALL("lang", "get_lang")
else CHECK_AND_CALL("language", "get_language")
else CHECK_AND_CALL("sessionid", "get_sessionid")
else CHECK_AND_CALL("sid", "get_sid")
else
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("invalid USERENV parameter: \"%s\".", $3)));
#undef CHECK_AND_CALL
}
```
具体功能则是在 `builtin_functions--1.0.sql` 中实现。例如:
```sql
CREATE OR REPLACE FUNCTION sys.get_language()
RETURNS varchar2
AS $$
SELECT (regexp_split_to_array(current_setting('lc_monetary'), '\.'))[1]||'.'||pg_client_encoding();
$$ LANGUAGE sql STRICT;
```

== USERENV支持的参数
[cols="2,8"]
|====
|*参数名称*|*返回值*
|sid | 当前session的用户ID。
|sessionid | 返回审计会话标识符。
|language | 返回数据库当前会话的语言、地域和字符集。
|lang | 返回ISO缩写语言名称。
|isdba | 如果用户已经被认证为管理员;或者是通过操作系统或口令文件具有管理员特权的,返回“TRUE",否则返回"FALSE"。
|====
Loading