# HG changeset patch # User František Kučera # Date 1591269857 -7200 # Node ID c83119110c7b5ded9ec2e605d39be6809073973e # Parent 428c278af4bea2aaa37274980d4ebe4d5ceee76c support also boolean and integer data types, do not treat everything as mere strings diff -r 428c278af4be -r c83119110c7b src/PreparedStatement.cpp --- a/src/PreparedStatement.cpp Thu Jun 04 00:46:00 2020 +0200 +++ b/src/PreparedStatement.cpp Thu Jun 04 13:24:17 2020 +0200 @@ -58,8 +58,7 @@ void PreparedStatement::setBoolean(int parameterNumber, relpipe::reader::boolean_t value) { booleanParameters.emplace_back(value); - // TODO: review SQL_C_TINYINT - SQLRETURN result = SQLBindParameter(statement, parameterNumber, SQL_PARAM_INPUT, SQL_C_TINYINT, SQL_INTEGER, 0, 0, &booleanParameters.back(), 0, nullptr); + SQLRETURN result = SQLBindParameter(statement, parameterNumber, SQL_PARAM_INPUT, SQL_C_BIT, SQL_INTEGER, 0, 0, &booleanParameters.back(), 0, nullptr); if (OdbcCommon::isNotSuccessful(result)) throw SqlException(L"Unable to set boolean parameter in prepared statement", result, SQL_HANDLE_STMT, statement); } diff -r 428c278af4be -r c83119110c7b src/ResultSet.cpp --- a/src/ResultSet.cpp Thu Jun 04 00:46:00 2020 +0200 +++ b/src/ResultSet.cpp Thu Jun 04 13:24:17 2020 +0200 @@ -44,12 +44,18 @@ } relpipe::writer::boolean_t ResultSet::getBoolean(unsigned short columnNumber, bool* isNull) { - throw SqlException(L"not yet implemented: getBoolean()"); + relpipe::writer::string_t s = getString(columnNumber, isNull); + if (isNull && *isNull) return false; + else if (s == L"1" || s == L"true" || s == L"y" || s == L"yes" || s == L"TRUE" || s == L"Y" || s == L"YES") return true; + else if (s == L"0" || s == L"false" || s == L"n" || s == L"no" || s == L"FALSE" || s == L"N" || s == L"NO") return false; + else throw SqlException(L"Unable to parse „" + s + L"“ as boolean"); } relpipe::writer::integer_t ResultSet::getInteger(unsigned short columnNumber, bool* isNull) { - throw SqlException(L"not yet implemented: getInteger()"); - + // TODO: get integer directly from SQLGetData() without string conversion + relpipe::writer::string_t s = getString(columnNumber, isNull); + if (isNull && *isNull) return 0; + else return std::stol(s); } relpipe::writer::string_t ResultSet::getString(unsigned short columnNumber, bool* isNull) { @@ -85,10 +91,15 @@ 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 + + if (dataType == SQL_INTEGER || dataType == SQL_BIGINT) columnDescriptor.type = relpipe::writer::TypeId::INTEGER; + else if (dataType == SQL_BIT) columnDescriptor.type = relpipe::writer::TypeId::BOOLEAN; + columnDescriptors.emplace_back(columnDescriptor); } diff -r 428c278af4be -r c83119110c7b src/SqlHandler.h --- a/src/SqlHandler.h Thu Jun 04 00:46:00 2020 +0200 +++ b/src/SqlHandler.h Thu Jun 04 13:24:17 2020 +0200 @@ -117,7 +117,16 @@ while (resultSet->next()) { for (int columnNumber = 1; columnNumber <= columnCount; columnNumber++) { - relationalWriter->writeAttribute(resultSet->getString(columnNumber)); + // TODO: null values (when supported in the format) + if (metadata[columnNumber - 1].typeId == relpipe::writer::TypeId::BOOLEAN) { + auto booleanValue = resultSet->getBoolean(columnNumber); + relationalWriter->writeAttribute(&booleanValue, typeid (booleanValue)); + } else if (metadata[columnNumber - 1].typeId == relpipe::writer::TypeId::INTEGER) { + auto integerValue = resultSet->getInteger(columnNumber); + relationalWriter->writeAttribute(&integerValue, typeid (integerValue)); + } else { + relationalWriter->writeAttribute(resultSet->getString(columnNumber)); + } } } } @@ -146,8 +155,8 @@ } relpipe::writer::string_t toSQLType(relpipe::reader::TypeId typeId) { - if (typeId == relpipe::reader::TypeId::BOOLEAN) return L"integer"; // TODO: map selected values back to booleans or allow optional storage as string - else if (typeId == relpipe::reader::TypeId::INTEGER) return L"integer"; + if (typeId == relpipe::reader::TypeId::BOOLEAN) return L"integer"; // TODO: bit type might fit better, but needs more testing (support in various DBMS and their drivers) + else if (typeId == relpipe::reader::TypeId::INTEGER) return L"bigint"; else return L"text"; }