暂无图片
暂无图片
11
暂无图片
暂无图片
3
暂无图片

"颗粒度"没对齐——让人费解的CHAR(1)

原创 小满未满、 2024-06-17
3529

本文为新专栏《那些让人感到"匪夷所思"或者说是让人摸不着头脑的Oracle"特色"设计》第一篇文章,

旨在分享和吐槽,作为羲和(Halo)数据库内核研发在实现Oracle兼容的时候,碰见过的奇奇怪怪的Oracle"特色"。

今天的主题是《"颗粒度"没对齐——让人费解的CHAR(1)类型》。

看到今天的主题,可能有不少的朋友会吐槽一个Oracle的CHAR(1)类型有什么让人费解的这不是简简单单吗?而且CHAR(1)在各个数据库中也都支持的呀?

我想说的是大伙,别着急咱们接下来慢慢看。

一、ORACLE——PL/SQL中CHAR(1)的表现

开门见题,还是以一个例子开头,如果是执行如下的匿名块,Oracle的输出结果是什么呢?

DECLARE
 col1 CHAR(1);
 BEGIN
 col1 := '';
 DBMS_OUTPUT.PUT_LINE('Length :'||TO_CHAR(LENGTH(col1)));
 IF (col1 IS NULL) THEN
 dbms_output.put_line('Treated as NULL');
 END IF;
 IF (col1 = '') THEN
 dbms_output.put_line('Treated as EMPTY STRING');
 END IF;
 IF (col1 = ' ') THEN
 dbms_output.put_line('Treated as space');
 END IF;
 END;
/
复制

整个匿名块其实非常简单,就是定义了一个名为col1的变量,且变量类型为CHAR(1),接下来被赋值成了 '' ,输出一下当前的长度,接下来就是几个简单的判断,最后输出对应的字符串。建议思考一会…

如果看到这的话,估计有同学会说,所见即所得嘛,既然变量col1被赋值成了'',那么符合col1 = ''这一条件,最后应该输出’Treated as EMPTY STRING’才对。

如果是对Oracle的SQL比较了解的同学,可能会给出col1变量符合 IS NULL的条件,最终应该会输出’Treated as NULL’。

那么最终到底结果如何呢?接下来给出运行结果

可以看到的是最终输出长度为一,最终结果’Treated as space’。

这时候有的同学可能想说:“我先不纠结为什么最后结果是这样的,你刚刚是不是说了‘对Oracle的SQL比较了解’,难道说在SQL层面还有新的花样?”。

接下来咱们来看看Oracle的SQL层面对类型为CHAR(1)的表现。

二、ORACLE——SQL中CHAR(1)的表现

那么当存在一个字段,字段类型为CHAR(1),插入字段值为 '' ,这个时候到底实际的数据值到底是什么呢?

以如下SQL进行测试:

CREATE TABLE ta(col1 CHAR(1));
INSERT INTO ta VALUES(''); 
SELECT 1,col1 FROM ta WHERE col1 IS NULL;
SELECT 1,col1 FROM ta WHERE col1 = '';
SELECT 1,col1 FROM ta WHERE col1 = ' ';
复制

创建一张名为ta的表,表中有一名为col1的字段,字段类型为CHAR(1),插入一条 '' 数据,接下来使用三条SELECT分别去判断此时col1到底为何值?

建议大家再思考一会…

最终运行结果如下所示:

可以看到的是,最终判定col1不为 '' ,也不为 ' '(空格),而是NULL。

可以看到的是,对于CHAR(1)这个同样的类型,同样的输入值,但是最终的输出,在Oracle的SQL层面和PL/SQL层面完全不一致。

至于这到底算不算是Oracle的bug,就交由诸君定夺。

不过我合理怀疑Oracle数据库研发存在多个团队,SQL层面有一个团队,PL/SQL层面也存在一个团队,

两个团队同时进行研发,两个团队中对于部分重合的内容设计各有各的想法,比如说(CHAR(1)),就像经典的修桥问题,如果用行业黑话来讲就是“颗粒度没对齐”,

这也就是今天的主题 《研发团队"颗粒度"没对齐——让人费解的CHAR(1)类型》。

三、PostgreSQL中CHAR(1)的表现

前面也说到了其实不仅仅只有Oracle支持CHAR类型,那么这块再把PostgreSQL拉过来玩玩。以如下SQL进行测试,

首先是plpgsql

DO $$
DECLARE
 col1 CHAR(1);
 BEGIN
 col1 := '';
 raise notice 'Length : %', LENGTH(col1);
 IF (col1 IS NULL) THEN
 raise notice 'Treated as NULL';
 END IF;
 IF (col1 = '') THEN
 raise notice 'Treated as EMPTY STRING';
 END IF;
 IF (col1 = ' ') THEN
 raise notice 'Treated as space';
 END IF;
 END;
$$ language plpgsql;
复制

运行结果

接下来是相同的SQL测试

CREATE TABLE ta(col1 CHAR(1));
INSERT INTO ta VALUES(''); 
SELECT 1,col1 FROM ta WHERE col1 IS NULL;
SELECT 1,col1 FROM ta WHERE col1 = '';
SELECT 1,col1 FROM ta WHERE col1 = ' ';
复制

运行结果:

可以看到的是,在PostgreSQL中如果类型为CHAR(1),且输入时 '' ,那么实际进行匹配的时候,既可以是所见即所得的 '',也可以是 ' '(空格)。

而对于PostgreSQL而言,不管是PL/SQL层面还是SQL层面,它的输出都是一致的,没有割裂的感觉。这是因为PostgreSQL的PL/SQL引擎其实是在原本SQL引擎的基础上实现的。

四、羲和(Halo)数据库

都讲到这了,拉上我们的数据库玩玩。对于羲和(Halo)数据库而言,则是要分模式来测试了。

比如说羲和数据库(PG模式)运行结果如下:

可以看到的是,和PostgreSQL输出结果一致。

接下来是羲和数据库(Oracle模式)运行结果如下:

可以看到的对于羲和数据库Oracle模式而言,对于CHAR(1)类型,如论在何种场景之下,保证了和SQL场景下的输出结果一致。

而对于其他类型比如说VARCHAR2(1)等没有任何歧义的,我们的最终输出结果与Oracle一致.

如下所示:

 

 

五、声明

本文为此系列第一篇,如想看到对Oracle功能的吐槽,敬请期待期待。

若文中存在错误或不当之处,敬请指出,以便我进行修正和完善。希望这篇文章能够帮助到各位。

文章转载请联系,谢谢合作。

欢迎大家加入羲和(Halo)产品吐槽群

最后修改时间:2024-06-18 11:47:10
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论

Great.Li
暂无图片
9月前
评论
暂无图片 0
认真做产品吧,别老是纠着别人的小辩子说事。 国产数据库一萝框,根基无非是MYSQL,PG, 真是可悲可叹!!!
9月前
暂无图片 点赞
1
小满未满、
暂无图片
9月前
回复
暂无图片 1
说得好!!!但是和本篇文章没有半毛钱关系。其实也正是因为认真做产品,所以才能发现一些奇奇怪怪的用法,本意是给大家找点乐子,同时增加大家的理解,让大家知道还能这麽玩。不知道怎么的到您这就成纠着别人小辫子说事了。顺带向您这位数据库大神问一嘴: "您为国产数据库又做了什么贡献呢?"
9月前
暂无图片 1
回复
锁钥
暂无图片
9月前
评论
暂无图片 0
在Oracle的SQL层面和PL/SQL层面对CHAR(1)的处理完全不一致
9月前
暂无图片 点赞
评论