-2
4

1 回答 1

1

According to manual of PostgreSQL bytea, there are 2 ways for writing a statement containing binary stream.

For a string "\x4A\xC3\xA1\xF2\x18"

  1. hex bytea : E'\\x4AC3A1F218'
  2. escaped bytea : E'J\\303\\241\\362\\030'::bytea -- escape \ as \\\\, escape ' as \' and escape non-printable as \\three-digit-octal

So you can come up with functions like these.

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

}

Suppose you have ss as stringstream with some data (for demo, we just ramdom it here)

  std::stringstream ss;
  { // random bits for length of 1024
    std::string str(1024,'\0');
    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);
  }

You can write statement using those functions

  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";

Print

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

于 2018-08-05T06:48:28.540 回答