SQL Server數(shù)據(jù)遷移至PostgreSQL出錯(cuò)的解釋以及解決方案
問題重現(xiàn):
1、PG客戶端:
postgres=# create table text_test (id int,info text); CREATE TABLE postgres=# insert into text_test values (1,E'\0x00'); ERROR: invalid byte sequence for encoding "UTF8": 0x00
2、SQL Server產(chǎn)生數(shù)據(jù)
create table test_varchar(id int,name varchar(20)); insert into test_varchar values (1, 'name' + char(0)); insert into test_varchar values (1, 'name' + '');
然后通過java程序進(jìn)行獲取數(shù)據(jù)并插入到PG,同樣會(huì)得到錯(cuò)誤信息:
invalid byte sequence for encoding "UTF8": 0x00
首先我們認(rèn)為此為gb2312轉(zhuǎn)化到UTF8時(shí),發(fā)生了無法轉(zhuǎn)化的錯(cuò)誤。經(jīng)查UTF8是變長(zhǎng)的, 1-6個(gè)字節(jié)。他的編碼規(guī)則如下:
Bits | Last code point | Byte 1 | Byte 2 |
Byte 3 |
Byte 4 |
Byte 5 |
Byte 6 |
7 | U+007F | 0xxxxxxx | |||||
11 | U+07FF |
110xxxxx | 10xxxxxx | ||||
16 | U+FFFF |
1110xxxx | 10xxxxxx |
10xxxxxx |
|||
21 | U+1FFFFF |
11110xxx | 10xxxxxx |
10xxxxxx |
10xxxxxx |
||
26 | U+3FFFFFF |
111110xx | 10xxxxxx |
10xxxxxx |
10xxxxxx |
10xxxxxx |
|
31 | U+7FFFFFFF |
1111110x | 10xxxxxx |
10xxxxxx |
10xxxxxx |
10xxxxxx |
10xxxxxx |
而0x00是符合UTF8規(guī)則的。這就使我們非常詫異。然后我們發(fā)現(xiàn)有兩點(diǎn)繼而確認(rèn)了問題:
1、
PostgreSQL doesn't support storing NULL (\0x00) characters in text fields (this is obviously different from the database NULL value, which is fully supported). If you need to store the NULL character, you must use a bytea field - which should store anything you want, but won't support text operations on it. Given that PostgreSQL doesn't support it in text values, there's no good way to get it to remove it. You could import your data into bytea and later convert it to text using a special function (in perl or something, maybe?), but it's likely going to be easier to do that in preprocessing before you load it. Source:http://stackoverflow.com/questions/1347646/postgres-error-on-insert-error-invalid-byte-sequence-for-encoding-utf8-0x0
2、
Terminating character |
Indicated by |
---|---|
Tab |
\t This is the default field terminator. |
Newline character |
\n This is the default row terminator. |
Carriage return/line feed |
\r |
Backslash1 |
\\ |
Null terminator (nonvisible terminator)2 |
\0 |
Any printable character (control characters are not printable, except null, tab, newline, and carriage return) |
(*, A, t, l, and so on) |
String of up to 10 printable characters, including some or all of the terminators listed earlier |
(**\t**, end, !!!!!!!!!!, \t—\n, and so on) |
Source:http://msdn.microsoft.com/en-us/library/ms191485.aspx
由此我們確定,是pg對(duì)null的處理和SQL Server處理是不相同的,所以在這里出現(xiàn)了錯(cuò)誤。
而導(dǎo)致這一問題的PG具體代碼如下(src/backend/utils/mb/wchar.c的pg_verify_mbstr_len):
if (!IS_HIGHBIT_SET(*mbstr)) { if (*mbstr != '\0') { mb_len++; mbstr++; len--; continue; } if (noError) return -1; report_invalid_encoding(encoding, mbstr, len); }
#define IS_HIGHBIT_SET(ch) ((unsigned char)(ch) & HIGHBIT) #define HIGHBIT (0x80)
report_invalid_encoding函數(shù)是將錯(cuò)誤信息返回,也就是
invalid byte sequence for encoding "UTF8": 0x00
而真正導(dǎo)致這一問題的就是:
!IS_HIGHBIT_SET(*mbstr)當(dāng)*mbstr為0x00時(shí)進(jìn)入判斷,然后進(jìn)而判斷*mbstr是否為\0,當(dāng)為\0時(shí),直接進(jìn)入函數(shù)report_invalid_encoding報(bào)錯(cuò)。
所以出現(xiàn)此問題的原因是PG和SQL Server對(duì)null的處理是不相同的。
處理方案 :
1、將SQL Server源數(shù)據(jù)進(jìn)行修改方法,
UPDATE: This seems to work: Select * from TABLE where UNICODE(SUBSTRING(naughtyField, LEN(naughtyField), 1)) = 0 So: Update TABLE SET naughtyField = SUBSTRING(naughtyField, 1, LEN(naughtyField) - 1) where UNICODE(SUBSTRING(naughtyField, LEN(naughtyField), 1)) = 0 Source:http://stackoverflow.com/questions/3533320/sql-server-remove-end-string-character-0-from-data
2、對(duì)應(yīng)用進(jìn)行修改,獲取到SQL Server數(shù)據(jù)時(shí),將數(shù)據(jù)進(jìn)行轉(zhuǎn)化,和第一種方法異曲同工。
- 關(guān)于MySQL數(shù)據(jù)遷移--data目錄直接替換注意事項(xiàng)的詳解
- 一句命令完成MySQL的數(shù)據(jù)遷移(輕量級(jí)數(shù)據(jù))
- 如何把sqlserver數(shù)據(jù)遷移到mysql數(shù)據(jù)庫及需要注意事項(xiàng)
- 簡(jiǎn)述MySQL分片中快速數(shù)據(jù)遷移
- mysql數(shù)據(jù)遷移到Oracle的正確方法
- MySQL數(shù)據(jù)遷移使用MySQLdump命令
- 從云數(shù)據(jù)遷移服務(wù)看MySQL大表抽取模式的原理解析
- 使用SQL SERVER存儲(chǔ)過程實(shí)現(xiàn)歷史數(shù)據(jù)遷移方式
- mysql數(shù)據(jù)遷移之data目錄復(fù)制方法
- MySql使用存儲(chǔ)過程進(jìn)行單表數(shù)據(jù)遷移的實(shí)現(xiàn)
- Sql Server數(shù)據(jù)遷移的實(shí)現(xiàn)場(chǎng)景及示例
相關(guān)文章
PostgreSQL 實(shí)現(xiàn)定時(shí)job執(zhí)行(pgAgent)
這篇文章主要介紹了PostgreSQL 實(shí)現(xiàn)定時(shí)job執(zhí)行(pgAgent),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-01-01在PostgreSQL中設(shè)置表中某列值自增或循環(huán)方式
這篇文章主要介紹了在PostgreSQL中設(shè)置表中某列值自增或循環(huán)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-01-01Postgresql開啟遠(yuǎn)程訪問的步驟全紀(jì)錄
postgre一般默認(rèn)為本地連接,不支持遠(yuǎn)程訪問,所以如果要開啟遠(yuǎn)程訪問,需要更改安裝文件的配置。下面這篇文章主要給大家介紹了關(guān)于Postgresql開啟遠(yuǎn)程訪問的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。2018-03-03PostgreSQL教程(七):函數(shù)和操作符詳解(3)
這篇文章主要介紹了PostgreSQL教程(七):函數(shù)和操作符詳解(3),本文講解了序列操作函數(shù)、條件表達(dá)式、數(shù)組函數(shù)和操作符、系統(tǒng)信息函數(shù)、系統(tǒng)管理函數(shù)等內(nèi)容,需要的朋友可以參考下2015-05-05postgresql高級(jí)應(yīng)用之行轉(zhuǎn)列&匯總求和的實(shí)現(xiàn)思路
這篇文章主要介紹了postgresql高級(jí)應(yīng)用之行轉(zhuǎn)列&匯總求和的實(shí)現(xiàn)思路,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-05-05如何使用Dockerfile創(chuàng)建PostgreSQL數(shù)據(jù)庫
這篇文章主要介紹了如何使用Dockerfile創(chuàng)建PostgreSQL數(shù)據(jù)庫,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-02-02postgresql數(shù)據(jù)庫連接數(shù)和狀態(tài)查詢操作
這篇文章主要介紹了postgresql數(shù)據(jù)庫連接數(shù)和狀態(tài)查詢操作,具有很好的參考價(jià)值,對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-02-02PostgreSQL三種自增列sequence,serial,identity的用法區(qū)別
這篇文章主要介紹了PostgreSQL三種自增列sequence,serial,identity的用法區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-02-02Postgresql刪除數(shù)據(jù)庫表中重復(fù)數(shù)據(jù)的幾種方法詳解
本文詳細(xì)講解了Postgresql刪除數(shù)據(jù)庫表中重復(fù)數(shù)據(jù)的幾種方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-10-10