diff --git a/core/src/cats/bdb_postgresql.h b/core/src/cats/bdb_postgresql.h index 7dd719aa502..655fdafe4ce 100644 --- a/core/src/cats/bdb_postgresql.h +++ b/core/src/cats/bdb_postgresql.h @@ -46,6 +46,10 @@ class BareosDbPostgresql : public BareosDbPrivateInterface { const char* old, int len) override; char* EscapeObject(JobControlRecord* jcr, char* old, int len) override; + unsigned char* EscapeObject(const unsigned char* old, + std::size_t old_len, + std::size_t& new_len) override; + void FreeEscapedObjectMemory(unsigned char* obj) override; void UnescapeObject(JobControlRecord* jcr, char* from, int32_t expected_len, diff --git a/core/src/cats/cats.h b/core/src/cats/cats.h index 0a2fc764b0f..c71d6c20689 100644 --- a/core/src/cats/cats.h +++ b/core/src/cats/cats.h @@ -1031,6 +1031,14 @@ class BareosDb : public BareosDbQueryEnum { const char* old, int len); virtual char* EscapeObject(JobControlRecord* jcr, char* old, int len); + virtual unsigned char* EscapeObject(const unsigned char* old, + std::size_t old_len, + std::size_t& new_len) + { + return nullptr; + } + virtual void FreeEscapedObjectMemory(unsigned char* obj) {} + virtual void UnescapeObject(JobControlRecord* jcr, char* from, int32_t expected_len, diff --git a/core/src/cats/postgresql.cc b/core/src/cats/postgresql.cc index f994983b2eb..fdf57244adf 100644 --- a/core/src/cats/postgresql.cc +++ b/core/src/cats/postgresql.cc @@ -400,6 +400,19 @@ char* BareosDbPostgresql::EscapeObject(JobControlRecord* jcr, return (char*)esc_obj; } +unsigned char* BareosDbPostgresql::EscapeObject(const unsigned char* old, + std::size_t old_len, + std::size_t& new_len) +{ + return PQescapeByteaConn(db_handle_, old, old_len, std::addressof(new_len)); +} + +void BareosDbPostgresql::FreeEscapedObjectMemory(unsigned char* obj) +{ + PQfreemem(obj); +} + + /** * Unescape binary object so that PostgreSQL is happy * diff --git a/core/src/dird/dbcopy/column_description.cc b/core/src/dird/dbcopy/column_description.cc index 870a8303fec..ea524775aec 100644 --- a/core/src/dird/dbcopy/column_description.cc +++ b/core/src/dird/dbcopy/column_description.cc @@ -46,12 +46,12 @@ ColumnDescription::ColumnDescription(const char* column_name_in, } } -static void no_conversion(FieldData& fd) +static void no_conversion(BareosDb* db, FieldData& fd) { fd.data_pointer = fd.data_pointer ? fd.data_pointer : ""; } -static void timestamp_conversion_postgresql(FieldData& fd) +static void timestamp_conversion_postgresql(BareosDb* db, FieldData& fd) { static const char* dummy_timepoint = "1970-01-01 00:00:00"; if (!fd.data_pointer) { @@ -63,11 +63,14 @@ static void timestamp_conversion_postgresql(FieldData& fd) } } -static void string_conversion_postgresql(FieldData& fd) +static void string_conversion_postgresql(BareosDb* db, FieldData& fd) { if (fd.data_pointer) { std::size_t len{strlen(fd.data_pointer)}; fd.converted_data.resize(len * 2 + 1); +#if 1 + db->EscapeString(nullptr, fd.converted_data.data(), fd.data_pointer, len); +#else char* n = fd.converted_data.data(); const char* o = fd.data_pointer; @@ -89,12 +92,23 @@ static void string_conversion_postgresql(FieldData& fd) } } *n = 0; +#endif fd.data_pointer = fd.converted_data.data(); } else { fd.data_pointer = ""; } } +static void bytea_conversion_postgresql(BareosDb* db, FieldData& fd) +{ + std::size_t new_len{}; + auto old = reinterpret_cast(fd.data_pointer); + auto obj = db->EscapeObject(old, strlen(fd.data_pointer), new_len); + fd.converted_data.resize(new_len + 1); + memcpy(fd.converted_data.data(), obj, new_len + 1); + db->FreeEscapedObjectMemory(obj); +} + const DataTypeConverterMap ColumnDescriptionMysql::db_import_converter_map{ {"bigint", no_conversion}, {"binary", no_conversion}, {"blob", no_conversion}, {"char", no_conversion}, @@ -121,7 +135,7 @@ ColumnDescriptionMysql::ColumnDescriptionMysql(const char* column_name_in, const DataTypeConverterMap ColumnDescriptionPostgresql::db_export_converter_map{ {"bigint", no_conversion}, - {"bytea", string_conversion_postgresql}, + {"bytea", bytea_conversion_postgresql}, {"character", string_conversion_postgresql}, {"integer", no_conversion}, {"numeric", no_conversion}, diff --git a/core/src/dird/dbcopy/column_description.h b/core/src/dird/dbcopy/column_description.h index 07b6fb8ca9d..223bf4c5f7e 100644 --- a/core/src/dird/dbcopy/column_description.h +++ b/core/src/dird/dbcopy/column_description.h @@ -27,6 +27,7 @@ #include class FieldData; +class BareosDb; class ColumnDescription { public: @@ -38,12 +39,14 @@ class ColumnDescription { std::string column_name; std::string data_type; std::size_t character_maximum_length{}; - std::function db_export_converter{}; - std::function db_import_converter{}; + + using ConverterCallback = std::function; + ConverterCallback db_export_converter{}; + ConverterCallback db_import_converter{}; }; using DataTypeConverterMap = - std::map>; + std::map; class ColumnDescriptionMysql : public ColumnDescription { public: diff --git a/core/src/dird/dbcopy/database_export_postgresql.cc b/core/src/dird/dbcopy/database_export_postgresql.cc index ff3f79866a8..22f2600f59f 100644 --- a/core/src/dird/dbcopy/database_export_postgresql.cc +++ b/core/src/dird/dbcopy/database_export_postgresql.cc @@ -84,7 +84,7 @@ void DatabaseExportPostgresql::CopyRow(RowData& origin_data) if (i < origin_data.row.size()) { query_values += "'"; - column_description->db_export_converter(origin_data.row[i]); + column_description->db_export_converter(db_, origin_data.row[i]); query_values += origin_data.row[i].data_pointer; query_values += "',"; } else { diff --git a/core/src/dird/dbcopy/database_import_mysql.cc b/core/src/dird/dbcopy/database_import_mysql.cc index 894b99b008d..a8cd3ef0cf8 100644 --- a/core/src/dird/dbcopy/database_import_mysql.cc +++ b/core/src/dird/dbcopy/database_import_mysql.cc @@ -69,8 +69,9 @@ struct ResultHandlerContext { ResultHandlerContext( const DatabaseColumnDescriptions::VectorOfColumnDescriptions& c, RowData& d, - DatabaseExport& e) - : column_descriptions(c), row_data(d), exporter(e) + DatabaseExport& e, + BareosDb* db_in) + : column_descriptions(c), row_data(d), exporter(e), db(db_in) { } const DatabaseColumnDescriptions::VectorOfColumnDescriptions& @@ -78,6 +79,7 @@ struct ResultHandlerContext { RowData& row_data; DatabaseExport& exporter; uint64_t counter{}; + BareosDb* db; }; void DatabaseImportMysql::RunQuerySelectAllRows( @@ -107,7 +109,7 @@ void DatabaseImportMysql::RunQuerySelectAllRows( } RowData row_data(t.column_descriptions, t.table_name); - ResultHandlerContext ctx(t.column_descriptions, row_data, exporter); + ResultHandlerContext ctx(t.column_descriptions, row_data, exporter, db_); if (!db_->SqlQuery(query.c_str(), ResultHandler, &ctx)) { std::cout << "Could not import table: " << t.table_name << std::endl; @@ -154,7 +156,7 @@ void DatabaseImportMysql::FillRowWithDatabaseResult(ResultHandlerContext* r, for (int i = 0; i < fields; i++) { RowData& row_data = r->row_data; row_data.row[i].data_pointer = row[i]; - r->column_descriptions[i]->db_import_converter(row_data.row[i]); + r->column_descriptions[i]->db_import_converter(r->db, row_data.row[i]); } }