From a2b2faa6019572388248617d0ac740bde95feb74 Mon Sep 17 00:00:00 2001
From: znone <glyc@sina.com.cn>
Date: Fri, 26 Feb 2021 13:44:08 +0000
Subject: [PATCH] PostgreSQL: support binary data PostgreSQl: add database pool

---
 test/TestPostgres.cpp |  112 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 105 insertions(+), 7 deletions(-)

diff --git a/test/TestPostgres.cpp b/test/TestPostgres.cpp
index 983b084..eeab3f2 100644
--- a/test/TestPostgres.cpp
+++ b/test/TestPostgres.cpp
@@ -40,13 +40,15 @@
 {
 	this->id = 0;
 	TEST_ADD(TestPostgres::test_dual)
-		TEST_ADD(TestPostgres::test_clear)
-		TEST_ADD(TestPostgres::test_insert)
-		TEST_ADD(TestPostgres::test_select)
-		TEST_ADD(TestPostgres::test_update)
-		TEST_ADD(TestPostgres::test_insert2)
-		TEST_ADD(TestPostgres::test_iterator)
-		TEST_ADD(TestPostgres::test_any)
+	TEST_ADD(TestPostgres::test_clear)
+	TEST_ADD(TestPostgres::test_insert)
+	TEST_ADD(TestPostgres::test_select)
+	TEST_ADD(TestPostgres::test_update)
+	TEST_ADD(TestPostgres::test_insert2)
+	TEST_ADD(TestPostgres::test_iterator)
+	TEST_ADD(TestPostgres::test_insert_blob)
+	TEST_ADD(TestPostgres::test_select_blob)
+	TEST_ADD(TestPostgres::test_any)
 }
 
 inline void TestPostgres::connect(qtl::postgres::database& db)
@@ -188,6 +190,89 @@
 	}
 }
 
+void hex_string(char* dest, const unsigned char* bytes, size_t count)
+{
+	for (size_t i = 0; i != count; i++)
+	{
+		sprintf(&dest[i * 2], "%02X", bytes[i] & 0xFF);
+	}
+}
+
+void TestPostgres::test_insert_blob()
+{
+	qtl::postgres::database db;
+	connect(db);
+
+	try
+	{
+#ifdef _WIN32
+		const char filename[] = "C:\\windows\\explorer.exe";
+#else
+		const char filename[] = "/bin/sh";
+#endif //_WIN32
+		qtl::postgres::transaction trans(db);
+		qtl::postgres::large_object content = qtl::postgres::large_object::load(db.handle(), filename);
+		TEST_ASSERT_MSG(content.oid()>0, "Cannot open test file.");
+		fstream fs(filename, ios::binary | ios::in);
+		unsigned char md5[16] = { 0 };
+		char md5_hex[33] = { 0 };
+		get_md5(fs, md5);
+		hex_string(md5_hex, md5, sizeof(md5));
+		printf("MD5 of file %s: %s.\n", filename, md5_hex);
+
+		db.simple_execute("DELETE FROM test_blob");
+
+		fs.clear();
+		fs.seekg(0, ios::beg);
+		db.query_first("INSERT INTO test_blob (filename, content, md5) values($1, $2, $3) returning id",
+			forward_as_tuple(filename, content, qtl::const_blob_data(md5, sizeof(md5))), id);
+		content.close();
+		trans.commit();
+	}
+	catch (qtl::postgres::error& e)
+	{
+		ASSERT_EXCEPTION(e);
+	}
+}
+
+void TestPostgres::test_select_blob()
+{
+	qtl::postgres::database db;
+	connect(db);
+
+	try
+	{
+		const char dest_file[] = "explorer.exe";
+
+		unsigned char md5[16] = { 0 };
+		std::string source_file;
+		qtl::postgres::transaction trans(db);
+		qtl::postgres::large_object content;
+		qtl::const_blob_data md5_value;
+		db.query_first("SELECT filename, content, md5 FROM test_blob WHERE id=$1", make_tuple(id),
+			forward_as_tuple(source_file, content, qtl::blob_data(md5, sizeof(md5))));
+		if (content.is_open())
+		{
+			content.save(dest_file);
+			ifstream fs(dest_file, ios::binary | ios::in);
+			TEST_ASSERT_MSG(fs, "Cannot open test file.");
+			char md5_hex[33] = { 0 };
+			hex_string(md5_hex, md5, sizeof(md5));
+			printf("MD5 of file %s stored in database: %s.\n", source_file.data(), md5_hex);
+			fs.clear();
+			fs.seekg(0, ios::beg);
+			get_md5(fs, md5);
+			hex_string(md5_hex, md5, sizeof(md5));
+			printf("MD5 of file %s: %s.\n", dest_file, md5_hex);
+			content.close();
+		}
+	}
+	catch (qtl::postgres::error& e)
+	{
+		ASSERT_EXCEPTION(e);
+	}
+}
+
 void TestPostgres::test_any()
 {
 #ifdef _QTL_ENABLE_CPP17
@@ -218,6 +303,19 @@
 #endif
 }
 
+void TestPostgres::get_md5(std::istream& is, unsigned char* result)
+{
+	std::array<char, 64 * 1024> buffer;
+	MD5_CTX context;
+	MD5Init(&context);
+	while (!is.eof())
+	{
+		is.read(&buffer.front(), buffer.size());
+		MD5Update(&context, (unsigned char*)buffer.data(), (unsigned int)is.gcount());
+	}
+	MD5Final(result, &context);
+}
+
 int main(int argc, char* argv[])
 {
 	Test::TextOutput output(Test::TextOutput::Verbose);

--
Gitblit v1.9.3