From 14337cf5b302c5385f0ae1393caf6df7e83fc539 Mon Sep 17 00:00:00 2001
From: znone <glyc@sina.com.cn>
Date: Sat, 07 Dec 2019 06:52:19 +0000
Subject: [PATCH] 1. 允许绑定字段到std::optional和std::any 2. 增加函数bind_fields可以一次绑定到多个字段 3. 查询函数返回数据库对象自身,以支持链式调用

---
 include/qtl_mysql.hpp |  237 ++++++++++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 169 insertions(+), 68 deletions(-)

diff --git a/include/qtl_mysql.hpp b/include/qtl_mysql.hpp
index 834e3c1..8174bca 100644
--- a/include/qtl_mysql.hpp
+++ b/include/qtl_mysql.hpp
@@ -10,6 +10,7 @@
 #include <string>
 #include <vector>
 #include <array>
+#include <utility>
 #include <functional>
 #include <algorithm>
 #include <system_error>
@@ -83,8 +84,9 @@
 	void bind(bool& v)
 	{
 		init();
-		buffer_type = MYSQL_TYPE_TINY;
+		buffer_type = MYSQL_TYPE_BIT;
 		buffer = &v;
+		buffer_length = 1;
 	}
 	void bind(int8_t& v)
 	{
@@ -275,6 +277,71 @@
 	}
 };
 
+struct time : public MYSQL_TIME
+{
+	time()
+	{
+		memset(this, 0, sizeof(MYSQL_TIME));
+		time_type = MYSQL_TIMESTAMP_NONE;
+	}
+	time(const struct tm& tm)
+	{
+		memset(this, 0, sizeof(MYSQL_TIME));
+		year = tm.tm_year + 1900;
+		month = tm.tm_mon + 1;
+		day = tm.tm_mday;
+		hour = tm.tm_hour;
+		minute = tm.tm_min;
+		second = tm.tm_sec;
+		time_type = MYSQL_TIMESTAMP_DATETIME;
+	}
+	time(time_t value)
+	{
+		struct tm tm;
+#if defined(_MSC_VER)
+		localtime_s(&tm, &value);
+#elif defined(_POSIX_VERSION)
+		localtime_r(&value, &tm);
+#else
+		tm = *localtime(&value);
+#endif
+		new(this)time(tm);
+	}
+	time(const time& src)
+	{
+		memcpy(this, &src, sizeof(MYSQL_TIME));
+	}
+	time& operator=(const time& src)
+	{
+		if (this != &src)
+			memcpy(this, &src, sizeof(MYSQL_TIME));
+		return *this;
+	}
+
+	static time now()
+	{
+		time_t value;
+		::time(&value);
+		return time(value);
+	}
+
+	time_t as_tm(struct tm& tm) const
+	{
+		tm.tm_year = year - 1900;
+		tm.tm_mon = month - 1;
+		tm.tm_mday = day;
+		tm.tm_hour = hour;
+		tm.tm_min = minute;
+		tm.tm_sec = second;
+		return mktime(&tm);
+	}
+	time_t get_time() const
+	{
+		struct tm tm;
+		return as_tm(tm);
+	}
+};
+
 class base_statement
 {
 protected:
@@ -409,7 +476,8 @@
 		if (m_result)
 		{
 			bind(m_binders[index], std::forward<Type>(value));
-			m_binderAddins[index].m_after_fetch = if_null<typename std::remove_reference<Type>::type>(value);
+			m_binderAddins[index].m_after_fetch = 
+				if_null<typename std::remove_reference<Type>::type>(value);
 		}
 	}
 
@@ -518,6 +586,104 @@
 		}
 	}
 
