From 18b8205f3984bff211131f82e4c0a1e33886ea64 Mon Sep 17 00:00:00 2001
From: znone <glyc@sina.com.cn>
Date: Tue, 27 Aug 2019 12:35:52 +0000
Subject: [PATCH] 提供以标准流的方式直接操纵ODBC的BLOB字段

---
 include/qtl_odbc.hpp |   83 +++++++++++++++++++++++++++++++++++++++--
 1 files changed, 79 insertions(+), 4 deletions(-)

diff --git a/include/qtl_odbc.hpp b/include/qtl_odbc.hpp
index 0c8c482..94ed746 100644
--- a/include/qtl_odbc.hpp
+++ b/include/qtl_odbc.hpp
@@ -10,6 +10,7 @@
 #include <assert.h>
 #include <malloc.h>
 #include <limits.h>
+#include <stdint.h>
 
 #if !defined(_WIN32) || defined(__MINGW32__)
 #include <sys/time.h>
@@ -81,12 +82,62 @@
 		}
 	}
 
-protected:
-	SQLHANDLE m_handle;
 	void verify_error(SQLINTEGER code) const
 	{
-		if(code<0)
-			throw odbc::error(*this, code); 
+		if (code < 0)
+			throw odbc::error(*this, code);
+	}
+
+protected:
+	SQLHANDLE m_handle;
+};
+
+class blobbuf : public qtl::blobbuf
+{
+public:
+	blobbuf() : m_stmt(nullptr), m_field(0)
+	{
+	}
+	blobbuf(const blobbuf&) = default;
+	blobbuf& operator=(const blobbuf&) = default;
+	virtual ~blobbuf() { overflow(); }
+
+	void open(object<SQL_HANDLE_STMT>* stmt, SQLSMALLINT field, std::ios_base::openmode mode)
+	{
+		if (m_stmt && m_field)
+		{
+			overflow();
+		}
+
+		assert(stmt != SQL_NULL_HANDLE);
+		m_stmt = stmt;
+		m_field = field;
+		m_size = INTMAX_MAX;
+		init_buffer(mode);
+	}
+
+private:
+	object<SQL_HANDLE_STMT>* m_stmt;
+	SQLSMALLINT m_field;
+
+protected:
+	virtual bool read_blob(char* buffer, off_type& count, pos_type position) override
+	{
+		SQLLEN indicator=0;
+		SQLRETURN ret = SQLGetData(m_stmt->handle(), m_field + 1, SQL_C_BINARY, buffer, count, const_cast<SQLLEN*>(&indicator));
+		if (ret != SQL_NO_DATA)
+		{
+			count = (indicator > count) || (indicator == SQL_NO_TOTAL) ?
+				count : indicator;
+			m_stmt->verify_error(ret);
+			return true;
+		}
+		else return false;
+	}
+
+	virtual void write_blob(const char* buffer, size_t count) override
+	{
+		m_stmt->verify_error(SQLPutData(m_stmt->handle(), (SQLPOINTER)buffer, count));
 	}
 };
 
@@ -281,6 +332,21 @@
 		};
 	}
 
+	void bind_param(SQLUSMALLINT index, const blob_writer& param)
+	{
+		m_params[index].m_data = nullptr;
+		m_params[index].m_size = blob_buffer_size;
+		m_params[index].m_indicator = SQL_LEN_DATA_AT_EXEC(m_params[index].m_size);
+		verify_error(SQLBindParameter(m_handle, index + 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY,
+			INT_MAX, 0, &m_params[index], 0, &m_params[index].m_indicator));
+		m_params[index].m_after_fetch = [this, index, &param](const param_data& b) {
+			blobbuf buf;
+			buf.open(this, index, std::ios::out);
+			std::ostream s(&buf);
+			param(s);
+		};
+	}
+
 	void bind_field(SQLUSMALLINT index, bool&& v)
 	{
 		verify_error(SQLBindCol(m_handle, index+1, SQL_C_BIT, &v, 0, &m_params[index].m_indicator));
@@ -422,6 +488,15 @@
 		};
 	}
 
+	void bind_field(size_t index, blobbuf&& value)
+	{
+		m_params[index].m_data = nullptr;
+		m_params[index].m_size = 0;
+		m_params[index].m_after_fetch = [this, index, &value](const param_data& p) {
+			value.open(this, index, std::ios::in);
+		};
+	}
+
 	template<typename Type>
 	void bind_field(size_t index, indicator<Type>&& value)
 	{

--
Gitblit v1.9.3