--- /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