【问题标题】:PostgreSQL - Psycopg2 - copy_from - Invalid byte sequence for encoding "UTF8": 0x00PostgreSQL - Psycopg2 - copy_from - 用于编码“UTF8”的无效字节序列:0x00
【发布时间】:2017-06-12 07:25:57
【问题描述】:

我想使用 Psycopg2 (2.7.1) copy_from() 方法将字节插入到类型为 bytea 的 PostgreSQL (9.5.7) 数据库列中。

我可以使用以下代码插入我的字节:

psycopg2_cursor.copy_from(
    StringIO("\x30\x40\x50"),
    "my_table",
)

通过在插入后对我的表执行 SELECT,我从 bytea 列中获得了预期值:

\x304050

现在,我想在我的字节前面加上字节 0:

psycopg2_cursor.copy_from(
    StringIO("\x00\x30\x40\x50"),
    "my_table",
)

我收到错误:psycopg2.DataError:用于编码“UTF-8”的无效字节序列:0x00。据我了解,仅在将空字节插入文本字段时才应触发此错误,但应按预期在 bytea 字段中工作。我错过了什么吗?有什么简单的方法可以将空字节插入到 bytea 列中?

谢谢!

【问题讨论】:

  • 您的standard_conforming_strings 设置是什么?
  • 你试过StringIO('\x30\x40\x50')吗?..

标签: python postgresql psycopg2


【解决方案1】:

https://www.postgresql.org/docs/current/static/sql-copy.html

以下字符必须以反斜杠开头,如果它们 作为列值的一部分出现:反斜杠本身、换行符、回车 return 和当前的分隔符。

刚刚意识到你正在使用COPY,所以你必须转义反斜杠:

t=# copy b from stdin;
Enter data to be copied followed by a newline.
End with a backslash and a period on a line by itself.
>> \\x00
>> \.
COPY 1
t=# copy b from stdin;
Enter data to be copied followed by a newline.
End with a backslash and a period on a line by itself.
>> \x00
>> \.
ERROR:  invalid byte sequence for encoding "UTF8": 0x00
CONTEXT:  COPY b, line 1: "\x00"

这应该可以解决问题:

psycopg2_cursor.copy_from(
    StringIO("\\x00\\x30\\x40\\x50"),
    "my_table",
)

【讨论】:

  • 我在我的 psycopg2 连接中添加了以下参数:options="-c standard_conforming_strings=on",但我仍然遇到同样的错误。我试过StringIO('\x30\x40\x50'),它工作正常,但我真的需要插入这个空字节。我尝试使用 BytesIO 而不是 StringIO,但仍然得到相同的结果。
  • 试试? select decode('00203040','hex') - 它是否产生了你想要的结果?..
  • 是的,在 PSQL (INSERT INTO my_table VALUES(decode('001060', 'hex'));) 中使用它时会产生想要的结果,但我需要使用 python 代码中的 copy_from() 方法插入字节,而不是直接使用 SQL 查询.
  • 最后一次尝试:psycopg2_cursor.copy_from( StringIO("\\x00\\x30\\x40\\x50"), "my_table", ) ?..
  • 还是一样(编码“UTF8”的字节序列无效:0x00)。好消息是,我可以在使用 cursor.execute("INSERT INTO my_table VALUES(decode('005566', 'hex'));") 时从我的 python 代码中插入字节,但是对于性能问题(我的 github 上的详细信息:github.com/jean553/massive-insert-postgresql-tornado),我更愿意使用 copy_from() 插入。
【解决方案2】:

要使用copy 插入二进制文件,必须使用binary format,这不是您想要的。使用extras.execute_values method

from psycopg2.extensions import Binary

binaries = [[Binary('\x00\x20')], [Binary('\x00\x30')]]

insert_query = 'insert into t (b) values %s'
psycopg2.extras.execute_values (
    cursor, insert_query, binaries, page_size=100
)

【讨论】:

    猜你喜欢
    • 2022-07-28
    • 1970-01-01
    • 1970-01-01
    • 2014-08-02
    • 2022-01-26
    • 1970-01-01
    • 2021-08-19
    • 2021-09-19
    • 2016-12-02
    相关资源
    最近更新 更多