如何阻止Sequel的postgres-pr适配器以错误的编码方式返回数据?

时间:2016-06-16 09:13:42

标签: ruby postgresql encoding sequel

我从jeremyevans-postgres-pr适配器获取了错误的编码,这是Sequel建议的那个。

有什么我做错了吗?

示例代码:

require 'postgres-pr/connection'
c = PostgresPR::Connection.new('blah', 'blah', 'blah')

row = c.query("select name, cost from remedium.prescription").rows.last
row.each do |f|
  #f.force_encoding(Encoding::UTF_8) #-- uncomment this to 'fix' everything ;/

  enc = f.kind_of?(String) ? f.encoding : ''
  puts [f.class, f, f.inspect, enc].join(' ')
end

输出:

String Paracelsium "Paracelsium" ASCII-8BIT
String £0.00 "\xC2\xA30.00" ASCII-8BIT

毋庸置疑,我从Sequel本身得到了相同的结果。我的数据库没有编码为ASCII,而是编码为UTF8。

  • 现在我需要使用Ruby和JRuby与PostgreSQL交谈,在每种情况下尝试使用相同的工具链是有意义的,所以这是显而易见的适配器。但

  • Jeremy分叉的original adaptor表现相同。

  • 我可以通过强制编码来解决这个问题,但这对我的所有代码都是一种巨大的痛苦......

我可能应该提供一些额外的答案(谢谢):

  • 版本 - > Centos 7; Ruby 2.3.1& JRuby 9.1.1.0;宝石版0.6.6
  • 操作系统区域设置 - > “LANG = en_GB.UTF-8”
  • Ruby默认值 - > Encoding.default_internal = nil; default_external =编码:: UTF-8

3 个答案:

答案 0 :(得分:1)

postgres-pr不支持编码。这不是我计划添加的东西,但我愿意考虑补丁。

您可以使用force_encoding Sequel :: Model插件来修复编码,至少在您使用模型的地方。

答案 1 :(得分:1)

我在我的一个数据库上尝试了你的代码示例,一切都按预期工作。 您的设置可能是特别的东西吗?您可以使用

检查客户端编码
p c.query("SHOW client_encoding;").rows.first

并且应该能够使用:

进行设置
p c.query("SET CLIENT_ENCODING TO 'UTF-8';")

在Andy Jones的一些反馈和Jeremy的评论之后,我更多地查看了源代码。编辑问题所以我有更好的格式选项而不是评论。

驱动程序从流中读取 US-ASCII ,如下所示:

    buffer.copy_from_stream(stream, length-4)

source code

这反过来调用Buffer#write,将数据插入其自己的@content

@content[@position, sz] = str

source code

现在@content是一个特定大小的字符串,用符号填充,它是这样创建的:

def self.of_size(size)
  raise ArgumentError if size < 0
  new('#' * size
end

这使得@content成为 UTF-8 字符串,因为您的系统设置为使用UTF-8。将 US-ASCII 字符串合并为 UTF将导致__UTF-8 字符串。从那以后,没有发生转换,所以它应该保持编码。使用执行此操作的Buffer.read方法读取列内容:

@content[@position, n]

source code

这个冗长的解释只是说:我不明白为什么你会看到 US-ASCII 输出: - (

除非:您的系统未设置为以某种奇怪的方式使用UTF-8。

使用Ruby 1.9,默认编码为 US-ASCII ,使用Ruby 2.2更改为 UTF-8 (或更早,不确定?)。

你有

吗?
# encoding: 

文件开头的样式注释?

如果你这样做会怎样?

puts String.new.encoding

的价值是多少?
puts __ENCODING__

的价值是多少?
puts RUBY_VERSION

请检查运行db test script的文件。

答案 2 :(得分:0)

理解这里发生的事情的关键是在ruby中进行编码的多个设置。有:

  • 使用魔术注释或-k命令行开关设置语言环境编码。

  • 默认外部编码,设置为Encoding.default_external或--external-encoding或-E

  • 默认内部编码,使用Encoding.default_internal或--internal-encoding(或冒号后的-E)设置

Ruby默认情况下会根据一些相当混乱的规则将字符串设置为内部或外部编码。有关详细信息,请参阅the documentation。但这里的重要部分是,当从二进制数据创建字符串时,它似乎是内部而不是使用的外部编码。

我的内部编码为零,因此没有发生。 (ASCII-8BIT是Ruby在不知道编码是什么时得到的编码 - 它基本上意味着“这只是给我的数据;祝你好运”。)

如果我在命令行上传递--internal-encoding UTF-8,则问题就会消失。从某种意义上说,这与杰里米的宝石无关。

当我在命令行上放置-E UTF-8时,会设置默认的外部编码。在这种情况下,这没有任何作用。

编辑:它适用于这种情况,但在某些(全部?)情况下,Ruby将字符串转码为内部编码,而不是像force_encoding中那样设置编码值。这个东西很难。