diff -r cd9db43db120 -r 91cb012d779a src/ResultSet.cpp --- /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 . + */ + +#include +#include + +#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 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 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 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