使用二进制数据更新 PostgreSQL 表

Updating PostgreSQL table with binary data

本文关键字:PostgreSQL 更新 数据 二进制      更新时间:2023-10-16

我有一个带有此序列化二进制数据的std::stringstream strs变量:

G {SSF>% hgRQ;Tjh A "ʐk R3 1[Z yA _ Kx O f ' t % +>, ~ 삾 +/Tb  7 ( Q1 5m& ( G# bm 3O AN ) DPeco 0=ʆ 0 j u E 3 G # " \ ! o% L. WMG?B- 3 }& . S ( B j& @ %&, 65 0 !G 5R N 0 b hthus��v) 8 x %7 5e : w|7ώJ 8 X/v c h2 3 i o^
A oG 0 + Ȑ" n 4 F#>b . m =; X <c(> [ ۠ ɴKG '$ _s g:] A؞, Q

这是使用 GDB 后相同的数据:

"\374G\371{SSF\301\251*>\177%\225\201\253i\b\344\206\341hgRQ\016\022\001;Tjh\002\000\000\000A\000\000\000\001\000\000\000\000"ʐk\323R3\000\061[Z\272yA\001\000_\340\016K\004x\005\000O\226\f\262\a\375\020\000\346\302\341f\230\235'\000\026\275\367\371\215t\020\000%\356\033\372+>, \000\307\016\361\327~\223\033\000삾\351\254+/\000Tb\335Â363\067\000\342(\357\336\346\326\017\000\327Q1\320\065m&\000\034\216\377\035\005(\a\000\020G#\345bm\017\000\063O\324AN )\000\225DPʇg\a\000\355\060=ʆ\260\060\000\232\377\272j\234u\006\000E\304\063\372\355\v\f\000\223G\353\024#\307"\000\317\327!\270o%\000\005L\035.\345\306\002\000\257WMG?B-\000\063\275\342\373\304}&\000\365\017.\367S\264\031\000(\236\033B\354\255\00\316\034j&\321\021\00\266@\226\314%&,\000\066\065\236\024\271\033\060\000!G\332\v5R\030\000\372\f\353N\225\201\060\000\331\377\035b\244\263\033\000h\361\205\267\207v)\000\322\027\070\246\212w\b\000x<\001\026n}\034\000Tʗp{\362F\t\000\370\352m\026ŵ8\000(\366\366ۡ:\017\000\364\026\210b=\235\"\000\251\214[)\262\342\022\000 m\316fd\345\060\000[VAl\206\233\006\000\035\354o\021'9#\000\363\032\327\372\357\322\034\000|'\256\306K{\021\000B\266\330v\257\332+\000x\346\023\300\315\306!\000qO\016\005wz*\000T\236*\021\272H;\000\ba\006$\376\214\027\000\213\377\a\330\372\023\003\000\361,m\274\300\321\004\000DË\277\272T \000\357\231Ţ\355\270\067\000;:\263\303\070\246\022\000~\267\374\060\272\261\r\000\264>\374\021\027%7\000\065\034E\216\305:\006\000w|7ώJ\006\000\070\242\210\310\343\206\00\365\263\370\377\005X/\000v\335c\200h\035\062\000\063\225\363\244i\362\r\000o^\371\353\302\27\000\000\000\000\000\000\000\000\000\000\t\224A\207\331\374\024\000\254oG\352\364\177\060\000+\254\332\330Ő\"\000n\024\310\360\265?\b\000\004\234\231\006\250\064\016\000F#\225>b\020 \000.\271\224m\246=;;\000\305\t\017\372X\024\024\000\232\023\005\360\277<\017\000\036\242 c\005(=\000\211\200\212\067Y:0027320617n204233270002Q364376O2773300w21233k273q!00333D204241G3317000O242306346l3276100j224205DH33320027025375rhJn00v͑UF227 00230P27221124705;0037217717310b|3200367357255352hn3600226U230255z247*006000Ԏ2413016600315b@24I2273200275322,K2753043400332R375B233760100331324ﲒir00256353o237H2056000353"2625360320n00203306344B,2000600$6QP325@1700YŽ3620360650036670251s2642521700360>251310340:>0025731032605*2163600Kp1>232~<00225022533023653502100x341650060652100S?331V311"0000356m3070330670400)212265351331z$00336Ye21732333-00215nK26Pzv00~8273쩳r00dFr261̄500206aɼ303365%00v365x304O346#0071210B373/26466003246521603274[.00363343P%:3113300244301370V367t0600G\005'\213O\017\000\252\220#bQ\3 24\071\000\376\272\377\347\016\237)\00037460%311[000177rf357233(?00e(r2045\r\000rt\000\005\230O*\000\345[\204۠x\b\000\207ɴKG\224\v\000\273'$\261_s\036\000\215\240\fg:]\002\000A؞,\303Q\t

\000\000\000\000\000\000\000\000"

我正在尝试将此数据(存储在std::stringstream strs中)上传到用UTF8编码的 PostgreSQL 数据库和byte_info列,但使用 libpqxx 库bytea除外:

pqxx::connection Con("My con information");
pqxx::work W(Con);
W.exec("UPDATE " + tableName + " SET byte_info =" + strs.str() + " WHERE id = 1;");
W.commit();

但我得到的只是这个错误:

错误:编码"UTF8"的字节序列无效:0xfc

我在这里错过了什么或做错了什么?

根据PostgreSQLbytea的手册,有2种方法可以编写包含二进制流的语句。

对于字符串"x4AxC3xA1xF2x18"

  1. 十六进制byteaE'\x4AC3A1F218'
  2. 转义byteaE'J\303\241\362\030'::bytea-- 转义\\,转义'',转义不可打印为\three-digit-octal

所以你可以想出这样的功能。

std::string ascii_to_hex_bytea(std::string_view sv) {
std::ostringstream os;
os << R"(E'\x)" << std::hex << std::uppercase;
for (unsigned char ch : sv) {
os << std::setfill('0') << std::setw(2) << static_cast<uint16_t>(ch);
}
os << "'";
return os.str();
}
std::string ascii_to_escaped_bytea(std::string_view sv) {
std::ostringstream os;
os << "E'" << std::oct;
for (unsigned char ch : sv) {
if (isprint(ch))
switch (ch) {
case('') : os << R"(\\)"; break; // escape back slash
case(''') : os << R"(')"; break;   // escape single quote
default    : os << ch;               // simply put printable char
}
else // escape the rest as an octal with back slash leading
os << R"(\)" << std::setfill('0') << std::setw(3) << static_cast<uint16_t>(ch);
}
os << "'::bytea";
return os.str();
}

假设您: �� �� Q��O� w�k�q! �D��G�8 O���l�1 j��DH ��rhJ v͑UF� �P���; �| ���h �U��z�* 0 Ԏ��6 @I� ��,K�� �R�B� ��ﲒi ��o�H�0 �"�� ���B,� $6QP�@ YŽ�05 �8�s�� �>���:> ���*� Kp1>�~< ����� x�5 05 S?�V�" �m�7 )����z$ �Ye��- �nKPz ~8�쩳 dF �̄5 �ɼ��% v�x�O�# 9�B�/�6 �5��[. ��P%:� ���V�t0stringstream了一些数据(对于演示,我们只是在这里横冲直撞)

std::stringstream ss;
{ // random bits for length of 1024
std::string str(1024,'');
for (char* addr = str.data(); addr < str.data() + str.size(); ++addr )
*addr = static_cast<char>(std::experimental::randint<uint16_t>(0,255) );
ss.str(str);
}

您可以使用这些函数编写语句

auto hex_str = ascii_to_hex_bytea(ss.str() );
std::cout << hex_str << "n";
std::string tableName{"table_name"};
std::string statement1 = "UPDATE " + tableName + " SET byte_info = " + hex_str + " WHERE id = 1;";
std::cout << statement1 << "nn";
auto escaped_str = ascii_to_escaped_bytea(ss.str() );
std::cout << escaped_str << "n";
std::string statement2 = "UPDATE " + tableName + " SET byte_info = " + escaped_str + " WHERE id = 1;";
std::cout << statement2 << "n";

打印

E'\x4AC3A1F218E1ED92AB0B3966C3E99CC5BD8419B4A91D504F85AE7621525F305A...'
UPDATE table_name SET byte_info = E'\x4AC3A1F218E1ED92AB0B3966C3E99C...' WHERE id = 1;
E'J\303\241\362\030\341\355\222\253\0139f\303\351\234\30...'::bytea
UPDATE table_name SET byte_info = E'J\303\241\362\030\341\355\...'::bytea WHERE id = 1;

godbolt.org/g/8Ctgcu

wandbox.org/permlink/eaaAWz7pCbGTLcbC