DuckDB like查询Invalid unicode的问题原因分析和规避

有人在DuckDB微信群里提到一个奇怪的bug, 模糊查询绿字开头的行就会报错,我验证了一下确实存在

D create table t as select '绿色' a;
D from t where a like '绿';
┌─────────┐
│    a    │
│ varchar │
├─────────┤
│ 0 rows  │
└─────────┘
D from t where a like '绿%';
Invalid Input Error:
Invalid unicode (byte sequence mismatch) detected in value construction
D from t where a like '绿_%';
Invalid Input Error:
Invalid unicode (byte sequence mismatch) detected in value construction

而如果把绿字改成其他的字比如,就没有问题。
张泽鹏先生发现,这个问题与绿字的UTF8编码有关,他跟踪到代码发现DuckDB还要查绿字的UTF8编码E7BBBF+1的代码,而那个E7BBC0码不是有效的UTF8编码,同样情况的例子是弿字。
为什么查绿字,还要查编码比它大1的字,看like执行计划就知道了。

D create or replace table temp as select i::varchar n from range(10000000)t(i);

D explain analyze select sum(length(n)) from temp where n like '5%';
┌─────────────┴─────────────┐
│         TABLE_SCAN        │
│    ────────────────────   │
│        Table: temp        │
│   Type: Sequential Scan   │
│       Projections: n      │
│                           │
│          Filters:         │
│      n>='5' AND n<'6'     │
│                           │
│      11,111,111 rows      │
│          (0.24s)          │
└───────────────────────────┘

原来,优化器把like '5%'改写成了n>='5' AND n<'6', 后面多出来的’6’就是’5’的编码+1的结果。
知道了原理,规避方法也很简单
找一个UTF8编码非常大的,确认大于在表中绿字后面的最大字符的字符附在我们要查的代码后面就可以了。
在网上查到“在 UTF-8 编码中,中文字符的范围主要集中在 Unicode 的 \u4E00-\u9FA5 区间。这一范围涵盖了大部分常用汉字。此外,还有更广泛的范围 \u2E80-\u9FFF,包括了日韩汉字等扩展字符。”
那在绿字后面放一个unicode为9FFF的字符就好了。

from t where a >='绿_%' and a<='绿'||chr('0x9FFF'::int);
┌─────────┐
│    a    │
│ varchar │
├─────────┤
│ 绿色    │
└─────────┘
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值