From 4ab84b086d4af4f824f5f231cf7d97121ca23470 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 24 Aug 2018 10:02:15 +0100 Subject: Don't rely on libdbppcore's columns Also reduce risk of needing to resize at all by getting the octet size --- libodbcpp/odbc-modifycommand.cpp | 2 +- libodbcpp/odbc-selectcommand.cpp | 25 +++++++++++++++---------- libodbcpp/odbc-selectcommand.h | 3 +++ libodbcpp/unittests/testodbc.cpp | 15 +++++++++++++++ 4 files changed, 34 insertions(+), 11 deletions(-) (limited to 'libodbcpp') diff --git a/libodbcpp/odbc-modifycommand.cpp b/libodbcpp/odbc-modifycommand.cpp index 0eeca01..60bb7c4 100644 --- a/libodbcpp/odbc-modifycommand.cpp +++ b/libodbcpp/odbc-modifycommand.cpp @@ -15,7 +15,7 @@ ODBC::ModifyCommand::~ModifyCommand() unsigned int ODBC::ModifyCommand::execute(bool anc) { - RETCODE rc = SQLExecute(hStmt); + RETCODE rc = SQLExecute(hStmt); if (!SQL_SUCCEEDED(rc)) { if (rc != SQL_NO_DATA || !anc) { throw Error(rc, SQL_HANDLE_STMT, hStmt); diff --git a/libodbcpp/odbc-selectcommand.cpp b/libodbcpp/odbc-selectcommand.cpp index 6b28a32..5e26053 100644 --- a/libodbcpp/odbc-selectcommand.cpp +++ b/libodbcpp/odbc-selectcommand.cpp @@ -16,7 +16,7 @@ ODBC::SelectCommand::SelectCommand(const Connection & c, const std::string & s) ODBC::SelectCommand::~SelectCommand() { - if (!columns->empty()) { + if (columnCount()) { SQLCloseCursor(hStmt); } } @@ -30,7 +30,7 @@ ODBC::SelectCommand::fetch() bool ODBC::SelectCommand::fetch(SQLSMALLINT orientation, SQLLEN offset) { - if (columns->empty()) { + if (!columnCount()) { execute(); } RETCODE rc = SQLFetchScroll(hStmt, orientation, offset); @@ -42,22 +42,20 @@ ODBC::SelectCommand::fetch(SQLSMALLINT orientation, SQLLEN offset) RETCODE diagrc = SQLGetDiagRec(SQL_HANDLE_STMT, hStmt, 1, sqlstatus, NULL, NULL, 0, NULL); if (SQL_SUCCEEDED(diagrc)) { if (!strncmp((const char*)sqlstatus, "01004", 5)) { - for (Columns::iterator i = columns->begin(); i != columns->end(); ++i) { - std::dynamic_pointer_cast(*i)->resize(); + for (const auto & c : largeColumns) { + c->resize(); } return fetch(SQL_FETCH_RELATIVE, 0); } - } - if (rc != SQL_SUCCESS_WITH_INFO) { - throw Error(rc, SQL_HANDLE_STMT, hStmt); + fprintf(stderr, "truncation\n"); } } // fall-through case SQL_SUCCESS: { bool resized = false; - for (Columns::iterator i = columns->begin(); i != columns->end(); ++i) { - resized |= std::dynamic_pointer_cast(*i)->resize(); + for (const auto & c : largeColumns) { + resized |= c->resize(); } if (resized) { return fetch(SQL_FETCH_RELATIVE, 0); @@ -130,7 +128,14 @@ ODBC::SelectCommand::execute() case SQL_UNKNOWN_TYPE: throw DB::ColumnTypeNotSupported(); default: - ncol = insertColumn(std::make_shared(this, colName, col, bindSize)); + SQLLEN octetSize = 0; + if (!SQL_SUCCEEDED(rc = SQLColAttribute(hStmt, sqlcol, SQL_DESC_OCTET_LENGTH, NULL, 0, NULL, &octetSize))) { + throw Error(rc, SQL_HANDLE_STMT, hStmt); + } + bindSize = octetSize; + auto lc = std::make_shared(this, colName, col, bindSize); + ncol = insertColumn(lc); + largeColumns.insert(lc); break; }; std::dynamic_pointer_cast(ncol)->bind(); diff --git a/libodbcpp/odbc-selectcommand.h b/libodbcpp/odbc-selectcommand.h index 2d4311a..1c71d57 100644 --- a/libodbcpp/odbc-selectcommand.h +++ b/libodbcpp/odbc-selectcommand.h @@ -15,6 +15,9 @@ namespace ODBC { private: bool fetch(SQLSMALLINT orientation = SQL_FETCH_NEXT, SQLLEN offset = 0); + typedef std::shared_ptr ColumnPtr; + typedef std::set Columns; + Columns largeColumns; }; } diff --git a/libodbcpp/unittests/testodbc.cpp b/libodbcpp/unittests/testodbc.cpp index bb6fd97..9a810c7 100644 --- a/libodbcpp/unittests/testodbc.cpp +++ b/libodbcpp/unittests/testodbc.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -90,5 +91,19 @@ BOOST_AUTO_TEST_CASE( bindAndSelectOther ) BOOST_REQUIRE_EQUAL(1, rows); } +BOOST_AUTO_TEST_CASE( multibyte ) +{ + auto ro = DB::MockDatabase::openConnectionTo("odbcmock"); + + auto select = ro->select("SELECT LPAD('', n, '£'), n FROM GENERATE_SERIES(1, 50000, 200) n"); + select->execute(); + int rows = 0; + for (const auto [s, n] : select->as()) { + BOOST_CHECK_EQUAL(s.length(), n * 2); + rows += 1; + } + BOOST_REQUIRE_EQUAL(250, rows); +} + BOOST_AUTO_TEST_SUITE_END(); -- cgit v1.2.3