【问题标题】:QSqlQuery inserting QByteArray as string into PostgreSQLQSqlQuery 将 QByteArray 作为字符串插入 PostgreSQL
【发布时间】:2016-05-12 12:40:16
【问题描述】:

我有一个 PostgreSQL 9.4.5 表,其中有一列具有基本字符数据类型,即这样创建:

CREATE TABLE films (
    code        char(5) CONSTRAINT firstkey PRIMARY KEY,
    title       varchar(40) NOT NULL);

然后我使用 QSqlQuery 插入数据,使用绑定的 QByteArray:

QSqlQuery query;
query.prepare("INSERT INTO films VALUES (1, ?)");
const QByteArray film("Avatar");
query.addBindValue(film);
query.exec();

在 Ubuntu 15.10 上,电影名称以字节形式进入表格:

\x417661746172

在 Windows 上,它作为字符输入。

如果不将 QByteArray 显式转换为 QString,有没有办法告诉 QSqlQuery 或 PostgreSQL 将数据视为字符串,因此它在 Ubuntu 上的工作方式与在 Windows 上的工作方式一样?

【问题讨论】:

  • 基本问题 - 有没有理由使用QByteArray 而不是QString?在引用的代码中我看不到任何内容。

标签: c++ postgresql qt qsqlquery qbytearray


【解决方案1】:

尝试使用bindValue 而不是addBindValue。请参考此link

【讨论】:

  • 恐怕同样的结果。
【解决方案2】:

QByteArray 没有关于它包含的字符串编码的信息(甚至它包含的字节序列可以解释为编码字符串)。

如果它恰好包含一个 UTF-8 编码的字符串,你可能会

  • 使用QString::fromUtf8(film.constData()) 将其绑定为字符串,而不仅仅是film

  • 让 Qt 驱动程序将其作为bytea 传递,但让 PostgreSQL 通过 INSERT 查询将其转换为文本:

    query.prepare("INSERT INTO films VALUES (1, convert_from(?,'UTF-8')))");
    

这也适用于其他编码,上面的UTF-8 就是一个例子。


关于 Windows/Ubuntu 之间的区别:目前尚不清楚 QtSql 的行为为何会有所不同,但可能是 postgres 配置的不同。

'\x417661746172'Avatar 在 UTF-8 中作为二进制字符串的文本表示,但仅当 bytea_output 设置为 hex 时。如果将bytea_output 设置为escape,那将完全是Avatar,并且从文本本身看不出来。

psql 命令行客户端中的示例:

test=> set bytea_output=hex;
SET
test=> select 'Avatar'::bytea;
     bytea      
----------------
 \x417661746172
(1 row)

test=> set bytea_output=escape;
SET
test=> select 'Avatar'::bytea;
 bytea  
--------
 Avatar
(1 row)

bytea 的转义也发生在客户端的驱动程序中,例如 QPSQL,而 hex 风格仅在 PostgreSQL 9.0 之后可用。在此之前,escape 是唯一的方法,bytea_output 参数不存在。 我相信,在 Windows 机器上简单地将 QtSql 与早于 9.0 的 libpq 链接可能可以解释为什么你会在最近的 Ubuntu 上获得“类似文本”的外观而不是“类似十六进制”的外观。

【讨论】:

  • convert_from 有助于了解,谢谢。有趣的是,在 Windows 上,QtSql 层会自动进行字节转换(大概是到UTF-8),而在 Ubuntu 上必须显式完成。
  • @Lozzer:我在答案中添加了一个可能的解释。我相信这不是真正的 windows vs ubuntu,而是版本/配置的差异。
【解决方案3】:

我在 Windows 上使用 Qt 5.6 和在 debian 上使用 PostgresSQL 9.6 时遇到同样的问题。 当使用 64 位编译时,bytea 被读取为二进制。 使用 32 位编译时,bytea 被读取为十六进制。

CREATE TABLE image (
   id serial,
   name text,
   picture bytea
 );

sql_query.prepare("SELECT id, name, picture FROM image");
...
QByteArray name = sql_query.value("name").toByteArray();
QByteArray Picture = SQL_query.value("Picture").toByteArray();

varchar read with both (32-bit and 64-bit) into QByteArray as string.

//Output 64-Bit application:
name = "Test", Picture = "‰PNG\r\n\x1a\n\0\0..."
//Output 32-Bit application:
Name = "Test", Picture = "x89504e470d0a1a0a0000..."

我在打开以下查询后添加,现在可以使用了

  QSqlQuery sql_query;
  sql_query.exec("SET bytea_output = 'escape'");

两个 postgres 驱动程序都来自 pg 9.5,64 位来自已安装的 Postgres,32 位是在 zip 文件中下载的。两者具有相同的名称“libpq.dll”

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-08
    • 2016-04-05
    • 1970-01-01
    • 2016-04-05
    • 1970-01-01
    相关资源
    最近更新 更多