+#ifdef _QTL_ENABLE_CPP17
+
+	template<typename T>
+	inline void bind_field(size_t index, std::optional<T>&& value)
+	{
+		if (m_result)
+		{
+			qtl::bind_field(*this, index, *value);
+			binder_addin& addin = m_binderAddins[index];
+			auto fetch_fun = addin.m_after_fetch;
+			addin.m_after_fetch = [&addin, fetch_fun, &value](const binder& b) {
+				if (fetch_fun) fetch_fun(b);
+				if (*b.is_null) value.reset();
+			};
+		}
+	}
+
+	inline void bind_field(size_t index, std::any&& value)
+	{
+		if (m_result)
+		{
+			MYSQL_FIELD* field = mysql_fetch_field_direct(m_result, (unsigned int)index);
+			if (field == nullptr) throw_exception();
+			switch (field->type)
+			{
+			case MYSQL_TYPE_NULL:
+				value.reset();
+				break;
+			case MYSQL_TYPE_BIT:
+				value.emplace<bool>();
+				bind_field(index, std::any_cast<bool&>(value));
+				break;
+			case MYSQL_TYPE_TINY:
+				value.emplace<int8_t>();
+				bind_field(index, std::any_cast<int8_t&>(value));
+				break;
+			case MYSQL_TYPE_SHORT:
+				value.emplace<int16_t>();
+				bind_field(index, std::any_cast<int16_t&>(value));
+				break;
+			case MYSQL_TYPE_LONG:
+				value.emplace<int32_t>();
+				bind_field(index, std::any_cast<int32_t&>(value));
+				break;
+			case MYSQL_TYPE_LONGLONG:
+				value.emplace<int64_t>();
+				bind_field(index, std::any_cast<int64_t&>(value));
+				break;
+			case MYSQL_TYPE_FLOAT:
+				value.emplace<float>();
+				bind_field(index, std::any_cast<float&>(value));
+				break;
+			case MYSQL_TYPE_DOUBLE:
+				value.emplace<double>();
+				bind_field(index, std::any_cast<double&>(value));
+				break;
+			case MYSQL_TYPE_DATE:
+			case MYSQL_TYPE_TIME:
+			case MYSQL_TYPE_DATETIME:
+			case MYSQL_TYPE_TIMESTAMP:
+			case MYSQL_TYPE_TIMESTAMP2:
+			case MYSQL_TYPE_DATETIME2:
+			case MYSQL_TYPE_TIME2:
+				value.emplace<qtl::mysql::time>();
+				bind_field(index, std::any_cast<qtl::mysql::time&>(value));
+				break;
+			case MYSQL_TYPE_VARCHAR:
+			case MYSQL_TYPE_VAR_STRING:
+			case MYSQL_TYPE_STRING:
+			case MYSQL_TYPE_ENUM:
+			case MYSQL_TYPE_JSON:
+			case MYSQL_TYPE_DECIMAL:
+			case MYSQL_TYPE_NEWDECIMAL:
+			case MYSQL_TYPE_GEOMETRY:
+				value.emplace<std::string>();
+				bind_field(index, qtl::bind_string(std::any_cast<std::string&>(value)));
+				break;
+			case MYSQL_TYPE_TINY_BLOB:
+			case MYSQL_TYPE_MEDIUM_BLOB:
+			case MYSQL_TYPE_BLOB:
+			case MYSQL_TYPE_LONG_BLOB:
+				value.emplace<blobbuf>();
+				bind_field(index, std::forward<blobbuf>(std::any_cast<blobbuf&>(value)));
+				break;
+			default:
+				throw mysql::error(CR_UNSUPPORTED_PARAM_TYPE, "Unsupported field type");
+			}
+			binder_addin& addin = m_binderAddins[index];
+			auto fetch_fun = addin.m_after_fetch;
+			addin.m_after_fetch = [&addin, fetch_fun, &value](const binder& b) {
+				if (fetch_fun) fetch_fun(b);
+				if (*b.is_null) value.reset();
+			};
+		}
+	}
+
+#endif // C++17
+
 	void close()
 	{
 		if (m_result)
@@ -571,7 +737,7 @@
 	template<typename Value>
 	struct if_null
 	{
-		if_null(Value& value, Value&& def=Value()) : m_value(value), m_def(std::move(def)) { }
+		explicit if_null(Value& value, Value&& def=Value()) : m_value(value), m_def(std::move(def)) { }
 		void operator()(const binder& b)
 		{
 			if(*b.is_null) m_value=m_def;
@@ -1000,71 +1166,6 @@
 
 #endif //MariaDB
 
-};
-
-struct time : public MYSQL_TIME
-{
-	time() 
-	{
-		memset(this, 0, sizeof(MYSQL_TIME));
-		time_type=MYSQL_TIMESTAMP_NONE;
-	}
-	time(const struct tm& tm)
-	{
-		memset(this, 0, sizeof(MYSQL_TIME));
-		year=tm.tm_year+1900;
-		month=tm.tm_mon+1;
-		day=tm.tm_mday;
-		hour=tm.tm_hour;
-		minute=tm.tm_min;
-		second=tm.tm_sec;
-		time_type=MYSQL_TIMESTAMP_DATETIME;
-	}
-	time(time_t value)
-	{
-		struct tm tm;
-#if defined(_MSC_VER)
-		localtime_s(&tm, &value);
-#elif defined(_POSIX_VERSION)
-		localtime_r(&value, &tm);
-#else
-		tm=*localtime(&value);
-#endif
-		new(this)time(tm);
-	}
-	time(const time& src)
-	{
-		memcpy(this, &src, sizeof(MYSQL_TIME));
-	}
-	time& operator=(const time& src)
-	{
-		if(this!=&src)
-			memcpy(this, &src, sizeof(MYSQL_TIME));
-		return *this;
-	}
-
-	static time now()
-	{
-		time_t value;
-		::time(&value);
-		return time(value);
-	}
-
-	time_t as_tm(struct tm& tm) const
-	{
-		tm.tm_year=year-1900;
-		tm.tm_mon=month-1;
-		tm.tm_mday=day;
-		tm.tm_hour=hour;
-		tm.tm_min=minute;
-		tm.tm_sec=second;
-		return mktime(&tm);
-	}
-	time_t get_time() const
-	{
-		struct tm tm;
-		return as_tm(tm);
-	}
 };
 
 #if MARIADB_VERSION_ID >= 100000

--
Gitblit v1.9.3