使用 psql 插入 postgres 数据库时的特殊字符
Special characters on insert to postgres db with psql
我尝试用 psql 将特殊字符“†”添加到 varchar 字段,但没有成功。从 php 应用程序它可以工作(php 用户作为 iso8859-1)。
数据库设置为:
encoding = LATIN1
collation = fi_FI
character type = fi_FI
client both UTF8 & LATIN1 (on commandline PGCLIENTENCODING=LATIN1 or PGCLIENTENCODING=UTF8)
从table中选择
当客户端是 UTF8
时显示
locationx \u0086
如何从psql向数据库添加值?以下均无效。
update tablex set field1 = 'locationY' || '†'
update tablex set field1 = 'locationY' || U&''
给出错误信息。
ERROR: character with byte sequence 0xe2 0x80 0xa0 in encoding "UTF8" has no equivalent in encoding "LATIN1"
ERROR: invalid Unicode escape value at or near "' "
如果我查看我的 PHP 应用程序输入的数据,字节数是 \x6c6f636174696f6e5986
,但是当我使用 psql
输入数据时,字节数是 \x6c6f636174696f6e59e280a0
.
它不适用于 PHP 或 psql
,因为字符 †
在 LATIN-1 编码中不存在。你只是不能将它存储在数据库中。
让我解释一下这是怎么回事。
如果您的客户端编码是LATIN1
并且您输入psql
:
INSERT INTO ... VALUES ('locationY†');
存储成功,因为您的终端设置为 UTF-8。所以你输入的†
实际上是三个字节:\xE280A0
,它们被解释并存储为三个单字节字符
如果您的客户端编码是UTF8
并且您输入psql
:
同样的insert会报错,因为输入†
时输入的三个字节会被正确解释为匕首字符,PostgreSQL尝试转换字符时会出错到 LATIN
:
ERROR: character with byte sequence 0xe2 0x80 0xa0 in encoding "UTF8" has no equivalent in encoding "LATIN1"
用PHP,你的客户端编码很可能设置为LATIN1
,而PHP程序实际使用的是WINDOWS-1252编码。
则†
由单字节\x86
表示。这是由 PostgreSQL 在 LATIN1
编码中解释的,它意味着完全不同的东西,即“selected 区域的开始”控制字符 U+0086
.
现在,当您的 PHP 程序读回该字符时,一切 似乎 工作正常,但数据库实际存储的字符与您预期的不同。
您会注意到,一旦您尝试通过任何其他方式 select 该值,例如在你的 psql
控制台上。那里的值将呈现为
locationY\u0086
这里有一个解决方法:
使用 UTF8
编码创建一个新数据库。
使用
转储旧数据库
pg_dump -F p -E LATIN1 dbname
手动编辑转储并更改行
SET client_encoding = 'LATIN1';
至
SET client_encoding = 'WIN1252';
使用 psql
将转储加载到新数据库中。
将 PHP 应用程序的 client_encoding
更改为 WIN1252
并开始使用新数据库。
我尝试用 psql 将特殊字符“†”添加到 varchar 字段,但没有成功。从 php 应用程序它可以工作(php 用户作为 iso8859-1)。
数据库设置为:
encoding = LATIN1
collation = fi_FI
character type = fi_FI
client both UTF8 & LATIN1 (on commandline PGCLIENTENCODING=LATIN1 or PGCLIENTENCODING=UTF8)
从table中选择 当客户端是 UTF8
时显示locationx \u0086
如何从psql向数据库添加值?以下均无效。
update tablex set field1 = 'locationY' || '†'
update tablex set field1 = 'locationY' || U&''
给出错误信息。
ERROR: character with byte sequence 0xe2 0x80 0xa0 in encoding "UTF8" has no equivalent in encoding "LATIN1"
ERROR: invalid Unicode escape value at or near "' "
如果我查看我的 PHP 应用程序输入的数据,字节数是 \x6c6f636174696f6e5986
,但是当我使用 psql
输入数据时,字节数是 \x6c6f636174696f6e59e280a0
.
它不适用于 PHP 或 psql
,因为字符 †
在 LATIN-1 编码中不存在。你只是不能将它存储在数据库中。
让我解释一下这是怎么回事。
如果您的客户端编码是
LATIN1
并且您输入psql
:INSERT INTO ... VALUES ('locationY†');
存储成功,因为您的终端设置为 UTF-8。所以你输入的
†
实际上是三个字节:\xE280A0
,它们被解释并存储为三个单字节字符如果您的客户端编码是
UTF8
并且您输入psql
:同样的insert会报错,因为输入
†
时输入的三个字节会被正确解释为匕首字符,PostgreSQL尝试转换字符时会出错到LATIN
:ERROR: character with byte sequence 0xe2 0x80 0xa0 in encoding "UTF8" has no equivalent in encoding "LATIN1"
用PHP,你的客户端编码很可能设置为
LATIN1
,而PHP程序实际使用的是WINDOWS-1252编码。则
†
由单字节\x86
表示。这是由 PostgreSQL 在LATIN1
编码中解释的,它意味着完全不同的东西,即“selected 区域的开始”控制字符U+0086
.现在,当您的 PHP 程序读回该字符时,一切 似乎 工作正常,但数据库实际存储的字符与您预期的不同。
您会注意到,一旦您尝试通过任何其他方式 select 该值,例如在你的
psql
控制台上。那里的值将呈现为locationY\u0086
这里有一个解决方法:
使用
UTF8
编码创建一个新数据库。使用
转储旧数据库pg_dump -F p -E LATIN1 dbname
手动编辑转储并更改行
SET client_encoding = 'LATIN1';
至
SET client_encoding = 'WIN1252';
使用
psql
将转储加载到新数据库中。将 PHP 应用程序的
client_encoding
更改为WIN1252
并开始使用新数据库。