使用二进制数据更新 PostgreSQL table
Updating PostgreSQL table with binary data
我有一个包含此序列化二进制数据的 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 ) �DP߇g �0=ʆ�0 ���j�u E�3�� �G�#�" \��!�o%
L.�� �WMG?B- 3����}& �.�S� (�B� �j&� �@��%&, 65��0 !G�5R
��N��0 ��b�� hv) �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(= ���7Y: �� �� 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,� QP�@ 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�t
G'�O ��#bQ�9 �����)
�0%�[0 f�(? e( �
5 rt �O �[�۠ �ɴKG� �'$�_s ��g:] Aߞ,�Q
这是使用GDB后的相同数据:
"4G1{SSF11*>7%513i\b461hgRQ62[=22=]1;Tjh[=22=]2[=22=]0[=22=]0[=22=]0A[=22=]0[=22=]0[=22=]0[=22=]1[=22=]0[=22=]0[=22=]0\"ʐk3R3[=22=]01[Z2yA[=22=]1[=22=]0_06K[=22=]4x[=22=]5[=22=]0O6\f2\a50[=22=]0621f05'[=22=]065715t0[=22=]0%632+>,[=22=]07617~33[=22=]0삾14+/[=22=]0Tb5Ҷ37[=22=]02(76667[=22=]07Q105m&[=22=]04675[=22=]5(\a[=22=]00G#5bm7[=22=]03O4AN
)[=22=]05DP߇g\a[=22=]050=ʆ00[=22=]0272j4u[=22=]6[=22=]0E4325\v\f[=22=]03G34#7\"[=22=]0\3177!0o%[=22=]0[=22=]5L5.56[=22=]2[=22=]07WMG?B-[=22=]035234}&[=22=]057.7S41[=22=]0(63B45\n[=22=]064j&11\n[=22=]06@64%&,[=22=]06564130[=22=]0!G2\v5R0[=22=]02\f3N510[=22=]0175b433[=22=]0h1577v)[=22=]027062w\b[=22=]0x<[=22=]16n}4[=22=]0Җp{2F\t[=22=]002m6ŵ8[=22=]0(66ۡ:7[=22=]0460b=5\"[=22=]014[)222[=22=]0
m6fd50[=22=]0[VAl63[=22=]6[=22=]054o1'9#[=22=]03272724[=22=]0|'66K{1[=22=]0B60v72+[=22=]0x63056![=22=]0qO6[=22=]5wz*[=22=]0T6*12H;[=22=]0\ba[=22=]6$647[=22=]037\a023[=22=]3[=22=]01,m401[=22=]4[=22=]0DË72T
[=22=]071Ţ507[=22=]0;:33062[=22=]0~74021\r[=22=]04>417%7[=22=]054e65:[=22=]6[=22=]0w|7ώJ[=22=]6[=22=]0020036\n[=22=]05307[=22=]5X/[=22=]0v5c0h52[=22=]03534i2\r[=22=]0o^132\n7[=22=]0[=22=]0[=22=]0[=22=]0[=22=]0[=22=]0[=22=]0[=22=]0[=22=]0\t4A7144[=22=]04oG2470[=22=]0+420Ȑ\"[=22=]0n4005?\b[=22=]0[=22=]441[=22=]6046[=22=]0F#5>b0
[=22=]0.14m6=;[=22=]05\t72X44[=22=]023[=22=]507<7[=22=]062 c[=22=]5(=[=22=]01027Y:[=15=]0367\n437[=15=]0[=15=]2Q46O73[=15=]0w23k3q![=15=]03D41G10[=15=]0O266l71[=15=]0j45DH32[=15=]0055rhJ\n[=15=]0v͑UF7
[=15=]00P217[=15=]5;[=15=]02770\b|2[=15=]07752h\n6[=15=]06U05z7*[=15=]00[=15=]0Ԏ116[=15=]05\b@4I72[=15=]052,K544[=15=]02R5B36[=15=]1[=15=]014ﲒi\r[=15=]063o7H50[=15=]03\"6500\n[=15=]0364B,0[=15=]6[=15=]0QP5@7[=15=]0YŽ6305[=15=]0601s427[=15=]00>100:>[=15=]0706[=15=]5*66[=15=]0Kp1>2~<[=15=]05[=15=]232501[=15=]0x15[=15=]0051[=15=]0S?1V1\"[=15=]0[=15=]06m7[=15=]307[=15=]4[=15=]0)2511z$[=15=]06Ye733-[=15=]05nK6Pz\v[=15=]0~83쩳\r[=15=]0dF\r1̄5[=15=]06\aɼ35%[=15=]0v5x4O6#[=15=]010B3/46[=15=]0456[=15=]34[.[=15=]033P%:13[=15=]0410V7t[=15=]6[=15=]0
G[=22=]5'3O7[=22=]020#bQ41[=22=]0627767)[=22=]040%1[0[=16=]07\rf73(?[=16=]0e(\r4
5\r[=22=]0rt[=22=]0[=22=]50O*[=22=]05[4۠x\b[=22=]07ɴKG4\v[=22=]03'$1_s6[=22=]050\fg:][=22=]2[=22=]0Aߞ,3Q\t[=22=]0[=22=]0[=22=]0[=22=]0[=22=]0[=22=]0[=22=]0[=22=]0"
我正在尝试将此数据(存储在 std::stringstream strs
中)上传到使用 UTF8
编码的 PostgreSQL 数据库并上传到 byte_info
列,但 bytea
使用libpqxx图书馆:
pqxx::connection Con("My con information");
pqxx::work W(Con);
W.exec("UPDATE " + tableName + " SET byte_info =" + strs.str() + " WHERE id = 1;");
W.commit();
但我得到的只是这个错误:
ERROR: invalid byte sequence for encoding "UTF8": 0xfc
我在这里遗漏了什么或做错了什么?
根据 PostgreSQL 手册bytea,有两种写包含二进制流的语句的方法。
对于字符串"\x4A\xC3\xA1\xF2\x18"
- 十六进制
bytea
: E'\x4AC3A1F218'
- escaped
bytea
: E'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();
}
假设你有 ss
作为 stringstream
和一些数据(为了演示,我们只是在这里 ramdom 它)
std::stringstream ss;
{ // random bits for length of 1024
std::string str(1024,'[=11=]');
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 << "\n\n";
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;
我有一个包含此序列化二进制数据的 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 ) �DP߇g �0=ʆ�0 ���j�u E�3�� �G�#�" \��!�o% L.�� �WMG?B- 3����}& �.�S� (�B� �j&� �@��%&, 65��0 !G�5R ��N��0 ��b�� hv) �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(= ���7Y: �� �� 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,� QP�@ 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�t
G'�O ��#bQ�9 �����)�0%�[0 f�(? e( �
5 rt �O �[�۠ �ɴKG� �'$�_s ��g:] Aߞ,�Q
这是使用GDB后的相同数据:
"4G1{SSF11*>7%513i\b461hgRQ62[=22=]1;Tjh[=22=]2[=22=]0[=22=]0[=22=]0A[=22=]0[=22=]0[=22=]0[=22=]1[=22=]0[=22=]0[=22=]0\"ʐk3R3[=22=]01[Z2yA[=22=]1[=22=]0_06K[=22=]4x[=22=]5[=22=]0O6\f2\a50[=22=]0621f05'[=22=]065715t0[=22=]0%632+>,[=22=]07617~33[=22=]0삾14+/[=22=]0Tb5Ҷ37[=22=]02(76667[=22=]07Q105m&[=22=]04675[=22=]5(\a[=22=]00G#5bm7[=22=]03O4AN )[=22=]05DP߇g\a[=22=]050=ʆ00[=22=]0272j4u[=22=]6[=22=]0E4325\v\f[=22=]03G34#7\"[=22=]0\3177!0o%[=22=]0[=22=]5L5.56[=22=]2[=22=]07WMG?B-[=22=]035234}&[=22=]057.7S41[=22=]0(63B45\n[=22=]064j&11\n[=22=]06@64%&,[=22=]06564130[=22=]0!G2\v5R0[=22=]02\f3N510[=22=]0175b433[=22=]0h1577v)[=22=]027062w\b[=22=]0x<[=22=]16n}4[=22=]0Җp{2F\t[=22=]002m6ŵ8[=22=]0(66ۡ:7[=22=]0460b=5\"[=22=]014[)222[=22=]0 m6fd50[=22=]0[VAl63[=22=]6[=22=]054o1'9#[=22=]03272724[=22=]0|'66K{1[=22=]0B60v72+[=22=]0x63056![=22=]0qO6[=22=]5wz*[=22=]0T6*12H;[=22=]0\ba[=22=]6$647[=22=]037\a023[=22=]3[=22=]01,m401[=22=]4[=22=]0DË72T [=22=]071Ţ507[=22=]0;:33062[=22=]0~74021\r[=22=]04>417%7[=22=]054e65:[=22=]6[=22=]0w|7ώJ[=22=]6[=22=]0020036\n[=22=]05307[=22=]5X/[=22=]0v5c0h52[=22=]03534i2\r[=22=]0o^132\n7[=22=]0[=22=]0[=22=]0[=22=]0[=22=]0[=22=]0[=22=]0[=22=]0[=22=]0\t4A7144[=22=]04oG2470[=22=]0+420Ȑ\"[=22=]0n4005?\b[=22=]0[=22=]441[=22=]6046[=22=]0F#5>b0 [=22=]0.14m6=;[=22=]05\t72X44[=22=]023[=22=]507<7[=22=]062 c[=22=]5(=[=22=]01027Y
:[=15=]0367\n437[=15=]0[=15=]2Q46O73[=15=]0w23k3q![=15=]03D41G10[=15=]0O266l71[=15=]0j45DH32[=15=]0055rhJ\n[=15=]0v͑UF7 [=15=]00P217[=15=]5;[=15=]02770\b|2[=15=]07752h\n6[=15=]06U05z7*[=15=]00[=15=]0Ԏ116[=15=]05\b@4I72[=15=]052,K544[=15=]02R5B36[=15=]1[=15=]014ﲒi\r[=15=]063o7H50[=15=]03\"6500\n[=15=]0364B,0[=15=]6[=15=]0QP5@7[=15=]0YŽ6305[=15=]0601s427[=15=]00>100:>[=15=]0706[=15=]5*66[=15=]0Kp1>2~<[=15=]05[=15=]232501[=15=]0x15[=15=]0051[=15=]0S?1V1\"[=15=]0[=15=]06m7[=15=]307[=15=]4[=15=]0)2511z$[=15=]06Ye733-[=15=]05nK6Pz\v[=15=]0~83쩳\r[=15=]0dF\r1̄5[=15=]06\aɼ35%[=15=]0v5x4O6#[=15=]010B3/46[=15=]0456[=15=]34[.[=15=]033P%:13[=15=]0410V7t[=15=]6[=15=]0
G[=22=]5'3O7[=22=]020#bQ41[=22=]0627767)[=22=]040%1[0[=16=]07\rf73(?[=16=]0e(\r4
5\r[=22=]0rt[=22=]0[=22=]50O*[=22=]05[4۠x\b[=22=]07ɴKG4\v[=22=]03'$1_s6[=22=]050\fg:][=22=]2[=22=]0Aߞ,3Q\t[=22=]0[=22=]0[=22=]0[=22=]0[=22=]0[=22=]0[=22=]0[=22=]0"
我正在尝试将此数据(存储在 std::stringstream strs
中)上传到使用 UTF8
编码的 PostgreSQL 数据库并上传到 byte_info
列,但 bytea
使用libpqxx图书馆:
pqxx::connection Con("My con information");
pqxx::work W(Con);
W.exec("UPDATE " + tableName + " SET byte_info =" + strs.str() + " WHERE id = 1;");
W.commit();
但我得到的只是这个错误:
ERROR: invalid byte sequence for encoding "UTF8": 0xfc
我在这里遗漏了什么或做错了什么?
根据 PostgreSQL 手册bytea,有两种写包含二进制流的语句的方法。
对于字符串"\x4A\xC3\xA1\xF2\x18"
- 十六进制
bytea
:E'\x4AC3A1F218'
- escaped
bytea
:E'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();
}
假设你有 ss
作为 stringstream
和一些数据(为了演示,我们只是在这里 ramdom 它)
std::stringstream ss;
{ // random bits for length of 1024
std::string str(1024,'[=11=]');
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 << "\n\n";
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;