summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/dbTypes.h4
-rw-r--r--lib/output/pq/writePqCopyStrm.cpp12
-rw-r--r--test/helpers.cpp15
-rw-r--r--test/helpers.h13
-rw-r--r--test/test-postgresql.cpp64
5 files changed, 104 insertions, 4 deletions
diff --git a/lib/dbTypes.h b/lib/dbTypes.h
index 31793e4..f49c929 100644
--- a/lib/dbTypes.h
+++ b/lib/dbTypes.h
@@ -13,10 +13,10 @@ struct timespec;
namespace MyGrate {
template<typename T> struct printer;
template<> struct printer<double> {
- constexpr static const char * const fmt {"%f"};
+ constexpr static const char * const fmt {"%g"};
};
template<> struct printer<float> {
- constexpr static const char * const fmt {"%f"};
+ constexpr static const char * const fmt {"%g"};
};
template<> struct printer<int8_t> {
constexpr static const char * const fmt {"%hhd"};
diff --git a/lib/output/pq/writePqCopyStrm.cpp b/lib/output/pq/writePqCopyStrm.cpp
index dd402e7..4664e6b 100644
--- a/lib/output/pq/writePqCopyStrm.cpp
+++ b/lib/output/pq/writePqCopyStrm.cpp
@@ -59,7 +59,7 @@ namespace MyGrate::Output::Pq {
fwrite(pos, esc - pos, 1, out);
pos = esc;
}
- while (pos != v.end()) {
+ while (pos != v.end() && std::iscntrl(*pos)) {
fprintf(out, "\\%03o", *pos);
pos++;
}
@@ -74,9 +74,17 @@ namespace MyGrate::Output::Pq {
void
WritePqCopyStream::operator()(Blob v) const
{
+ static constexpr const auto hex {[] {
+ std::array<std::array<char, 2>, 256> h {};
+ std::array<char, 16> hc {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+ for (int x {}; x < 256; x += 1) {
+ h[x] = {hc[x >> 4], hc[x & 0xF]};
+ }
+ return h;
+ }()};
fputs("\\\\x", out);
std::for_each(v.begin(), v.end(), [this](auto b) {
- fprintf(out, "%02hhx", (uint8_t)b);
+ fwrite(hex[(uint8_t)b].data(), 2, 1, out);
});
}
}
diff --git a/test/helpers.cpp b/test/helpers.cpp
new file mode 100644
index 0000000..f4fc030
--- /dev/null
+++ b/test/helpers.cpp
@@ -0,0 +1,15 @@
+#include "helpers.h"
+
+MemStream::MemStream() : out {nullptr}, len {}, s {open_memstream(&out, &len)} { }
+
+MemStream::~MemStream()
+{
+ fclose(s);
+ free(out);
+}
+
+void
+MemStream::flush()
+{
+ fflush(s);
+}
diff --git a/test/helpers.h b/test/helpers.h
index 59ae18d..87ef31d 100644
--- a/test/helpers.h
+++ b/test/helpers.h
@@ -3,8 +3,10 @@
#include <concepts>
#include <cstddef>
+#include <cstdio>
#include <ctime>
#include <iostream>
+#include <memory>
#include <optional>
inline constexpr std::byte operator""_b(const unsigned long long hex)
@@ -55,4 +57,15 @@ make_tm(int year, int mon, int day, int hr, int min, int sec)
return tm;
}
+struct MemStream {
+ MemStream();
+ virtual ~MemStream();
+
+ void flush();
+
+ char * out;
+ size_t len;
+ FILE * s;
+};
+
#endif
diff --git a/test/test-postgresql.cpp b/test/test-postgresql.cpp
index 15ba789..727e08c 100644
--- a/test/test-postgresql.cpp
+++ b/test/test-postgresql.cpp
@@ -1,6 +1,9 @@
#define BOOST_TEST_MODULE PostgreSQL
+#include <boost/mpl/list.hpp>
+#include <boost/test/data/test_case.hpp>
#include <boost/test/unit_test.hpp>
+#include "helpers.h"
#include "testdb-postgresql.h"
#include <cstddef>
#include <dbConn.h>
@@ -11,6 +14,7 @@
#include <helpers.h>
#include <memory>
#include <output/pq/pqConn.h>
+#include <output/pq/writePqCopyStrm.h>
#include <stdexcept>
#include <string_view>
#include <type_traits>
@@ -91,3 +95,63 @@ BOOST_AUTO_TEST_CASE(mock_schema)
auto rs = MyGrate::DbStmt<"SELECT COUNT(*) FROM mygrate.source">::execute(&mdb);
BOOST_CHECK_EQUAL(rs->at(0, 0).operator unsigned int(), 0);
}
+
+BOOST_FIXTURE_TEST_SUITE(ms, MemStream);
+
+BOOST_DATA_TEST_CASE(write_strings,
+ boost::unit_test::data::make({
+ std::make_tuple("", ""),
+ {"simple", "simple"},
+ {"simple with spaces", "simple with spaces"},
+ {"simple\twith\ttabs", "simple\\011with\\011tabs"},
+ {"\ttab start", "\\011tab start"},
+ {"tab end\t", "tab end\\011"},
+ {"tab\t\t\t\tmany", "tab\\011\\011\\011\\011many"},
+ }),
+ in, exp)
+{
+ MyGrate::Output::Pq::WritePqCopyStream c {s};
+ c(in);
+ flush();
+
+ BOOST_REQUIRE(out);
+ BOOST_CHECK_EQUAL(out, exp);
+}
+
+using IntTypes = boost::mpl::list<int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t, uint32_t, uint64_t>;
+BOOST_AUTO_TEST_CASE_TEMPLATE(write_ints, T, IntTypes)
+{
+ MyGrate::Output::Pq::WritePqCopyStream c {s};
+ c(T {1});
+ flush();
+
+ BOOST_REQUIRE(out);
+ BOOST_CHECK_EQUAL(len, 1);
+ BOOST_CHECK_EQUAL(out, "1");
+}
+
+using FloatTypes = boost::mpl::list<float, double>;
+BOOST_AUTO_TEST_CASE_TEMPLATE(write_floats, T, FloatTypes)
+{
+ MyGrate::Output::Pq::WritePqCopyStream c {s};
+ c(T {1.1});
+ flush();
+
+ BOOST_REQUIRE(out);
+ BOOST_CHECK_EQUAL(len, 3);
+ BOOST_CHECK_EQUAL(out, "1.1");
+}
+
+BOOST_AUTO_TEST_CASE(write_blob)
+{
+ MyGrate::Output::Pq::WritePqCopyStream c {s};
+ std::array<std::byte, 10> b {0x00_b, 0x10_b, 0x12_b, 0x30_b, 0x90_b, 0xaa_b, 0xff_b};
+ c(b);
+ flush();
+
+ BOOST_REQUIRE(out);
+ BOOST_CHECK_EQUAL(len, 23);
+ BOOST_CHECK_EQUAL(out, R"B(\\x0010123090AAFF000000)B");
+}
+
+BOOST_AUTO_TEST_SUITE_END();