[Python] 塞 NULL 字元進 PostgreSQL 資料庫時,出現 A string literal cannot contain NUL (0x00) characters 的錯誤訊息
今天專案的 python 程式,
在把一串資料塞進 PostgreSQL 時,突然出現了 exception:
ValueError: A string literal cannot contain NUL (0x00) characters.
檢查了一下,要塞進去的資料是一個 byte 的 NULL 字元,
以 python 來說是 “\x00″,
但以前同樣的程式沒有問題,為什麼現在出錯了呢?
首先懷疑是 PostgreSQL 不吃 NULL 字元…
但試著塞一個 \x00 字串進去,是成功的:
testdb=> insert into tbl_info values('xxx', decode('00', 'hex')); INSERT 0 1
用 SELECT 也看的到這個 \x00 NULL 字元:
testdb=> select * from tbl_info; name | value | updatetime ------------+----------------+---------------------------- xxx | \x00 | 2018-06-12 04:08:46.910405
到底是怎麼一回事呢?
如果 PostgreSQL 可以吃 NULL 字元,這個 exception 又是哪裡來的?
在網路上找了一下,似乎在不同的專案間都有這個 exception 的身影…
後來注意到 psycopg2,這是我們用來存取資料庫用的 Python 第三方模組,
這個 exception 的訊息在 psycopg/utils.c 可以看到:
char * psycopg_escape_string(connectionObject *conn, const char *from, Py_ssize_t len, char *to, Py_ssize_t *tolen) { // ... } else if (strchr(from, '\0') != from + len) { PyErr_Format(PyExc_ValueError, "A string literal cannot contain NUL (0x00) characters."); // ... }
從這段程式可以很清楚看到,只要字串裡有 \x00 NULL 字元,
psycopg2 就會彈一個 ValueError 的 exception,
內容就是 A string literal cannot contain NUL (0x00) characters.
這段程式在新版 psycopg2 2.7 版有出現,
但在我們之前使用的舊版 2.4.5 版本上沒有出現。
這就解釋了為什麼現在才冒出這個問題,
因為專案的舊版本搭配 psycopg2 2.4.5 版,所以沒事。
專案的新版本搭配了 psycopg2 2.7 版,所以出事了…
目前的解法,就是採取類似 C/C++ 對字串的處理方式,
把 \x00 NULL 字元連同後面的字串都截掉,
這樣字串的中間就不會有 \x00 NULL 字元,
也就不會觸發新版 psycopg2 的 exception 囉~