如何使用C++ libpqxx API将二进制数据插入到PostgreSQL BYTEA列中?

12

我想将一些二进制数据插入到BYTEA列中,但是我发现Doxygen的输出缺乏细节,并且http://pqxx.org/在过去几天里一直无法访问。

我应该如何将somefile.bin的内容插入到具有BYTEA列的表中?

我手头的代码大致如下:

pqxx::work work( conn );
work.exec( "CREATE TABLE test ( name varchar(20), data BYTEA )" );
work.exec( "INSERT INTO test( name, data ) VALUES ( 'foo', <insert filename.bin here> )" );
work.commit();

如果有所区别,我想使用PostgreSQL 9.1中可用的新hex格式来处理BYTEA。

5个回答

14

已经弄清楚了。以下是一个示例,展示如何将一堆二进制对象插入到表中:

pqxx::connection conn( ... );
conn.prepare( "test", "INSERT INTO mytable( name, binfile ) VALUES ($1, $2)" );
pqxx::work work( conn );
for ( ... )
{
    std::string name = "foo";
    void * bin_data = ...; // obviously do what you need to get the binary data...
    size_t bin_size = 123; // ...and the size of the binary data

    pqxx::binarystring blob( bin_data, bin_size );
    pqxx::result r = work.prepared( "test" )( name )( blob ).exec();
}
work.commit();

以下是从数据库中获取二进制数据的方法:

pqxx::result result = work.exec( "SELECT * FROM mytable" );
for ( const auto &row : result )
{
    pqxx::binarystring blob( row["binfile"] );
    void * ptr = blob.data();
    size_t len = blob.size();
    ...
}

我很喜欢你的解决方案,但是我不喜欢使用conn.prepare。当我需要用一条查询插入n个元素时(性能问题),这会让我受到限制。我正在使用pqxx 5.0.1构建一个解决方案。 - LAL

1

在插入时没有pqxx::binarystring。我使用以下解决方案来解决这个问题:

=== 将wxImage存储在数据库中 ====

//Getting image string data
wxImage foto = (...);
wxMemoryOutputStream stream;
foto.SaveFile(stream,wxBITMAP_TYPE_PNG);
wxStreamBuffer* streamBuffer = stream.GetOutputStreamBuffer();
size_t tamanho = streamBuffer->GetBufferSize();
char* fotoData = reinterpret_cast<char*>(streamBuffer->GetBufferStart());
string dados(fotoData, tamanho);

//Performing the query
conn->prepare("InsertBinaryData", "INSERT INTO table1(bytea_field) VALUES (decode(encode($1,'HEX'),'HEX'))") ("bytea",pqxx::prepare::treat_binary);

pqxx::work w = (...);
w.prepared(dados).exec();

从数据库中检索wxImage。
pqxx::result r = w.exec("SELECT bytea_field FROM table1 WHERE (...)");
w.commit();

const result::tuple row = r[0];
const result::field tfoto = row[0];

pqxx::binarystring bs(tfoto);
const char* dadosImg = bs.get();
size_t size = bs.length();

wxMemoryInputStream stream(dadosImg,size);
wxImage imagem;

imagem.LoadFile(stream);

我希望它有帮助。

0

我想到了一种使用std::string内的二进制数据的灵活解决方案。

我提出这个新的解决方案,因为当前的答案已经过时(2013年),而我正在寻找一个使用pqxx 5.0.1进行多插入查询的方法。

通过下面的解决方案,您可以灵活地使用for循环在单个插入查询中附加多个二进制数据。

CustomStruct data = .... ; // have some binary data

// initialise connection and declare worker
pqxx::connection conn = new pqxx::connection(...);    
pqxx::work w(conn); 

// prepare query
string query += "INSERT INTO table (bytea_field) VALUES ("
// convert your data in a binary string. 
pqxx::binarystring blob((void *)&(data), data.size());
// avoid null character to bug your query string. 
query += "'"+w.esc_raw(blob.str())+"');";

//execute query
pqxx::result rows = w.exec(query);

当我们想从数据库中检索数据时,您应该具有您的数据类型(例如CustomStruct)的范围,并且应该能够将其转换回您选择的二进制格式。

// assuming worker and connection are declared and initialized.
string query = "SELECT bytea_field FROM table;";
pqxx::result rows = w.exec(query);
for(pqxx::result::iterator col = rows.begin(); col != rows.end(); ++col)
{
    pqxx::binarystring blob(col[0]);
    CustomStruct *data = (CustomStruct*) blob.data();
    ...
}

这是使用 pqxx 5.0.1c++11postgresSQL 9.5.8 进行测试的。


0

如果你想要的话,可以使用pqxx::escape_binary函数中的一个重载来简单地转义二进制数据,而不是像Stéphane的答案中使用conn.prepare准备SQL语句。这里是相关文档。


0

由于这个问题是通过libpqxx插入BYTEA的顶级搜索结果,这里提供另一种使用参数化查询进行操作的方法,如果只执行单个插入,则更为适合。

// Assuming pre-existing pqxx::connection c, void * bin_data, size_t bin_size...
pqxx::work txn(c);
pqxx::result res = txn.parameterized("INSERT INTO mytable(name, binfile) VALUES ($1, $2)")
                                    (name)
                                    (pqxx::binarystring(bin_data, bin_size))
                                    .exec();
txn.commit();

请注意,参数不应使用quoteesc方法进行转义。
还要注意,使用pqxx::connection::prepare的接受答案会导致准备好的查询在连接的整个生命周期内存在。如果连接将持续很长时间并且不再需要准备好的查询,则应通过调用pqxx::connection::unprepare来删除它。

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