[LightDB兼容增强]支持'\0'插入char(1)

支持的版本:自LightDB 23.3。

背景:
  在Oracle以及Mysql中,'\0'可以正常插入char(n)类型字符串中,然而PG内核对字符类型的处理均以'\0'作为结尾符处理,并且所有的输入字符都会在服务器端进行编码校验,当发现字符串中有'\0'字符的时候,直接认为字符串无效,并报错结束。
  因此'\0'在PG中并不是一个可以用来作为业务表达的字符值,比如chr(0), E'\0'均作错误处理,最终导致jdbc/libpq绑定变量也无法插入'\0'到char(n)中。
解决方案:  
  为解决此兼容问题,满足特定场景的需求,并尽最大可能性减少对原有的系统改造,LightDB针对JDBC以及Libpq绑定变量中'\0'插入char(n)类型字段作了特别的处理。
  LightDB引入了一个新的GUC参数,lightdb_ascii_zero_store_value, 此参数在创建数据库时指定,之后不能修改。如果此值非零,并且数据库模式为Oracle或者Mysql, 当插入字符'\0'的时候,我们会对‘\0’进行替换操作,如果插入'\0abc'或'abc\0'行为模式不受影响,为维持'\0'值在系统的行为一致,E'\0', CHR(0)的相应逻辑也作了更新。
 
练习:
1,创建数据库
  
create database oradb with lightdb_ascii_zero_store_value 20 lightdb_syntax_compatible_type 'oracle';

\c oradb

2,创建表,并插入数据

lightdb@oradb=# create table t00(a char(1), b char(2));
CREATE TABLE
lightdb@oradb=# insert into t00(a,b) values(E'\0',E'\0');
INSERT 0 1
lightdb@oradb=# insert into t00(a,b) values(chr(0),chr(0));
INSERT 0 1
lightdb@oradb=#
lightdb@oradb=# select * from t00;
  a   |   b
------+-------
 \x14 | \x14
 \x14 | \x14
(2 rows)

3,条件查询,更新,删除

lightdb@oradb=# select * from t00 where a=E'\0';
  a   |   b
------+-------
 \x14 | \x14
 \x14 | \x14
(2 rows)

lightdb@oradb=# UPDATE t00 SET b='a' where a=E'\0' LIMIT 1;
UPDATE 1
lightdb@oradb=# select * from t00;
  a   |   b
------+-------
 \x14 | \x14
 \x14 | a
(2 rows)

lightdb@oradb=# delete from t00 where a=E'\0';
DELETE 2
lightdb@oradb=# select * from t00;
 a | b
---+---
(0 rows)

4,若字符串长度超过2,或者模式不为Oracle,也不为Mysql, 或lightdb_ascii_zero_store_value为0,行为模式均维持与原生PG(13.8)一致。

 

lightdb@oradb=# insert into t00(a,b) values(E'\0a',E'a\0');
ERROR:  invalid byte sequence for encoding "UTF8": 0x00

lightdb@oradb=# create database dboff with lightdb_syntax_compatible_type 'off';
CREATE DATABASE

lightdb@oradb=# \c dboff;
You are now connected to database "dboff" as user "lightdb".
compatible type: postgresql
lightdb@dboff=# select E'\0';
ERROR:  invalid byte sequence for encoding "UTF8": 0x00
lightdb@dboff=# select chr(0);
ERROR:  null character not permitted

lightdb@dboff=# create database oradb2 with lightdb_syntax_compatible_type 'oracle' lightdb_ascii_zero_store_value 0;
NOTICE:  auto create user "oradb2" success
CREATE DATABASE
lightdb@dboff=# \c oradb2
You are now connected to database "oradb2" as user "lightdb".
compatible type: oracle
lightdb@oradb2=# select E'\0';
ERROR:  invalid byte sequence for encoding "UTF8": 0x00
lightdb@oradb2=# select CHR(0);
ERROR:  null character not permitted

 

5,JDBC, Libpq使用

  JDBC,Libpq在插入'\0'的时候,我们仅拦截并修改了文本类型的'\0'参数,如果绑定变量为'\0a'或'a\0'或为非文本类型,并不受此影响。

  在使用JDBC的绑定参数的时候,请确认传递的类型为文本类型(使用SetString)

  在使用Libpq的时候,请确定使用与LightDB匹配的Libpq版本,并且设置为文本类型相关参数,因为Libpq默认会因'\0'结尾的原因导致字符并不会发送到服务端,因此LightDB对应匹配的Libpq版本针对此情况专门做了修改。

6,其它注意事项

  1,lightdb_ascii_zero_store_value取值范围为[0,32], 默认值为0(为0时,行为不受影响),非oracle, mysql模式,行为不受影响。

  2,因为'\0'的值被替换,其它的行为也会受到影响,最终跟被替换的值保持一致。例如大小比较,取长度,拼接等接受字符为输入参数的函数。

  3,存储在表中的值为最终替换值,读行时,读到的值也是此存储值。业务中如果有需要做二次映射的,需要业务自己处理。

  4,此替换行为,目前只能在oracle, mysql模式下生效,创建业务数据库的时候,需要选择正确的模式。

  

  

 

 
 
posted on 2023-09-06 11:01  aodb  阅读(73)  评论(0编辑  收藏  举报