From ab9dec8671eeb90230064474cf86c49c69fd8e10 Mon Sep 17 00:00:00 2001
From: znone <glyc@sina.com.cn>
Date: Wed, 27 Jun 2018 06:54:45 +0000
Subject: [PATCH] 允许用字段名绑定数据(会影响性能) 允许对同一个数据结构进行不同的绑定

---
 include/qtl_sqlite.hpp |   13 ++++
 include/qtl_common.hpp |   73 +++++++++++++++++++++++-
 include/qtl_odbc.hpp   |   22 +++++++
 include/qtl_mysql.hpp  |   29 +++++++--
 4 files changed, 125 insertions(+), 12 deletions(-)

diff --git a/include/qtl_common.hpp b/include/qtl_common.hpp
index e0eb972..eb616a1 100644
--- a/include/qtl_common.hpp
+++ b/include/qtl_common.hpp
@@ -218,6 +218,66 @@
 	fun(value, temp);
 }
 
+template<typename Command, typename T, typename=typename std::enable_if<!std::is_reference<T>::value>::type>
+inline void bind_field(Command& command, const char* name, T&& value)
+{
+	size_t index=command.find_field(name);
+	if(index==-1)
+		value=T();
+	else
+		command.bind_field(index, std::forward<T>(value));
+}
+
+template<typename Command, typename T>
+inline void bind_field(Command& command, const char* name, T& value)
+{
+	size_t index=command.find_field(name);
+	if(index==-1)
+		value=T();
+	else
+		bind_field(command, index, std::forward<T>(value));
+}
+
+template<typename FieldType, typename Command, typename BindType>
+inline void bind_field(Command& command, const char* name, BindType& value)
+{
+	size_t index=command.find_field(name);
+	if(index==-1)
+		value=BindType();
+	else
+		bind_field<FieldType>(command, index, value);
+}
+
+template<typename FieldType, typename Command, typename BindType, typename CastFun>
+inline void bind_field(Command& command, const char* name, BindType& value, CastFun&& fun)
+{
+	size_t index=command.find_field(name);
+	if(index==-1)
+		value=BindType();
+	else
+		bind_field<FieldType>(command, index, value, fun);
+}
+
+template<typename Command>
+inline void bind_field(Command& command, const char* name, char* value, size_t length)
+{
+	size_t index=command.find_field(name);
+	if(index==-1)
+		value[0]='\0';
+	else
+		command.bind_field(index, value, length);
+}
+
+template<typename Command>
+inline void bind_field(Command& command, const char* name, wchar_t* value, size_t length)
+{
+	size_t index=command.find_field(name);
+	if(index==-1)
+		value[0]='\0';
+	else
+		command.bind_field(index, value, length);
+}
+
 namespace detail
 {
 
@@ -404,7 +464,7 @@
 	void operator()(std::tuple<Types...>&& params) const
 	{
 		typedef typename std::remove_reference<typename std::tuple_element<0, tuple_type>::type>::type param_type;
-		bind_field(m_command, 0, std::forward<param_type>(std::get<0>(std::forward<tuple_type>(params))));
+		bind_field(m_command, static_cast<size_t>(0), std::forward<param_type>(std::get<0>(std::forward<tuple_type>(params))));
 	}
 private:
 	typedef std::tuple<Types...> tuple_type;
@@ -554,7 +614,7 @@
 {
 	inline void operator()(Command& command, T&& value) const
 	{
-		bind_field(command, 0, std::forward<typename std::remove_reference<T>::type>(value));
+		bind_field(command, static_cast<size_t>(0), std::forward<typename std::remove_reference<T>::type>(value));
 	}
 };
 
@@ -573,11 +633,16 @@
 {
 	void operator()(Command& command, std::pair<Type1, Type2>&& values) const
 	{
-		bind_field(command, 0, std::forward<Type1>(values.first));
-		bind_field(command, 1, std::forward<Type2>(values.second));
+		bind_field(command, static_cast<size_t>(0), std::forward<Type1>(values.first));
+		bind_field(command, static_cast<size_t>(1), std::forward<Type2>(values.second));
 	}
 };
 
+template<typename T, typename Tag>
+struct record_with_tag : public T
+{
+};
+
 template<typename Command, typename T>
 inline void bind_record(Command& command, T&& value)
 {
diff --git a/include/qtl_mysql.hpp b/include/qtl_mysql.hpp
index bf0ee64..e0cb34f 100644
--- a/include/qtl_mysql.hpp
+++ b/include/qtl_mysql.hpp
@@ -195,8 +195,8 @@
 {
 public:
 	error() : m_error(0) { }
-	error(int err, const char* errmsg) : m_error(err), m_errmsg(errmsg) { }
-	explicit error(int err) : m_error(err), m_errmsg(ER(err)) { }
+	error(unsigned int err, const char* errmsg) : m_error(err), m_errmsg(errmsg) { }
+	explicit error(unsigned int err) : m_error(err), m_errmsg(ER(err)) { }
 	explicit error(statement& stmt);
 	explicit error(database& db);
 	error(const error& src) = default;
@@ -204,7 +204,7 @@
 	int code() const throw() { return m_error; }
 	virtual const char* what() const throw() override { return m_errmsg.data(); }
 private:
-	int m_error;
+	unsigned int m_error;
 	std::string m_errmsg;
 };
 
@@ -444,6 +444,19 @@
 		return m_binderAddins[index].m_isNull!=0;
 	}
 
+	size_t find_field(const char* name) const
+	{
+		if(m_result)
+		{
+			for(size_t i=0; i!=m_result->field_count; i++)
+			{
+				if(strncmp(m_result->fields[i].name, name, m_result->fields[i].name_length)==0)
+					return i;
+			}
+		}
+		return -1;
+	}
+
 	void close()
 	{
 		if(m_result)
@@ -512,11 +525,11 @@
 		return &m_binders[index];
 	}
 
-	unsigned int error() 
+	unsigned int error() const
 	{
 		return mysql_stmt_errno(m_stmt);
 	}
-	const char* errmsg()
+	const char* errmsg() const
 	{
 		return mysql_stmt_error(m_stmt);
 	}
@@ -577,7 +590,7 @@
 class database final : public qtl::base_database<database, statement>
 {
 public:
-	typedef error exception_type;
+	typedef mysql::error exception_type;
 
 	database()
 	{
@@ -654,11 +667,11 @@
 		return m_mysql->db;
 	}
 
-	unsigned int error() 
+	unsigned int error() const
 	{
 		return mysql_errno(m_mysql);
 	}
-	const char* errmsg()
+	const char* errmsg() const
 	{
 		return mysql_error(m_mysql);
 	}
diff --git a/include/qtl_odbc.hpp b/include/qtl_odbc.hpp
index 99a4c49..c31c620 100644
--- a/include/qtl_odbc.hpp
+++ b/include/qtl_odbc.hpp
@@ -538,6 +538,26 @@
 		return count;
 	}
 
+	size_t find_field(const char* name) const
+	{
+		SQLSMALLINT count=0;
+		verify_error(SQLNumResultCols(m_handle, &count));
+		for(SQLSMALLINT i=0; i!=count; i++)
+		{
+			SQLCHAR field_name[256]={0};
+			SQLSMALLINT name_length=0;
+			SQLSMALLINT data_type;
+			SQLULEN column_size;
+			SQLSMALLINT digits;
+			SQLSMALLINT nullable;
+			verify_error(SQLDescribeCol(m_handle, i, field_name, sizeof(field_name), &name_length,
+				&data_type, &column_size, &digits, &nullable));
+			if(strncmp((char*)field_name, name, name_length)==0)
+				return i;
+		}
+		return -1;
+	}
+
 	/*
 		ODBC do not support this function, but you can use query to instead it:
 		For MS SQL Server: SELECT @@IDENTITY;
@@ -595,6 +615,8 @@
 class database : public object<SQL_HANDLE_DBC>, public qtl::base_database<database, statement>
 {
 public:
+	typedef odbc::error exception_type;
+
 	explicit database(environment& env) : object(env.handle()), m_opened(false)
 	{
 	}
diff --git a/include/qtl_sqlite.hpp b/include/qtl_sqlite.hpp
index 66cfb0d..512d942 100644
--- a/include/qtl_sqlite.hpp
+++ b/include/qtl_sqlite.hpp
@@ -215,6 +215,17 @@
 		bind_field(index, value.data(), value.size());
 	}
 
+	size_t find_field(const char* name) const
+	{
+		size_t count=get_column_count();
+		for(size_t i=0; i!=count; i++)
+		{
+			if(strcmp(get_column_name(i), name)==0)
+				return i;
+		}
+		return -1;
+	}
+
 	bool fetch()
 	{
 		m_fetch_result=sqlite3_step(m_stmt);
@@ -374,6 +385,8 @@
 class database final : public qtl::base_database<database, statement>
 {
 public:	
+	typedef sqlite::error exception_type;
+
 	database() : m_db(NULL) { }
 	~database() { close(); }
 	database(const database&) = delete;

--
Gitblit v1.9.3