Skip to content

Commit 6347a79

Browse files
authored
Merge pull request #171 from OreoYang/master
Add NLS paramters docs
2 parents b60867a + e23ff22 commit 6347a79

File tree

7 files changed

+562
-0
lines changed

7 files changed

+562
-0
lines changed

.coderabbit.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
2+
# Minimal configuration for getting started
3+
# language: "zh-CN"
4+
language: "en-US"
5+
reviews:
6+
profile: "chill"
7+
high_level_summary: true
8+
auto_review:
9+
enabled: true
10+
drafts: false
11+
base_branches: ["master", "v5.0", "v4.6", "v1.17"]

CN/modules/ROOT/nav.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
**** xref:master/6.3.3.adoc[RowID]
2626
**** xref:master/6.3.2.adoc[OUT 参数]
2727
**** xref:master/6.3.4.adoc[%TYPE、%ROWTYPE]
28+
**** xref:master/6.3.5.adoc[NLS 参数]
2829
*** xref:master/6.4.adoc[国标GB18030]
2930
** Oracle兼容功能列表
3031
*** xref:master/7.1.adoc[1、框架设计]
@@ -43,6 +44,7 @@
4344
*** xref:master/7.14.adoc[14、RowID]
4445
*** xref:master/7.15.adoc[15、OUT 参数]
4546
*** xref:master/7.16.adoc[16、%TYPE、%ROWTYPE]
47+
*** xref:master/7.17.adoc[17、NLS 参数]
4648
** IvorySQL贡献指南
4749
*** xref:master/8.1.adoc[社区贡献指南]
4850
*** xref:master/8.2.adoc[asciidoc语法快速参考]
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
2+
:sectnums:
3+
:sectnumlevels: 5
4+
5+
6+
= **功能概述**
7+
8+
IvorySQL提供了兼容Oracle的NLS参数功能,包含如下参数。
9+
10+
[cols="3,7"]
11+
|====
12+
|*参数名称*|*功能描述*
13+
|ivorysql.datetime_ignore_nls_mask | 表示日期格式是否忽略NLS参数影响,默认为0。
14+
|nls_length_semantics | 兼容Oracle的同名参数,表示char/varchar/varchar2的类型修饰符的大小单位是字节还是字符。
15+
|nls_date_format | 表示默认的日期格式,可以通过show命令查看,默认为‘YYYY-MM-DD’。
16+
|nls_timestamp_format | 兼容Oracle的同名参数,控制带时间的日期格式。
17+
|nls_timestamp_tz_format | 兼容Oracle的同名参数,控制带时区的日期时间格式。
18+
|nls_territory | 兼容Oracle的同名参数,指定数据库的默认区域。
19+
|nls_iso_currency | 兼容Oracle的同名参数,指定的国家和区域制定唯一的货币符号。
20+
|nls_currency | 兼容Oracle的同名参数,指定显示本地货币的符号,对应数字字符串格式中占位符L。
21+
|====
22+
23+
== 实现原理
24+
25+
=== `nls_length_semantics` 参数
26+
27+
IvorySQL中的数据类型存在一个属性修饰符 `typmod` ,是对类型的补充说明,比如在 `VARCHAR(n)` 类型中,`n` 就是类型修饰符。
28+
29+
在创建或修改表的列时可以指定长度类型,例如:
30+
```c
31+
ivorysql=# create table t1(name varchar2(2 byte));
32+
```
33+
34+
对于列类型为 `CHAR` 、 `VARCHAR` 和 `VARCHAR2` 字符型的列,当没有显式指定列的长度类型时,IvorySQL使用 `nls_length_semantics` 参数的值来决定长度类型,有 `byte` 和 `char` 两种值,默认为 `byte` 。
35+
36+
需要特别注意的是, `nls_length_semantics` 参数的值仅影响新创建的列,对已经存在的列不会产生任何影响。
37+
38+
在语法解析文件 ora_gram.y中,存在如下代码来根据 `nls_length_semantics` 把原本的 `char/varchar/varchar2` 类型改成 `oracharchar` 或者 `oracharbyte` :
39+
40+
```c
41+
CharacterWithLength: character '(' Iconst ')'
42+
{
43+
if (ORA_PARSER == compatible_db)
44+
{
45+
if (strcmp($1, "bpchar"))
46+
{
47+
if (nls_length_semantics == NLS_LENGTH_CHAR)
48+
$1 = "oravarcharchar";
49+
else
50+
$1 = "oravarcharbyte";
51+
}
52+
else
53+
{
54+
if (nls_length_semantics == NLS_LENGTH_CHAR)
55+
$1 = "oracharchar";
56+
else
57+
$1 = "oracharbyte";
58+
}
59+
60+
$$ = OracleSystemTypeName($1);
61+
$$->typmods = list_make1(makeIntConst($3, @3));
62+
$$->location = @1;
63+
}
64+
else
65+
{
66+
...
67+
}
68+
}
69+
;
70+
71+
```
72+
73+
IvorySQL 中数据类型 `oracharchar` 和 `oracharbyte` 的修饰符输入输出函数包括:
74+
```c
75+
oravarcharchartypmodout()
76+
oravarcharbytetypmodout()
77+
oracharbytetypmodout()
78+
oracharchartypmodout()
79+
```
80+
81+
上面这些函数调用C语言实现的函数 `anychar_typmodout()` ,后者根据 `nls_length_semantics` 的值来调整输出的内容是否包含 `byte/char` 的说明。
82+
83+
`nls_length_semantics` 另一个作用是限制表中的列长度:
84+
根据上述代码在语法解析文件 ora_gram.y中,如果原本的 `varchar` 类型被转换成了 `oracharchar` 类型,则函数 `oravarcharchar()` 会被调用,而 `pg_mbcharcliplen()` 函数计算字符长度,而不是字节长度。
85+
86+
```c
87+
Datum
88+
oravarcharchar(PG_FUNCTION_ARGS)
89+
{
90+
VarChar *source = PG_GETARG_VARCHAR_PP(0);
91+
int32 typmod = PG_GETARG_INT32(1);
92+
bool isExplicit = PG_GETARG_BOOL(2);
93+
int32 len,
94+
maxlen;
95+
size_t maxmblen;
96+
char *s_data;
97+
98+
len = VARSIZE_ANY_EXHDR(source);
99+
s_data = VARDATA_ANY(source);
100+
maxlen = typmod - VARHDRSZ;
101+
102+
/* No work if typmod is invalid or supplied data fits it already */
103+
if (maxlen < 0 || len <= maxlen)
104+
PG_RETURN_VARCHAR_P(source);
105+
106+
maxmblen = pg_mbcharcliplen(s_data, len, maxlen);
107+
108+
...
109+
}
110+
```
111+
112+
=== GUC参数 `datetime_ignore_nls_mask`
113+
114+
这个参数被定义为一个int值,低四位分别表示是否在相应的日期时间格式上忽略NLS参数的影响,掩码定义如下:
115+
```c
116+
#define ORADATE_MASK 0x01
117+
#define ORATIMESTAMP_MASK 0x02
118+
#define ORATIMESTAMPTZ_MASK 0x04
119+
#define ORATIMESTAMPLTZ_MASK 0x08
120+
```
121+
122+
在源代码中,这个GUC参数被用于下面这些函数:
123+
```c
124+
oradate_in()
125+
oratimestamp_in()
126+
oratimestampltz_in()
127+
oratimestamptz_in()
128+
```
129+
130+
如果相应的掩码被设置,则调用原生PG的处理函数,否则调用兼容代码并忽略NLS格式。
131+
132+
=== GUC参数 `nls_date_format`/`nls_timestamp_format`/`nls_timestamp_tz_format`
133+
134+
这三个GUC参数,在函数 `ora_do_to_timestamp()` 中做为格式字符串,对输入的字符串进行格式检查与模式识别。
135+
136+
下面是其默认值,可以通过设置其值为"pg"使其失效。"pg"表示禁用NLS特定行为,恢复为PostgreSQL的默认行为。
137+
```c
138+
char *nls_date_format = "YYYY-MM-DD";
139+
char *nls_timestamp_format = "YYYY-MM-DD HH24:MI:SS.FF6";
140+
char *nls_timestamp_tz_format = "YYYY-MM-DD HH24:MI:SS.FF6 TZH:TZM";
141+
```
142+
143+
=== GUC参数 `nls_currency`/`nls_iso_currency`/`nls_territory`
144+
145+
目前,`nls_territory` 和 `nls_iso_currency` 支持CHINA与AMERICA两个值。
146+
147+
默认值如下:
148+
149+
```c
150+
char *nls_territory = "AMERICA";
151+
char *nls_currency = "$";
152+
char *nls_iso_currency = "AMERICA";
153+
```
154+
155+
这三个参数将在oracle兼容函数 `to_number()` 中被使用。
156+
[NOTE]
157+
====
158+
`to_number()` 函数尚未实现。
159+
====
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
:sectnums:
2+
:sectnumlevels: 5
3+
4+
:imagesdir: ./_images
5+
6+
= NLS 参数
7+
8+
== 目的
9+
10+
NLS 是 National Language Support(国家语言支持)的缩写,指的是 Oracle 提供的本地化支持功能。
11+
12+
IvorySQL提供兼容Oracle的NLS参数功能。
13+
14+
== 功能说明
15+
16+
包含如下参数:
17+
18+
[cols="3,7"]
19+
|====
20+
|*参数名称*|*功能描述*
21+
|ivorysql.datetime_ignore_nls_mask | 表示日期格式是否忽略NLS参数影响,默认为0。
22+
|nls_length_semantics | 兼容Oracle的同名参数,表示char/varchar/varchar2的类型修饰符的大小单位是字节还是字符。
23+
|nls_date_format | 表示默认的日期格式,可以通过show命令查看,默认为‘YYYY-MM-DD’。
24+
|nls_timestamp_format | 兼容Oracle的同名参数,控制带时间的日期格式。
25+
|nls_timestamp_tz_format | 兼容Oracle的同名参数,控制带时区的日期时间格式。
26+
|nls_territory | 兼容Oracle的同名参数,指定数据库的默认区域。
27+
|nls_iso_currency | 兼容Oracle的同名参数,指定的国家和区域制定唯一的货币符号。
28+
|nls_currency | 兼容Oracle的同名参数,指定显示本地货币的符号,对应数字字符串格式中占位符L。
29+
|====
30+
31+
=== NLS 日期掩码设置
32+
示例:
33+
```sql
34+
ivorysql=# set ivorysql.datetime_ignore_nls_mask = 0;
35+
SET
36+
ivorysql=# select '2025-10-15 11:00:00.102030 CST'::oratimestamp ;
37+
ERROR: datetime format picture ends before converting entire input string
38+
LINE 1: select '2025-10-15 11:00:00.102030 CST'::oratimestamp ;
39+
^
40+
ivorysql=# set ivorysql.datetime_ignore_nls_mask = 2;
41+
SET
42+
ivorysql=# select '2025-10-15 11:00:00.102030 CST'::oratimestamp ;
43+
oratimestamp
44+
----------------------------
45+
2025-10-15 11:00:00.102030
46+
(1 row)
47+
```
48+
49+
=== 禁用NLS日期/时间戳参数
50+
示例:
51+
```sql
52+
ivorysql=# select '2025-10-15 11:00:00.102030 '::oratimestamp ;
53+
oratimestamp
54+
----------------------------
55+
2025-10-15 11:00:00.102030
56+
(1 row)
57+
58+
ivorysql=# set nls_timestamp_format="pg";
59+
SET
60+
ivorysql=# select '2025-10-15 11:00:00.102030 '::oratimestamp ;
61+
ERROR: date format not recognized
62+
LINE 1: select '2025-10-15 11:00:00.102030 '::oratimestamp ;
63+
^
64+
```
65+
=== 设置nls_length_semantics
66+
IvorySQL使用nls_length_semantics参数的值来决定长度类型,有byte和char两种值,默认为byte。
67+
示例:
68+
```sql
69+
vorysql=# alter session set nls_length_semantics = char;
70+
SET
71+
ivorysql=# create table character_tb(char_c char(6), char_b varchar2(6 byte), char_v varchar(6));
72+
CREATE TABLE
73+
ivorysql=# insert into character_tb values('中文测试数据', '123456', '成功');
74+
INSERT 0 1
75+
ivorysql=# select * from character_tb ;
76+
char_c | char_b | char_v
77+
--------------+--------+--------
78+
中文测试数据 | 123456 | 成功
79+
(1 row)
80+
81+
ivorysql=# select length(char_b), length(char_c), length(char_v) from character_tb;
82+
length | length | length
83+
--------+--------+--------
84+
6 | 6 | 2
85+
(1 row)
86+
87+
```
88+
=== 设置NLS货币符号
89+
示例:
90+
```sql
91+
ivorysql=# show ivorysql.identifier_case_switch;
92+
ivorysql.identifier_case_switch
93+
---------------------------------
94+
interchange
95+
(1 row)
96+
97+
ivorysql=# set nls_currency to "CHINA";
98+
SET
99+
ivorysql=# show nls_currency;
100+
nls_currency
101+
--------------
102+
CHINA
103+
(1 row)
104+
105+
ivorysql=# set nls_currency to "China";
106+
SET
107+
ivorysql=# show nls_currency;
108+
nls_currency
109+
--------------
110+
China
111+
(1 row)
112+
```
113+
[NOTE]
114+
====
115+
nls_currency和nls_iso_currency的行为,受兼容oracle大小写特性 `identifier_case_switch` 影响
116+
====

EN/modules/ROOT/nav.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
*** xref:master/6.3.3.adoc[RowID]
2525
*** xref:master/6.3.2.adoc[OUT Parameter]
2626
*** xref:master/6.3.4.adoc[%Type & %Rowtype]
27+
*** xref:master/6.3.5.adoc[NLS Parameters]
2728
** xref:master/6.4.adoc[GB18030 Character Set]
2829
* List of Oracle compatible features
2930
** xref:master/7.1.adoc[1、Ivorysql frame design]
@@ -42,6 +43,7 @@
4243
** xref:master/7.14.adoc[14、RowID Column]
4344
** xref:master/7.15.adoc[15、OUT Parameter]
4445
** xref:master/7.16.adoc[16、%Type & %Rowtype]
46+
** xref:master/7.17.adoc[17、NLS Parameters]
4547
* xref:master/8.adoc[Community contribution]
4648
* xref:master/9.adoc[Tool Reference]
4749
* xref:master/10.adoc[FAQ]

0 commit comments

Comments
 (0)