Postgres中不存在函数convert_from(character varying, unknown)。

4
在下面的代码中,当我试图从Unicode转换为UTF8时,出现了“函数convert_from(character varying,unknown)不存在”的错误。
select convert_from(artists, 'UTF8') from songs where     
to_tsvector('simple',convert_from(artists, 'UTF8')) 
  @@ plainto_tsquery('simple','alizee') 
limit 100

列 "artists" 的类型为 "TEXT"。

但是当我运行时

select convert_from(E'\u0422\u0438\u043c\u0430\u0442\u0438', 'UTF8');

它的表现很好。

我该如何解决这个问题? 非常感谢您的帮助。谢谢


请展示一下artists列中的一个值样本。在PostgreSQL的text字段中无法存储“unicode”(假设您指的是utf-16 / utf-32 / ucs-2 / ucs-4),因为它包含空字节,而在text字段中,空字节会终止字符串。所以无论发生了什么,这里都没有足够的信息来猜测。通过编辑问题来展示数据,完成后在此处发表评论。 - Craig Ringer
艺术家列的示例值:“brig\u0442\u0438ada” - Mega4alik
啊,原来是带有Unicode字符转义的文本。这很不同。 - Craig Ringer
可能是 https://dev59.com/IHnZa4cB1Zd3GeqPpmm5 和 http://stackoverflow.com/q/10111654/398670 的重复问题。 - Craig Ringer
2个回答

5

来自文档convert_from(string bytea, src_encoding name)。 因此将艺术家转换为bytea:

select convert_from(artists::bytea, 'UTF8') from songs where     
to_tsvector('simple',convert_from(artists, 'UTF8')) 
  @@ plainto_tsquery('simple','alizee') 
limit 100

2
从歌曲中选择convert_from(artists::bytea, 'UTF8'),其中to_tsvector('simple',convert_from(artists::bytea, 'UTF8')) @@ plainto_tsquery('simple','alizee'),限制100个。另一个错误发生:"ERROR: invalid input syntax for type bytea"。 - Mega4alik

4

在我的看法中,您已经以7位ascii和2字节unicode十六进制转义符(\uxxxx)的形式获取了数据,并将其存储在varchar类型的字段中。

convert_from完全不是处理该数据的正确方法。它并不是utf-8,除了7位ASCII是utf-8的子集之外。如果你强制使用convert_from(..., 'utf-8'),你会得到完全一样的东西,例如blah\u0123等。

select convert_from(E'\u0422\u0438\u043c\u0430\u0442\u0438', 'UTF8');之所以似乎有效是因为convert_from什么也没做。以下是发生的情况:

  • PostgreSQL sees the literal value E'\u0422\u0438\u043c\u0430\u0442\u0438' and sees that convert_from wants bytea input.

  • PostgreSQL parses the escape-string format of the string literal, decoding the unicode escapes to produce the utf-8 string Тимати. At this point it's as if you wrote:

    SELECT convert_from('Тимати', 'utf-8')
    
  • Because convert_from wants bytea input, PostgreSQL implicitly casts the data to bytea, converting the text string to utf-8 encodied binary because that's your database server's text encoding. Now it's as if you wrote:

    SELECT convert_from( convert_to('Тимати','utf-8'), 'utf-8')
    

    which when the first conversion is done gets turned into:

    SELECT convert_from(BYTEA '\xd0a2d0b8d0bcd0b0d182d0b8', 'utf-8');
    
因此,你的convert_from实际上是一种非常缓慢和低效的无操作方式。
对于列值而不是字面量,它并不适用,因为PostgreSQL会隐式地将未知类型的字面量转换为已知类型的列值,例如varchar列。这是一种类型安全性考虑。
因此,要正确地转换数据,您需要解码那些\u转义字符。 convert_from并不是您想要的,因为它被设计用于将编码文本的二进制表示转换为本地数据库文本编码。
PostgreSQL支持字符串字面量的这种转换,我们通过查看E''字面量的处理方式来确定了这一点。我目前正在寻找一个向用户公开该解码的函数,但decode(...)不支持\u转义字符,只支持八进制转义字符...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接