【问题标题】:How to insert binary data into a PostgreSQL BYTEA column using the C++ libpqxx API?如何使用 C++ libpqxx API 将二进制数据插入 PostgreSQL BYTEA 列?
【发布时间】:2013-04-09 12:05:36
【问题描述】:

我想在 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 中可用的 BYTEA 新 hex 格式。

【问题讨论】:

    标签: c++ postgresql libpqxx


    【解决方案1】:

    想通了。下面是一个示例,展示了如何将一堆二进制对象插入到表中:

    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)。
    【解决方案2】:

    插入中没有 pqxx::bynarystring。我使用以下解决方案来做到这一点:

    === 在数据库中存储 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);
    

    希望对你有帮助。

    【讨论】:

      【解决方案3】:

      如果您愿意,可以使用 pqxx::escape_binary 函数的重载之一简单地转义二进制数据,而不是像在 Stéphane 的回答中那样使用带有 conn.prepare 的准备好的 SQL 语句。 Here 是文档。

      【讨论】:

        【解决方案4】:

        由于此问题是通过 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 将其删除。

        【讨论】:

          【解决方案5】:

          我使用std::string 中的二进制数据提出了一个灵活的解决方案。

          我提出了这个新的解决方案,因为当前的答案是旧的(2013 年),我正在寻找一个使用 pqxx 5.0.1 的多插入查询。

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

          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 测试的

          【讨论】:

            猜你喜欢
            • 2013-12-14
            • 1970-01-01
            • 1970-01-01
            • 2021-08-12
            • 2019-04-26
            • 2010-09-27
            • 1970-01-01
            • 2015-06-09
            • 2019-08-05
            相关资源
            最近更新 更多