IGNITE-4183: ODBC Fixed null-values fetching issue.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/ac660dca Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/ac660dca Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/ac660dca Branch: refs/heads/ignite-4242 Commit: ac660dcaa5bf8eb20e7dd4e442e97c1cf548a827 Parents: d88f422 Author: Igor Sapego <[email protected]> Authored: Wed Nov 9 15:29:06 2016 +0300 Committer: Igor Sapego <[email protected]> Committed: Wed Nov 9 15:29:06 2016 +0300 ---------------------------------------------------------------------- .../platforms/cpp/odbc-test/include/test_type.h | 42 ++++-- .../cpp/odbc-test/src/queries_test.cpp | 139 +++++++++++++++++-- .../cpp/odbc-test/src/sql_outer_join_test.cpp | 2 +- .../odbc/src/app/application_data_buffer.cpp | 34 ++++- 4 files changed, 187 insertions(+), 30 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/ac660dca/modules/platforms/cpp/odbc-test/include/test_type.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/include/test_type.h b/modules/platforms/cpp/odbc-test/include/test_type.h index 2a4a979..0e08251 100644 --- a/modules/platforms/cpp/odbc-test/include/test_type.h +++ b/modules/platforms/cpp/odbc-test/include/test_type.h @@ -28,6 +28,7 @@ namespace ignite struct TestType { TestType() : + allNulls(false), i8Field(0), i16Field(0), i32Field(0), @@ -45,6 +46,7 @@ namespace ignite int64_t i64Field, const std::string& strField, float floatField, double doubleField, bool boolField, const Guid& guidField, const Date& dateField, const Timestamp& timestampField) : + allNulls(false), i8Field(i8Field), i16Field(i16Field), i32Field(i32Field), @@ -60,6 +62,7 @@ namespace ignite // No-op. } + bool allNulls; int8_t i8Field; int16_t i16Field; int32_t i32Field; @@ -91,17 +94,34 @@ namespace ignite void Write(BinaryWriter& writer, TestType obj) { - writer.WriteInt8("i8Field", obj.i8Field); - writer.WriteInt16("i16Field", obj.i16Field); - writer.WriteInt32("i32Field", obj.i32Field); - writer.WriteInt64("i64Field", obj.i64Field); - writer.WriteString("strField", obj.strField); - writer.WriteFloat("floatField", obj.floatField); - writer.WriteDouble("doubleField", obj.doubleField); - writer.WriteBool("boolField", obj.boolField); - writer.WriteGuid("guidField", obj.guidField); - writer.WriteDate("dateField", obj.dateField); - writer.WriteTimestamp("timestampField", obj.timestampField); + if (!obj.allNulls) + { + writer.WriteInt8("i8Field", obj.i8Field); + writer.WriteInt16("i16Field", obj.i16Field); + writer.WriteInt32("i32Field", obj.i32Field); + writer.WriteInt64("i64Field", obj.i64Field); + writer.WriteString("strField", obj.strField); + writer.WriteFloat("floatField", obj.floatField); + writer.WriteDouble("doubleField", obj.doubleField); + writer.WriteBool("boolField", obj.boolField); + writer.WriteGuid("guidField", obj.guidField); + writer.WriteDate("dateField", obj.dateField); + writer.WriteTimestamp("timestampField", obj.timestampField); + } + else + { + writer.WriteNull("i8Field"); + writer.WriteNull("i16Field"); + writer.WriteNull("i32Field"); + writer.WriteNull("i64Field"); + writer.WriteNull("strField"); + writer.WriteNull("floatField"); + writer.WriteNull("doubleField"); + writer.WriteNull("boolField"); + writer.WriteNull("guidField"); + writer.WriteNull("dateField"); + writer.WriteNull("timestampField"); + } } TestType Read(BinaryReader& reader) http://git-wip-us.apache.org/repos/asf/ignite/blob/ac660dca/modules/platforms/cpp/odbc-test/src/queries_test.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/src/queries_test.cpp b/modules/platforms/cpp/odbc-test/src/queries_test.cpp index 82e9972..a7fc7a9 100644 --- a/modules/platforms/cpp/odbc-test/src/queries_test.cpp +++ b/modules/platforms/cpp/odbc-test/src/queries_test.cpp @@ -250,14 +250,14 @@ struct QueriesTestSuiteFixture BOOST_CHECK_EQUAL(columns[9], 0); BOOST_CHECK_EQUAL(columns[10], 0); - BOOST_CHECK_EQUAL(columnLens[0], 0); - BOOST_CHECK_EQUAL(columnLens[1], 0); - BOOST_CHECK_EQUAL(columnLens[2], 0); - BOOST_CHECK_EQUAL(columnLens[3], 0); - BOOST_CHECK_EQUAL(columnLens[4], 0); - BOOST_CHECK_EQUAL(columnLens[5], 0); - BOOST_CHECK_EQUAL(columnLens[6], 0); - BOOST_CHECK_EQUAL(columnLens[7], 0); + BOOST_CHECK_EQUAL(columnLens[0], static_cast<SQLLEN>(sizeof(T))); + BOOST_CHECK_EQUAL(columnLens[1], static_cast<SQLLEN>(sizeof(T))); + BOOST_CHECK_EQUAL(columnLens[2], static_cast<SQLLEN>(sizeof(T))); + BOOST_CHECK_EQUAL(columnLens[3], static_cast<SQLLEN>(sizeof(T))); + BOOST_CHECK_EQUAL(columnLens[4], static_cast<SQLLEN>(sizeof(T))); + BOOST_CHECK_EQUAL(columnLens[5], static_cast<SQLLEN>(sizeof(T))); + BOOST_CHECK_EQUAL(columnLens[6], static_cast<SQLLEN>(sizeof(T))); + BOOST_CHECK_EQUAL(columnLens[7], static_cast<SQLLEN>(sizeof(T))); BOOST_CHECK_EQUAL(columnLens[8], SQL_NO_TOTAL); BOOST_CHECK_EQUAL(columnLens[9], SQL_NO_TOTAL); BOOST_CHECK_EQUAL(columnLens[10], SQL_NO_TOTAL); @@ -296,32 +296,32 @@ BOOST_AUTO_TEST_CASE(TestConnectionProtocolVersion_1_6_0) BOOST_AUTO_TEST_CASE(TestTwoRowsInt8) { - CheckTwoRowsInt<int8_t>(SQL_C_STINYINT); + CheckTwoRowsInt<signed char>(SQL_C_STINYINT); } BOOST_AUTO_TEST_CASE(TestTwoRowsUint8) { - CheckTwoRowsInt<uint8_t>(SQL_C_UTINYINT); + CheckTwoRowsInt<unsigned char>(SQL_C_UTINYINT); } BOOST_AUTO_TEST_CASE(TestTwoRowsInt16) { - CheckTwoRowsInt<int16_t>(SQL_C_SSHORT); + CheckTwoRowsInt<signed short>(SQL_C_SSHORT); } BOOST_AUTO_TEST_CASE(TestTwoRowsUint16) { - CheckTwoRowsInt<uint16_t>(SQL_C_USHORT); + CheckTwoRowsInt<unsigned short>(SQL_C_USHORT); } BOOST_AUTO_TEST_CASE(TestTwoRowsInt32) { - CheckTwoRowsInt<int32_t>(SQL_C_SLONG); + CheckTwoRowsInt<signed long>(SQL_C_SLONG); } BOOST_AUTO_TEST_CASE(TestTwoRowsUint32) { - CheckTwoRowsInt<uint32_t>(SQL_C_ULONG); + CheckTwoRowsInt<unsigned long>(SQL_C_ULONG); } BOOST_AUTO_TEST_CASE(TestTwoRowsInt64) @@ -674,4 +674,115 @@ BOOST_AUTO_TEST_CASE(TestDataAtExecution) BOOST_CHECK(ret == SQL_NO_DATA); } +BOOST_AUTO_TEST_CASE(TestNullFields) +{ + Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;CACHE=cache"); + + SQLRETURN ret; + + TestType in(1, 2, 3, 4, "5", 6.0f, 7.0, true, Guid(8, 9), BinaryUtils::MakeDateGmt(1987, 6, 5), + BinaryUtils::MakeTimestampGmt(1998, 12, 27, 1, 2, 3, 456)); + + TestType inNull; + + inNull.allNulls = true; + + testCache.Put(1, in); + testCache.Put(2, inNull); + testCache.Put(3, in); + + const size_t columnsCnt = 10; + + SQLLEN columnLens[columnsCnt] = { 0 }; + + int8_t i8Column; + int16_t i16Column; + int32_t i32Column; + int64_t i64Column; + char strColumn[ODBC_BUFFER_SIZE]; + float floatColumn; + double doubleColumn; + bool boolColumn; + SQL_DATE_STRUCT dateColumn; + SQL_TIMESTAMP_STRUCT timestampColumn; + + // Binding columns. + ret = SQLBindCol(stmt, 1, SQL_C_STINYINT, &i8Column, 0, &columnLens[0]); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + ret = SQLBindCol(stmt, 2, SQL_C_SSHORT, &i16Column, 0, &columnLens[1]); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + ret = SQLBindCol(stmt, 3, SQL_C_SLONG, &i32Column, 0, &columnLens[2]); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + ret = SQLBindCol(stmt, 4, SQL_C_SBIGINT, &i64Column, 0, &columnLens[3]); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + ret = SQLBindCol(stmt, 5, SQL_C_CHAR, &strColumn, ODBC_BUFFER_SIZE, &columnLens[4]); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + ret = SQLBindCol(stmt, 6, SQL_C_FLOAT, &floatColumn, 0, &columnLens[5]); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + ret = SQLBindCol(stmt, 7, SQL_C_DOUBLE, &doubleColumn, 0, &columnLens[6]); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + ret = SQLBindCol(stmt, 8, SQL_C_BIT, &boolColumn, 0, &columnLens[7]); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + ret = SQLBindCol(stmt, 9, SQL_C_DATE, &dateColumn, 0, &columnLens[8]); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + ret = SQLBindCol(stmt, 10, SQL_C_TIMESTAMP, ×tampColumn, 0, &columnLens[9]); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + SQLCHAR request[] = "SELECT i8Field, i16Field, i32Field, i64Field, strField, " + "floatField, doubleField, boolField, dateField, timestampField FROM TestType ORDER BY _key"; + + ret = SQLExecDirect(stmt, request, SQL_NTS); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + // Fetching the first non-null row. + ret = SQLFetch(stmt); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + // Checking that columns are not null. + for (SQLSMALLINT i = 0; i < columnsCnt; ++i) + BOOST_CHECK_NE(columnLens[i], SQL_NULL_DATA); + + // Fetching null row. + ret = SQLFetch(stmt); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + // Checking that columns are null. + for (SQLSMALLINT i = 0; i < columnsCnt; ++i) + BOOST_CHECK_EQUAL(columnLens[i], SQL_NULL_DATA); + + // Fetching the last non-null row. + ret = SQLFetch(stmt); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + // Checking that columns are not null. + for (SQLSMALLINT i = 0; i < columnsCnt; ++i) + BOOST_CHECK_NE(columnLens[i], SQL_NULL_DATA); + + ret = SQLFetch(stmt); + BOOST_CHECK(ret == SQL_NO_DATA); +} + BOOST_AUTO_TEST_SUITE_END() http://git-wip-us.apache.org/repos/asf/ignite/blob/ac660dca/modules/platforms/cpp/odbc-test/src/sql_outer_join_test.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/src/sql_outer_join_test.cpp b/modules/platforms/cpp/odbc-test/src/sql_outer_join_test.cpp index 426041b..56f5219 100644 --- a/modules/platforms/cpp/odbc-test/src/sql_outer_join_test.cpp +++ b/modules/platforms/cpp/odbc-test/src/sql_outer_join_test.cpp @@ -211,7 +211,7 @@ BOOST_AUTO_TEST_CASE(TestOuterJoinOpsLess) BOOST_CHECK_NE(columnsLen[0], SQL_NULL_DATA); BOOST_CHECK_EQUAL(columns[0], 30); - BOOST_CHECK_EQUAL(columnsLen[1], SQL_NULL_DATA); + BOOST_CHECK_NE(columnsLen[1], SQL_NULL_DATA); ret = SQLFetch(stmt); BOOST_CHECK(ret == SQL_NO_DATA); http://git-wip-us.apache.org/repos/asf/ignite/blob/ac660dca/modules/platforms/cpp/odbc/src/app/application_data_buffer.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/app/application_data_buffer.cpp b/modules/platforms/cpp/odbc/src/app/application_data_buffer.cpp index 1438b0c..078e691 100644 --- a/modules/platforms/cpp/odbc/src/app/application_data_buffer.cpp +++ b/modules/platforms/cpp/odbc/src/app/application_data_buffer.cpp @@ -182,6 +182,10 @@ namespace ignite memcpy(out->val, &uval, std::min<int>(SQL_MAX_NUMERIC_LEN, sizeof(uval))); } + + if (resLenPtr) + *resLenPtr = static_cast<SqlLen>(sizeof(SQL_NUMERIC_STRUCT)); + break; } @@ -237,12 +241,16 @@ namespace ignite void ApplicationDataBuffer::PutNumToNumBuffer(Tin value) { void* dataPtr = GetData(); + SqlLen* resLenPtr = GetResLen(); if (dataPtr) { Tbuf* out = reinterpret_cast<Tbuf*>(dataPtr); *out = static_cast<Tbuf>(value); } + + if (resLenPtr) + *resLenPtr = static_cast<SqlLen>(sizeof(Tbuf)); } template<typename CharT, typename Tin> @@ -448,6 +456,8 @@ namespace ignite { using namespace type_traits; + SqlLen* resLenPtr = GetResLen(); + switch (type) { case IGNITE_ODBC_C_TYPE_CHAR: @@ -476,13 +486,14 @@ namespace ignite for (size_t i = 0; i < sizeof(guid->Data4); ++i) guid->Data4[i] = (lsb >> (sizeof(guid->Data4) - i - 1) * 8) & 0xFF; + if (resLenPtr) + *resLenPtr = static_cast<SqlLen>(sizeof(SQLGUID)); + break; } default: { - SqlLen* resLenPtr = GetResLen(); - if (resLenPtr) *resLenPtr = SQL_NO_TOTAL; } @@ -573,6 +584,8 @@ namespace ignite { using namespace type_traits; + SqlLen* resLenPtr = GetResLen(); + switch (type) { case IGNITE_ODBC_C_TYPE_SIGNED_TINYINT: @@ -637,6 +650,9 @@ namespace ignite numeric->sign = unscaled.GetSign() < 0 ? 0 : 1; numeric->precision = unscaled.GetPrecision(); + if (resLenPtr) + *resLenPtr = static_cast<SqlLen>(sizeof(SQL_NUMERIC_STRUCT)); + break; } @@ -644,8 +660,6 @@ namespace ignite case IGNITE_ODBC_C_TYPE_BINARY: default: { - SqlLen* resLenPtr = GetResLen(); - if (resLenPtr) *resLenPtr = SQL_NO_TOTAL; } @@ -716,6 +730,9 @@ namespace ignite buffer->month = tmTime.tm_mon + 1; buffer->day = tmTime.tm_mday; + if (resLenPtr) + *resLenPtr = static_cast<SqlLen>(sizeof(SQL_DATE_STRUCT)); + break; } @@ -731,6 +748,9 @@ namespace ignite buffer->second = tmTime.tm_sec; buffer->fraction = 0; + if (resLenPtr) + *resLenPtr = static_cast<SqlLen>(sizeof(SQL_TIMESTAMP_STRUCT)); + break; } @@ -830,6 +850,9 @@ namespace ignite buffer->month = tmTime.tm_mon + 1; buffer->day = tmTime.tm_mday; + if (resLenPtr) + *resLenPtr = static_cast<SqlLen>(sizeof(SQL_DATE_STRUCT)); + break; } @@ -845,6 +868,9 @@ namespace ignite buffer->second = tmTime.tm_sec; buffer->fraction = value.GetSecondFraction(); + if (resLenPtr) + *resLenPtr = static_cast<SqlLen>(sizeof(SQL_TIMESTAMP_STRUCT)); + break; }
