使用过Sybase开发的同学都知道,Sybase的空字符串并不空,而是占一个字节的空格(' ')。直接上Sybase官方文档:
Using the empty string
The empty string ("") or ('') is interpreted as a single blank in insert or assignment statements on varchar or univarchar data. In concatenation of varchar, char, nchar, nvarchar data, the empty string is interpreted as a single space; for following example is stored as “abc def”:
"abc" + "" + "def"
因为Sybase这个诡异的行为,导致在将Sybase数据库migrate到PostgreSQL时稍不留意,就会出问题。以下是我们项目组遇到的空字符串的案例汇总。
案例一:空字符串引发的自动化测试问题
首先看数据转换存在的问题。
Sybase中,当插入一个空字符串时,会被自动转换为一个空格(' ')。假设已存在表
CREATE TABLE hospital( code VARCHAR(10), name VARCHAR(255) )
执行:
INSERT INTO hospital VALUES('', 'HK')
Sybase会使用空格(' ')插入到表字段code中。
当使用自动化工具将hospital表数据迁移到PG时,自动化工具会认为Sybase中的空格' '是空字符串,于是往PG数据表插入一条code为空字符串的记录。
理论上,这是没有问题的。但我们在编写自动化比对脚本时,需要注意这一点,Sybase中的空格(' ')等于PG中的空字符串(''),否则就会产生误报。
案例二:自动化转换工具对空字符串的处理问题
原Sybase SP代码:
SELECT * FROM hospital WHERE code = ''; -- 注意,这里是空字符串('')
以下是采用工具自动转换后的PG代码:
SELECT * FROM hospital WHERE code = ' '; -- 转换后,变成一个空格(' ')的字符串
这说明自动转换工具知道Sybase的空字符串('')不空,而是一个空格,因此转换后的代码自动使用空格替代。
但实际上这样转换是问题的。我们先查看Sybase的hospital表,发现插入的code为空字符串时,select出来的code确实变为一个空格(' ')。我们再看PG的hospital表,因为自动迁移工具知道在空格(' ')在Sybase中是空字符的意思,因此数据迁移到PG后,PG的hospital表中的记录就是空字符串,而不是空格(' ')。然后这行代码就崩溃了:
SELECT * FROM hospital WHERE code = ' ';
因为PG里select出来的code是空字符串(''),永远不会与空格(' ')相等!
那如何修复?当然是将PG的代码使用空字符串('')替代空格(' ')。
案例三:传入参数为空字符串引发的问题
再看一个SP的入参问题。遇到过一个类似下面的Sybase的SP:
CREATE PROCEDURE prc
@search_string VARCHAR(10)
AS SELECT * FROM hospital WHERE code LIKE '%' + @search_string + '%'
转换为PG的SP后,代码为:
CREATE OR REPLACE FUNCTION prc ( search_string VARCHAR(10) )
RETURNS SETOF hospital
AS $$
BEGIN
RETURN query SELECT * FROM hospital WHERE code LIKE '%'|| search_string || '%';
END;
$$
LANGUAGE PLPGSQL;
转换后的代码看起来没有错,执行也没报错。但其实转换后的SP行为已经与Sybase的不一样了!让我们使用空字符串作为参数分别调用一下这两个sp,就会发现Sybase的没有任何数据返回,而PG的则返回了所有记录。为何?因为在Sybase中,输入空字符串后,Sybase会解释为空格,因此SQL变为:
SELECT * FROM hospital WHERE code LIKE '% %'; -- 查带有空格的code,肯定查不到数据。
而PG呢,输入空字符串后,SQL就是
SELECT * FROM hospital WHERE code LIKE '%%'; -- 就是查询所有数据。
为了保证移植后的SP行为一致性,需要在PG的SP代码中将空字符串''转换成空格' '。
以上便是我们项目组看到过的由Sybase空字符串引发的问题汇总,现存档供大家分析参考。