2013-04-16 2 views
7

Я хотел бы вставить некоторые двоичные данные в столбец BYTEA, но я обнаружил, что выход Doxygen отсутствует в деталях, а http://pqxx.org/ был недоступен последние несколько дней.Как вставить двоичные данные в столбец PostgreSQL BYTEA с помощью API libpqxx C++?

Как я могу вставить содержимое 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(); 

Если это имеет значение, я хотел бы использовать новый формат hex для BYTEA доступны в PostgreSQL 9.1.

ответ

9

Выяснил это. Ниже приведен пример, показывающий, как вставить кучу двоичных объектов в таблицу:

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(); 
    ... 
} 
+0

мне нравится ваше решение, но я не люблю, используя conn.prepare. Это ограничивает меня, когда у меня есть элемент 'n' для вставки с одним запросом (проблема с производительностью). Я работаю над решением (с pqxx 5.0.1). – LAL

1

Там не 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(); 



=== Получение AN 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

Вместо использования подготовленного оператора SQL с conn.prepare, как и в ответе Стефана, если вы хотите, вы можете просто избежать двоичных данных с одной из перегрузок функции pqxx::escape_binary. Here - это документация.

0

Поскольку этот вопрос является лучшим результатом поиска для вставки BYTEA через libpqxx, вот еще один способ сделать это с помощью параметризованного запроса, что более подходит для выполнения одной вставки.

// 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(); 

Обратите внимание, что параметры должны не быть экранированы с quote или esc методами.

Также обратите внимание, что принятый ответ использования pqxx::connection::prepare заставляет подготовленный запрос существовать на протяжении всего срока службы соединения. Если соединение будет длительным и готовый запрос больше не нужен, его, вероятно, следует удалить, вызвав pqxx::connection::unprepare.

0

Я придумал гибкое решение, используя двоичные данные внутри 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.1, c++11 и postgresSQL 9.5.8