src/ResultSet.cpp
branchv_0
changeset 36 91cb012d779a
child 43 7f396cdb9628
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ResultSet.cpp	Sun May 31 16:56:07 2020 +0200
@@ -0,0 +1,114 @@
+/**
+ * Relational pipes
+ * Copyright © 2020 František Kučera (Frantovo.cz, GlobalCode.info)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sql.h>
+#include <sqlext.h>
+
+#include "ResultSet.h"
+#include "OdbcCommon.h"
+
+namespace relpipe {
+namespace tr {
+namespace sql {
+
+ResultSet::ResultSet(void* statement) : statement(statement) {
+
+}
+
+ResultSet::~ResultSet() {
+	// freeHandle() is called in ~PreparedStatement()
+}
+
+bool ResultSet::next() {
+	SQLRETURN result = SQLFetch(statement);
+	if (OdbcCommon::isSuccessful(result)) return true;
+	else if (result == SQL_NO_DATA) return false;
+	else throw SqlException(L"Unable to fetch next record", result, SQL_HANDLE_STMT, statement);
+}
+
+relpipe::writer::boolean_t ResultSet::getBoolean(unsigned short columnNumber, bool* isNull) {
+	throw SqlException(L"not yet implemented: getBoolean()");
+}
+
+relpipe::writer::integer_t ResultSet::getInteger(unsigned short columnNumber, bool* isNull) {
+	throw SqlException(L"not yet implemented: getInteger()");
+
+}
+
+relpipe::writer::string_t ResultSet::getString(unsigned short columnNumber, bool* isNull) {
+	SQLCHAR uselessBuffer; // just to get stringLength – ODBC does not eat nullptr
+	SQLLEN stringLength = -1;
+	SQLRETURN result = SQLGetData(statement, columnNumber, SQL_C_CHAR, &uselessBuffer, 0, &stringLength);
+	if (isNull) *isNull = stringLength == SQL_NULL_DATA;
+	if (stringLength == SQL_NULL_DATA) {
+		return L"";
+	} else if (stringLength >= 0) {
+		std::string value;
+		value.reserve(stringLength);
+		result = SQLGetData(statement, columnNumber, SQL_C_CHAR, (SQLCHAR*) value.c_str(), value.capacity() + 1, &stringLength); // trailing null byte = + 1
+		if (OdbcCommon::isSuccessful(result)) return convertor.from_bytes(value.c_str());
+	}
+	throw SqlException(L"Unable to get string value", result, SQL_HANDLE_STMT, statement);
+}
+
+ResultSet::MetaData* ResultSet::getMetaData() {
+	SQLRETURN result;
+	SQLSMALLINT columnCount;
+	std::vector<ResultSet::MetaData::ColumnDescriptor> columnDescriptors;
+
+	result = SQLNumResultCols(statement, &columnCount);
+	if (OdbcCommon::isNotSuccessful(result)) throw SqlException(L"Unable to get column count", result, SQL_HANDLE_STMT, statement);
+
+	for (SQLSMALLINT columnNumber = 1; columnNumber <= columnCount; columnNumber++) {
+		ResultSet::MetaData::ColumnDescriptor columnDescriptor;
+		std::string nameBuffer; // TODO: use rather vector<char> instead of string.c_str()?
+		nameBuffer.reserve(100); // TODO: max column name length?
+		SQLSMALLINT nameLength;
+		SQLSMALLINT dataType;
+		SQLULEN columnSize;
+		SQLSMALLINT decimalDigits;
+		SQLSMALLINT nullable;
+		result = SQLDescribeCol(statement, columnNumber, (SQLCHAR*) nameBuffer.c_str(), nameBuffer.capacity(), &nameLength, &dataType, &columnSize, &decimalDigits, &nullable);
+		if (OdbcCommon::isNotSuccessful(result)) throw SqlException(L"Unable describe column", result, SQL_HANDLE_STMT, statement);
+		columnDescriptor.name = convertor.from_bytes(nameBuffer.c_str());
+		//columnDescriptor.type = … // FIXME: support also other types than string
+		columnDescriptors.emplace_back(columnDescriptor);
+	}
+
+	return new MetaData(columnCount, columnDescriptors);
+}
+
+ResultSet::MetaData::MetaData(unsigned short columnCount, std::vector<ColumnDescriptor> columnDescriptors) : columnCount(columnCount), columnDescriptors(columnDescriptors) {
+}
+
+ResultSet::MetaData::~MetaData() {
+}
+
+unsigned short ResultSet::MetaData::getColumnCount() {
+	return columnCount;
+}
+
+ResultSet::MetaData::ColumnDescriptor ResultSet::MetaData::describeColumn(unsigned short columnNumber) {
+	if (columnNumber >= 1 && columnNumber <= columnCount) return columnDescriptors[columnNumber - 1];
+	else throw SqlException(L"Unable to describe column " + std::to_wstring(columnNumber) + L", out of bounds, column count is " + std::to_wstring(columnCount));
+}
+
+
+
+}
+}
+}
\ No newline at end of file