http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/modules/platforms/cpp/odbc-test/src/cursor_test.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/src/cursor_test.cpp b/modules/platforms/cpp/odbc-test/src/cursor_test.cpp new file mode 100644 index 0000000..2be2e23 --- /dev/null +++ b/modules/platforms/cpp/odbc-test/src/cursor_test.cpp @@ -0,0 +1,205 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MSC_VER +# define BOOST_TEST_DYN_LINK +#endif + +#include <boost/test/unit_test.hpp> + +#include <ignite/impl/binary/binary_writer_impl.h> + +#include "ignite/odbc/system/odbc_constants.h" +#include "ignite/odbc/cursor.h" + +using namespace ignite::odbc; + +const int64_t testQueryId = 42; + +std::auto_ptr<ResultPage> CreateTestPage(bool last, int32_t size) +{ + using namespace ignite::impl::binary; + using namespace ignite::impl::interop; + + ignite::impl::interop::InteropUnpooledMemory mem(1024); + InteropOutputStream outStream(&mem); + BinaryWriterImpl writer(&outStream, 0); + + // Last page flag. + writer.WriteBool(last); + + //Page size. + writer.WriteInt32(size); + + for (int32_t i = 0; i < size; ++i) + { + // Writing row size = 1 column. + writer.WriteInt32(1); + + // Writing column type. + writer.WriteInt8(IGNITE_TYPE_INT); + + // Column value. + writer.WriteInt32(i); + } + + outStream.Synchronize(); + + std::auto_ptr<ResultPage> res(new ResultPage()); + + InteropInputStream inStream(&mem); + BinaryReaderImpl reader(&inStream); + + res->Read(reader); + + BOOST_REQUIRE(res->GetSize() == size); + BOOST_REQUIRE(res->IsLast() == last); + + return res; +} + +void CheckCursorNeedUpdate(Cursor& cursor) +{ + BOOST_REQUIRE(cursor.NeedDataUpdate()); + + BOOST_REQUIRE(cursor.HasData()); + + BOOST_REQUIRE(!cursor.Increment()); + + BOOST_REQUIRE(!cursor.GetRow()); +} + +void CheckCursorReady(Cursor& cursor) +{ + BOOST_REQUIRE(!cursor.NeedDataUpdate()); + + BOOST_REQUIRE(cursor.HasData()); + + BOOST_REQUIRE(cursor.GetRow()); +} + +void CheckCursorEnd(Cursor& cursor) +{ + BOOST_REQUIRE(!cursor.NeedDataUpdate()); + + BOOST_REQUIRE(!cursor.HasData()); + + BOOST_REQUIRE(!cursor.Increment()); + + BOOST_REQUIRE(!cursor.GetRow()); +} + +BOOST_AUTO_TEST_SUITE(CursorTestSuite) + +BOOST_AUTO_TEST_CASE(TestCursorEmpty) +{ + Cursor cursor(testQueryId); + + BOOST_REQUIRE(cursor.GetQueryId() == testQueryId); + + CheckCursorNeedUpdate(cursor); +} + +BOOST_AUTO_TEST_CASE(TestCursorLast) +{ + const int32_t pageSize = 16; + + Cursor cursor(testQueryId); + + std::auto_ptr<ResultPage> resultPage = CreateTestPage(true, pageSize); + + cursor.UpdateData(resultPage); + + BOOST_REQUIRE(cursor.GetQueryId() == testQueryId); + + CheckCursorReady(cursor); + + for (int32_t i = 0; i < pageSize; ++i) + BOOST_REQUIRE(cursor.Increment()); + + CheckCursorEnd(cursor); +} + +BOOST_AUTO_TEST_CASE(TestCursorUpdate) +{ + const int32_t pageSize = 16; + + Cursor cursor(testQueryId); + + std::auto_ptr<ResultPage> resultPage = CreateTestPage(false, pageSize); + + cursor.UpdateData(resultPage); + + BOOST_REQUIRE(cursor.GetQueryId() == testQueryId); + + for (int32_t i = 0; i < pageSize; ++i) + { + CheckCursorReady(cursor); + + BOOST_REQUIRE(cursor.Increment()); + } + + CheckCursorNeedUpdate(cursor); + + resultPage = CreateTestPage(true, pageSize); + + cursor.UpdateData(resultPage); + + CheckCursorReady(cursor); + + for (int32_t i = 0; i < pageSize; ++i) + { + CheckCursorReady(cursor); + + BOOST_REQUIRE(cursor.Increment()); + } + + CheckCursorEnd(cursor); +} + +BOOST_AUTO_TEST_CASE(TestCursorUpdateOneRow) +{ + Cursor cursor(testQueryId); + + std::auto_ptr<ResultPage> resultPage = CreateTestPage(false, 1); + + cursor.UpdateData(resultPage); + + BOOST_REQUIRE(cursor.GetQueryId() == testQueryId); + + CheckCursorReady(cursor); + + BOOST_REQUIRE(cursor.Increment()); + + CheckCursorNeedUpdate(cursor); + + BOOST_REQUIRE(!cursor.Increment()); + + resultPage = CreateTestPage(true, 1); + + cursor.UpdateData(resultPage); + + CheckCursorReady(cursor); + + BOOST_REQUIRE(cursor.Increment()); + + CheckCursorEnd(cursor); + + BOOST_REQUIRE(!cursor.Increment()); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/modules/platforms/cpp/odbc-test/src/parser_test.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/src/parser_test.cpp b/modules/platforms/cpp/odbc-test/src/parser_test.cpp new file mode 100644 index 0000000..7c8a73d --- /dev/null +++ b/modules/platforms/cpp/odbc-test/src/parser_test.cpp @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MSC_VER +# define BOOST_TEST_DYN_LINK +#endif + +#include <boost/test/unit_test.hpp> + +#include <ignite/odbc/parser.h> + +using namespace ignite::odbc; + +struct TestMessage +{ + TestMessage() + { + // No-op. + } + + TestMessage(int32_t a, const std::string& b) : a(a), b(b) + { + // No-op. + } + + ~TestMessage() + { + // No-op. + } + + void Write(ignite::impl::binary::BinaryWriterImpl& writer) const + { + writer.WriteInt32(a); + writer.WriteString(b.data(), static_cast<int32_t>(b.size())); + } + + void Read(ignite::impl::binary::BinaryReaderImpl& reader) + { + a = reader.ReadInt32(); + + b.resize(reader.ReadString(0, 0)); + reader.ReadString(&b[0], static_cast<int32_t>(b.size())); + } + + int32_t a; + std::string b; +}; + +bool operator==(const TestMessage& lhs, const TestMessage& rhs) +{ + return lhs.a == rhs.a && + lhs.b == rhs.b; +} + +BOOST_AUTO_TEST_SUITE(ParserTestSuite) + +BOOST_AUTO_TEST_CASE(TestParserEncodeDecode) +{ + Parser parser; + + std::vector<int8_t> buffer; + + TestMessage outMsg(42, "Test message"); + TestMessage inMsg; + + parser.Encode(outMsg, buffer); + + parser.Decode(inMsg, buffer); + + BOOST_REQUIRE(outMsg == inMsg); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/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 new file mode 100644 index 0000000..cc3fa8e --- /dev/null +++ b/modules/platforms/cpp/odbc-test/src/queries_test.cpp @@ -0,0 +1,516 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef _WIN32 +# include <windows.h> +#endif + +#include <sql.h> +#include <sqlext.h> + +#include <vector> +#include <string> + +#ifndef _MSC_VER +# define BOOST_TEST_DYN_LINK +#endif + +#include <boost/test/unit_test.hpp> + +#include "ignite/ignite.h" +#include "ignite/ignition.h" +#include "ignite/impl/binary/binary_utils.h" + +#include "test_type.h" + +using namespace ignite; +using namespace ignite::cache; +using namespace ignite::cache::query; +using namespace ignite::common; + +using namespace boost::unit_test; + +using ignite::impl::binary::BinaryUtils; + +/** Read buffer size. */ +enum { ODBC_BUFFER_SIZE = 1024 }; + +/** + * Extract error message. + * + * @param handleType Type of the handle. + * @param handle Handle. + * @return Error message. + */ +std::string GetOdbcErrorMessage(SQLSMALLINT handleType, SQLHANDLE handle) +{ + SQLCHAR sqlstate[7] = {}; + SQLINTEGER nativeCode; + + SQLCHAR message[ODBC_BUFFER_SIZE]; + SQLSMALLINT reallen = 0; + + SQLGetDiagRec(handleType, handle, 1, sqlstate, &nativeCode, message, ODBC_BUFFER_SIZE, &reallen); + + return std::string(reinterpret_cast<char*>(sqlstate)) + ": " + + std::string(reinterpret_cast<char*>(message), reallen); +} + +/** + * Test setup fixture. + */ +struct QueriesTestSuiteFixture +{ + /** + * Constructor. + */ + QueriesTestSuiteFixture() : testCache(0), env(NULL), dbc(NULL), stmt(NULL) + { + IgniteConfiguration cfg; + + cfg.jvmOpts.push_back("-Xdebug"); + cfg.jvmOpts.push_back("-Xnoagent"); + cfg.jvmOpts.push_back("-Djava.compiler=NONE"); + cfg.jvmOpts.push_back("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"); + cfg.jvmOpts.push_back("-XX:+HeapDumpOnOutOfMemoryError"); + +#ifdef IGNITE_TESTS_32 + cfg.jvmInitMem = 256; + cfg.jvmMaxMem = 768; +#else + cfg.jvmInitMem = 1024; + cfg.jvmMaxMem = 4096; +#endif + + char* cfgPath = getenv("IGNITE_NATIVE_TEST_ODBC_CONFIG_PATH"); + + cfg.springCfgPath = std::string(cfgPath).append("/").append("queries-test.xml"); + + IgniteError err; + + grid = Ignition::Start(cfg, &err); + + if (err.GetCode() != IgniteError::IGNITE_SUCCESS) + BOOST_FAIL(err.GetText()); + + testCache = grid.GetCache<int64_t, TestType>("cache"); + + // Allocate an environment handle + SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env); + + BOOST_REQUIRE(env != NULL); + + // We want ODBC 3 support + SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, reinterpret_cast<void*>(SQL_OV_ODBC3), 0); + + // Allocate a connection handle + SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc); + + BOOST_REQUIRE(dbc != NULL); + + // Connect string + SQLCHAR connectStr[] = "DRIVER={Apache Ignite};SERVER=localhost;PORT=10800;CACHE=cache"; + + SQLCHAR outstr[ODBC_BUFFER_SIZE]; + SQLSMALLINT outstrlen; + + // Connecting to ODBC server. + SQLRETURN ret = SQLDriverConnect(dbc, NULL, connectStr, static_cast<SQLSMALLINT>(sizeof(connectStr)), + outstr, sizeof(outstr), &outstrlen, SQL_DRIVER_COMPLETE); + + if (!SQL_SUCCEEDED(ret)) + { + Ignition::Stop(grid.GetName(), true); + + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_DBC, dbc)); + } + + // Allocate a statement handle + SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt); + + BOOST_REQUIRE(stmt != NULL); + } + + /** + * Destructor. + */ + ~QueriesTestSuiteFixture() + { + // Releasing statement handle. + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + + // Disconneting from the server. + SQLDisconnect(dbc); + + // Releasing allocated handles. + SQLFreeHandle(SQL_HANDLE_DBC, dbc); + SQLFreeHandle(SQL_HANDLE_ENV, env); + + Ignition::Stop(grid.GetName(), true); + } + + template<typename T> + void CheckTwoRowsInt(SQLSMALLINT type) + { + SQLRETURN ret; + + TestType in1(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 in2(8, 7, 6, 5, "4", 3.0f, 2.0, false, Guid(1, 0), BinaryUtils::MakeDateGmt(1976, 1, 12), BinaryUtils::MakeTimestampGmt(1978, 8, 21, 23, 13, 45, 456)); + + testCache.Put(1, in1); + testCache.Put(2, in2); + + const size_t columnsCnt = 11; + + T columns[columnsCnt] = { 0 }; + + // Binding colums. + for (SQLSMALLINT i = 0; i < columnsCnt; ++i) + { + ret = SQLBindCol(stmt, i + 1, type, &columns[i], sizeof(columns[i]), 0); + + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + } + + SQLCHAR request[] = "SELECT i8Field, i16Field, i32Field, i64Field, strField, " + "floatField, doubleField, boolField, guidField, dateField, timestampField FROM TestType"; + + ret = SQLExecDirect(stmt, request, SQL_NTS); + + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + ret = SQLFetch(stmt); + + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + BOOST_CHECK_EQUAL(columns[0], 1); + BOOST_CHECK_EQUAL(columns[1], 2); + BOOST_CHECK_EQUAL(columns[2], 3); + BOOST_CHECK_EQUAL(columns[3], 4); + BOOST_CHECK_EQUAL(columns[4], 5); + BOOST_CHECK_EQUAL(columns[5], 6); + BOOST_CHECK_EQUAL(columns[6], 7); + BOOST_CHECK_EQUAL(columns[7], 1); + BOOST_CHECK_EQUAL(columns[8], 0); + BOOST_CHECK_EQUAL(columns[9], 0); + BOOST_CHECK_EQUAL(columns[10], 0); + + SQLLEN columnLens[columnsCnt] = { 0 }; + + // Binding colums. + for (SQLSMALLINT i = 0; i < columnsCnt; ++i) + { + ret = SQLBindCol(stmt, i + 1, type, &columns[i], sizeof(columns[i]), &columnLens[i]); + + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + } + + ret = SQLFetch(stmt); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + BOOST_CHECK_EQUAL(columns[0], 8); + BOOST_CHECK_EQUAL(columns[1], 7); + BOOST_CHECK_EQUAL(columns[2], 6); + BOOST_CHECK_EQUAL(columns[3], 5); + BOOST_CHECK_EQUAL(columns[4], 4); + BOOST_CHECK_EQUAL(columns[5], 3); + BOOST_CHECK_EQUAL(columns[6], 2); + BOOST_CHECK_EQUAL(columns[7], 0); + BOOST_CHECK_EQUAL(columns[8], 0); + 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[8], SQL_NO_TOTAL); + BOOST_CHECK_EQUAL(columnLens[9], SQL_NO_TOTAL); + BOOST_CHECK_EQUAL(columnLens[10], SQL_NO_TOTAL); + + ret = SQLFetch(stmt); + BOOST_CHECK(ret == SQL_NO_DATA); + } + + /** Node started during the test. */ + Ignite grid; + + /** Test cache instance. */ + Cache<int64_t, TestType> testCache; + + /** ODBC Environment. */ + SQLHENV env; + + /** ODBC Connect. */ + SQLHDBC dbc; + + /** ODBC Statement. */ + SQLHSTMT stmt; +}; + +BOOST_FIXTURE_TEST_SUITE(QueriesTestSuite, QueriesTestSuiteFixture) + +BOOST_AUTO_TEST_CASE(TestTwoRowsInt8) +{ + CheckTwoRowsInt<int8_t>(SQL_C_STINYINT); +} + +BOOST_AUTO_TEST_CASE(TestTwoRowsUint8) +{ + CheckTwoRowsInt<uint8_t>(SQL_C_UTINYINT); +} + +BOOST_AUTO_TEST_CASE(TestTwoRowsInt16) +{ + CheckTwoRowsInt<int16_t>(SQL_C_SSHORT); +} + +BOOST_AUTO_TEST_CASE(TestTwoRowsUint16) +{ + CheckTwoRowsInt<uint16_t>(SQL_C_USHORT); +} + +BOOST_AUTO_TEST_CASE(TestTwoRowsInt32) +{ + CheckTwoRowsInt<int32_t>(SQL_C_SLONG); +} + +BOOST_AUTO_TEST_CASE(TestTwoRowsUint32) +{ + CheckTwoRowsInt<uint32_t>(SQL_C_ULONG); +} + +BOOST_AUTO_TEST_CASE(TestTwoRowsInt64) +{ + CheckTwoRowsInt<int64_t>(SQL_C_SBIGINT); +} + +BOOST_AUTO_TEST_CASE(TestTwoRowsUint64) +{ + CheckTwoRowsInt<uint64_t>(SQL_C_UBIGINT); +} + +BOOST_AUTO_TEST_CASE(TestTwoRowsString) +{ + SQLRETURN ret; + + TestType in1(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 in2(8, 7, 6, 5, "4", 3.0f, 2.0, false, Guid(1, 0), BinaryUtils::MakeDateGmt(1976, 1, 12), BinaryUtils::MakeTimestampGmt(1978, 8, 21, 23, 13, 45, 999999999)); + + testCache.Put(1, in1); + testCache.Put(2, in2); + + const size_t columnsCnt = 11; + + SQLCHAR columns[columnsCnt][ODBC_BUFFER_SIZE] = { 0 }; + + // Binding colums. + for (SQLSMALLINT i = 0; i < columnsCnt; ++i) + { + ret = SQLBindCol(stmt, i + 1, SQL_C_CHAR, &columns[i], ODBC_BUFFER_SIZE, 0); + + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + } + + SQLCHAR request[] = "SELECT i8Field, i16Field, i32Field, i64Field, strField, " + "floatField, doubleField, boolField, guidField, dateField, timestampField FROM TestType"; + + ret = SQLExecDirect(stmt, request, SQL_NTS); + + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + ret = SQLFetch(stmt); + + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[0])), "1"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[1])), "2"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[2])), "3"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[3])), "4"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[4])), "5"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[5])), "6"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[6])), "7"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[7])), "1"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[8])), "00000000-0000-0008-0000-000000000009"); + // Such format is used because Date returned as Timestamp. + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[9])), "1987-06-05 00:00:00"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[10])), "1998-12-27 01:02:03"); + + SQLLEN columnLens[columnsCnt] = { 0 }; + + // Binding colums. + for (SQLSMALLINT i = 0; i < columnsCnt; ++i) + { + ret = SQLBindCol(stmt, i + 1, SQL_C_CHAR, &columns[i], ODBC_BUFFER_SIZE, &columnLens[i]); + + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + } + + ret = SQLFetch(stmt); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[0])), "8"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[1])), "7"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[2])), "6"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[3])), "5"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[4])), "4"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[5])), "3"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[6])), "2"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[7])), "0"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[8])), "00000000-0000-0001-0000-000000000000"); + // Such format is used because Date returned as Timestamp. + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[9])), "1976-01-12 00:00:00"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[10])), "1978-08-21 23:13:45"); + + BOOST_CHECK_EQUAL(columnLens[0], 1); + BOOST_CHECK_EQUAL(columnLens[1], 1); + BOOST_CHECK_EQUAL(columnLens[2], 1); + BOOST_CHECK_EQUAL(columnLens[3], 1); + BOOST_CHECK_EQUAL(columnLens[4], 1); + BOOST_CHECK_EQUAL(columnLens[5], 1); + BOOST_CHECK_EQUAL(columnLens[6], 1); + BOOST_CHECK_EQUAL(columnLens[7], 1); + BOOST_CHECK_EQUAL(columnLens[8], 36); + BOOST_CHECK_EQUAL(columnLens[9], 19); + BOOST_CHECK_EQUAL(columnLens[10], 19); + + ret = SQLFetch(stmt); + BOOST_CHECK(ret == SQL_NO_DATA); +} + +BOOST_AUTO_TEST_CASE(TestOneRowString) +{ + 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)); + + testCache.Put(1, in); + + const size_t columnsCnt = 11; + + SQLCHAR columns[columnsCnt][ODBC_BUFFER_SIZE] = { 0 }; + + SQLLEN columnLens[columnsCnt] = { 0 }; + + // Binding colums. + for (SQLSMALLINT i = 0; i < columnsCnt; ++i) + { + ret = SQLBindCol(stmt, i + 1, SQL_C_CHAR, &columns[i], ODBC_BUFFER_SIZE, &columnLens[i]); + + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + } + + SQLCHAR request[] = "SELECT i8Field, i16Field, i32Field, i64Field, strField, " + "floatField, doubleField, boolField, guidField, dateField, timestampField FROM TestType"; + + ret = SQLExecDirect(stmt, request, SQL_NTS); + + ret = SQLFetch(stmt); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[0])), "1"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[1])), "2"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[2])), "3"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[3])), "4"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[4])), "5"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[5])), "6"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[6])), "7"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[7])), "1"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[8])), "00000000-0000-0008-0000-000000000009"); + // Such format is used because Date returned as Timestamp. + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[9])), "1987-06-05 00:00:00"); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(columns[10])), "1998-12-27 01:02:03"); + + BOOST_CHECK_EQUAL(columnLens[0], 1); + BOOST_CHECK_EQUAL(columnLens[1], 1); + BOOST_CHECK_EQUAL(columnLens[2], 1); + BOOST_CHECK_EQUAL(columnLens[3], 1); + BOOST_CHECK_EQUAL(columnLens[4], 1); + BOOST_CHECK_EQUAL(columnLens[5], 1); + BOOST_CHECK_EQUAL(columnLens[6], 1); + BOOST_CHECK_EQUAL(columnLens[7], 1); + BOOST_CHECK_EQUAL(columnLens[8], 36); + BOOST_CHECK_EQUAL(columnLens[9], 19); + BOOST_CHECK_EQUAL(columnLens[10], 19); + + ret = SQLFetch(stmt); + BOOST_CHECK(ret == SQL_NO_DATA); +} + +BOOST_AUTO_TEST_CASE(TestOneRowStringLen) +{ + 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)); + + testCache.Put(1, in); + + const size_t columnsCnt = 11; + + SQLLEN columnLens[columnsCnt] = { 0 }; + + // Binding colums. + for (SQLSMALLINT i = 0; i < columnsCnt; ++i) + { + ret = SQLBindCol(stmt, i + 1, SQL_C_CHAR, 0, 0, &columnLens[i]); + + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + } + + SQLCHAR request[] = "SELECT i8Field, i16Field, i32Field, i64Field, strField, " + "floatField, doubleField, boolField, guidField, dateField, timestampField FROM TestType"; + + ret = SQLExecDirect(stmt, request, SQL_NTS); + + ret = SQLFetch(stmt); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + BOOST_CHECK_EQUAL(columnLens[0], 1); + BOOST_CHECK_EQUAL(columnLens[1], 1); + BOOST_CHECK_EQUAL(columnLens[2], 1); + BOOST_CHECK_EQUAL(columnLens[3], 1); + BOOST_CHECK_EQUAL(columnLens[4], 1); + BOOST_CHECK_EQUAL(columnLens[5], 1); + BOOST_CHECK_EQUAL(columnLens[6], 1); + BOOST_CHECK_EQUAL(columnLens[7], 1); + BOOST_CHECK_EQUAL(columnLens[8], 36); + BOOST_CHECK_EQUAL(columnLens[9], 19); + BOOST_CHECK_EQUAL(columnLens[10], 19); + + ret = SQLFetch(stmt); + BOOST_CHECK(ret == SQL_NO_DATA); +} + +BOOST_AUTO_TEST_SUITE_END() http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/modules/platforms/cpp/odbc-test/src/row_test.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/src/row_test.cpp b/modules/platforms/cpp/odbc-test/src/row_test.cpp new file mode 100644 index 0000000..bbf0e3d --- /dev/null +++ b/modules/platforms/cpp/odbc-test/src/row_test.cpp @@ -0,0 +1,208 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MSC_VER +# define BOOST_TEST_DYN_LINK +#endif + +#include <boost/test/unit_test.hpp> + +#include <ignite/impl/binary/binary_writer_impl.h> + +#include "ignite/odbc/system/odbc_constants.h" +#include "ignite/odbc/row.h" + +using namespace ignite::odbc::app; +using namespace ignite::odbc; + + +std::string GetStrColumnValue(size_t rowIdx) +{ + std::stringstream generator("Column 2 test string, row num: "); + generator << rowIdx << ". Some trailing bytes"; + + return generator.str(); +} + +void FillMemWithData(ignite::impl::interop::InteropUnpooledMemory& mem, size_t rowNum) +{ + using namespace ignite::impl::binary; + using namespace ignite::impl::interop; + + InteropOutputStream stream(&mem); + BinaryWriterImpl writer(&stream, 0); + + for (size_t i = 0; i < rowNum; ++i) + { + // Number of columns in page. + writer.WriteInt32(4); + + // First column is int. + writer.WriteInt8(IGNITE_TYPE_LONG); + writer.WriteInt64(static_cast<int64_t>(i * 10)); + + // Second column is string. + const std::string& str(GetStrColumnValue(i)); + + writer.WriteString(str.data(), static_cast<int32_t>(str.size())); + + // Third column is GUID. + ignite::Guid guid(0x2b218f63642a4a64ULL, 0x9674098f388ac298ULL + i); + + writer.WriteGuid(guid); + + // The last column is bool. + writer.WriteInt8(IGNITE_TYPE_BOOL); + writer.WriteBool(i % 2 == 1); + } + + stream.Synchronize(); +} + +void CheckRowData(Row& row, size_t rowIdx) +{ + SqlLen reslen; + + long longBuf; + char strBuf[1024]; + SQLGUID guidBuf; + char bitBuf; + size_t* offset = 0; + + ApplicationDataBuffer appLongBuf(type_traits::IGNITE_ODBC_C_TYPE_SIGNED_LONG, &longBuf, sizeof(longBuf), &reslen, &offset); + ApplicationDataBuffer appStrBuf(type_traits::IGNITE_ODBC_C_TYPE_CHAR, &strBuf, sizeof(strBuf), &reslen, &offset); + ApplicationDataBuffer appGuidBuf(type_traits::IGNITE_ODBC_C_TYPE_GUID, &guidBuf, sizeof(guidBuf), &reslen, &offset); + ApplicationDataBuffer appBitBuf(type_traits::IGNITE_ODBC_C_TYPE_BIT, &bitBuf, sizeof(bitBuf), &reslen, &offset); + + // Checking size. + BOOST_REQUIRE(row.GetSize() == 4); + + // Checking 1st column. + BOOST_REQUIRE(row.ReadColumnToBuffer(1, appLongBuf) == SQL_RESULT_SUCCESS); + BOOST_REQUIRE(longBuf == rowIdx * 10); + + // Checking 2nd column. + BOOST_REQUIRE(row.ReadColumnToBuffer(2, appStrBuf) == SQL_RESULT_SUCCESS); + + std::string strReal(strBuf, static_cast<size_t>(reslen)); + std::string strExpected(GetStrColumnValue(rowIdx)); + + BOOST_REQUIRE(strReal == strExpected); + + // Checking 3rd column. + BOOST_REQUIRE(row.ReadColumnToBuffer(3, appGuidBuf) == SQL_RESULT_SUCCESS); + + BOOST_REQUIRE(guidBuf.Data1 == 0x2b218f63UL); + BOOST_REQUIRE(guidBuf.Data2 == 0x642aU); + BOOST_REQUIRE(guidBuf.Data3 == 0x4a64U); + + BOOST_REQUIRE(guidBuf.Data4[0] == 0x96); + BOOST_REQUIRE(guidBuf.Data4[1] == 0x74); + BOOST_REQUIRE(guidBuf.Data4[2] == 0x09); + BOOST_REQUIRE(guidBuf.Data4[3] == 0x8f); + BOOST_REQUIRE(guidBuf.Data4[4] == 0x38); + BOOST_REQUIRE(guidBuf.Data4[5] == 0x8a); + BOOST_REQUIRE(guidBuf.Data4[6] == 0xc2); + BOOST_REQUIRE(guidBuf.Data4[7] == 0x98 + rowIdx); + + // Checking 4th column. + BOOST_REQUIRE(row.ReadColumnToBuffer(4, appBitBuf) == SQL_RESULT_SUCCESS); + BOOST_REQUIRE(bitBuf == rowIdx % 2); +} + + +BOOST_AUTO_TEST_SUITE(RowTestSuite) + +BOOST_AUTO_TEST_CASE(TestRowMoveToNext) +{ + ignite::impl::interop::InteropUnpooledMemory mem(4096); + + const size_t rowNum = 32; + + FillMemWithData(mem, rowNum); + + Row row(mem); + + for (size_t i = 0; i < rowNum - 1; ++i) + { + BOOST_REQUIRE(row.GetSize() == 4); + + BOOST_REQUIRE(row.MoveToNext()); + } + + BOOST_REQUIRE(row.GetSize() == 4); +} + +BOOST_AUTO_TEST_CASE(TestRowRead) +{ + ignite::impl::interop::InteropUnpooledMemory mem(4096); + + const size_t rowNum = 8; + + FillMemWithData(mem, rowNum); + + Row row(mem); + + BOOST_REQUIRE(row.GetSize() == 4); + + for (size_t i = 0; i < rowNum - 1; ++i) + { + CheckRowData(row, i); + + BOOST_REQUIRE(row.MoveToNext()); + } + + CheckRowData(row, rowNum - 1); +} + +BOOST_AUTO_TEST_CASE(TestSingleRow) +{ + ignite::impl::interop::InteropUnpooledMemory mem(4096); + + const size_t rowNum = 1; + + FillMemWithData(mem, 1); + + Row row(mem); + + BOOST_REQUIRE(row.GetSize() == 4); + + CheckRowData(row, 0); +} + +BOOST_AUTO_TEST_CASE(TestTwoRows) +{ + ignite::impl::interop::InteropUnpooledMemory mem(4096); + + const size_t rowNum = 2; + + FillMemWithData(mem, 2); + + Row row(mem); + + BOOST_REQUIRE(row.GetSize() == 4); + + CheckRowData(row, 0); + + BOOST_REQUIRE(row.MoveToNext()); + + BOOST_REQUIRE(row.GetSize() == 4); + + CheckRowData(row, 1); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/modules/platforms/cpp/odbc-test/src/teamcity/teamcity_boost.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/src/teamcity/teamcity_boost.cpp b/modules/platforms/cpp/odbc-test/src/teamcity/teamcity_boost.cpp new file mode 100644 index 0000000..9a14fe9 --- /dev/null +++ b/modules/platforms/cpp/odbc-test/src/teamcity/teamcity_boost.cpp @@ -0,0 +1,159 @@ +/* Copyright 2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Revision: 88625 $ +*/ + +#define BOOST_TEST_MODULE IgniteOdbcTest + +#include <sstream> + +#include <boost/test/unit_test_suite_impl.hpp> +#include <boost/test/results_collector.hpp> +#include <boost/test/utils/basic_cstring/io.hpp> +#include <boost/test/unit_test_log.hpp> +#include <boost/test/included/unit_test.hpp> + +#include "teamcity/teamcity_messages.h" + +using namespace boost::unit_test; +using namespace std; + +namespace JetBrains { + +// Custom formatter for TeamCity messages +class TeamcityBoostLogFormatter: public boost::unit_test::unit_test_log_formatter { + TeamcityMessages messages; + std::string currentDetails; + std::string flowId; + +public: + TeamcityBoostLogFormatter(const std::string &_flowId); + TeamcityBoostLogFormatter(); + + void log_start(std::ostream&, boost::unit_test::counter_t test_cases_amount); + void log_finish(std::ostream&); + void log_build_info(std::ostream&); + + void test_unit_start(std::ostream&, boost::unit_test::test_unit const& tu); + void test_unit_finish(std::ostream&, + boost::unit_test::test_unit const& tu, + unsigned long elapsed); + void test_unit_skipped(std::ostream&, boost::unit_test::test_unit const& tu); + + void log_exception(std::ostream&, + boost::unit_test::log_checkpoint_data const&, + boost::unit_test::const_string explanation); + + void log_entry_start(std::ostream&, + boost::unit_test::log_entry_data const&, + log_entry_types let); + void log_entry_value(std::ostream&, boost::unit_test::const_string value); + void log_entry_finish(std::ostream&); +}; + +// Fake fixture to register formatter +struct TeamcityFormatterRegistrar { + TeamcityFormatterRegistrar() { + if (JetBrains::underTeamcity()) { + boost::unit_test::unit_test_log.set_formatter(new JetBrains::TeamcityBoostLogFormatter()); + boost::unit_test::unit_test_log.set_threshold_level(boost::unit_test::log_successful_tests); + } + } +}; +BOOST_GLOBAL_FIXTURE(TeamcityFormatterRegistrar); + +// Formatter implementation +string toString(const_string bstr) { + stringstream ss; + + ss << bstr; + + return ss.str(); +} + +TeamcityBoostLogFormatter::TeamcityBoostLogFormatter(const std::string &_flowId) +: flowId(_flowId) +{} + +TeamcityBoostLogFormatter::TeamcityBoostLogFormatter() +: flowId(getFlowIdFromEnvironment()) +{} + +void TeamcityBoostLogFormatter::log_start(ostream &out, counter_t test_cases_amount) +{} + +void TeamcityBoostLogFormatter::log_finish(ostream &out) +{} + +void TeamcityBoostLogFormatter::log_build_info(ostream &out) +{} + +void TeamcityBoostLogFormatter::test_unit_start(ostream &out, test_unit const& tu) { + messages.setOutput(out); + + if (tu.p_type == tut_case) { + messages.testStarted(tu.p_name, flowId); + } else { + messages.suiteStarted(tu.p_name, flowId); + } + + currentDetails.clear(); +} + +void TeamcityBoostLogFormatter::test_unit_finish(ostream &out, test_unit const& tu, unsigned long elapsed) { + messages.setOutput(out); + + test_results const& tr = results_collector.results(tu.p_id); + if (tu.p_type == tut_case) { + if(!tr.passed()) { + if(tr.p_skipped) { + messages.testIgnored(tu.p_name, "ignored", flowId); + } else if (tr.p_aborted) { + messages.testFailed(tu.p_name, "aborted", currentDetails, flowId); + } else { + messages.testFailed(tu.p_name, "failed", currentDetails, flowId); + } + } + + messages.testFinished(tu.p_name, elapsed / 1000, flowId); + } else { + messages.suiteFinished(tu.p_name, flowId); + } +} + +void TeamcityBoostLogFormatter::test_unit_skipped(ostream &out, test_unit const& tu) +{} + +void TeamcityBoostLogFormatter::log_exception(ostream &out, log_checkpoint_data const&, const_string explanation) { + string what = toString(explanation); + + out << what << endl; + currentDetails += what + "\n"; +} + +void TeamcityBoostLogFormatter::log_entry_start(ostream&, log_entry_data const&, log_entry_types let) +{} + +void TeamcityBoostLogFormatter::log_entry_value(ostream &out, const_string value) { + out << value; + currentDetails += toString(value); +} + +void TeamcityBoostLogFormatter::log_entry_finish(ostream &out) { + out << endl; + currentDetails += "\n"; +} + +} http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/modules/platforms/cpp/odbc-test/src/teamcity/teamcity_messages.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/src/teamcity/teamcity_messages.cpp b/modules/platforms/cpp/odbc-test/src/teamcity/teamcity_messages.cpp new file mode 100644 index 0000000..1f224af --- /dev/null +++ b/modules/platforms/cpp/odbc-test/src/teamcity/teamcity_messages.cpp @@ -0,0 +1,150 @@ +/* Copyright 2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Revision: 88625 $ +*/ + +#include <stdlib.h> +#include <sstream> + +#include "teamcity/teamcity_messages.h" + +using namespace std; + +namespace JetBrains { + +std::string getFlowIdFromEnvironment() { + const char *flowId = getenv("TEAMCITY_PROCESS_FLOW_ID"); + return flowId == NULL ? "" : flowId; +} + +bool underTeamcity() { + return getenv("TEAMCITY_PROJECT_NAME") != NULL; +} + +TeamcityMessages::TeamcityMessages() +: m_out(&cout) +{} + +void TeamcityMessages::setOutput(ostream &out) { + m_out = &out; +} + +string TeamcityMessages::escape(string s) { + string result; + + for (size_t i = 0; i < s.length(); i++) { + char c = s[i]; + + switch (c) { + case '\n': result.append("|n"); break; + case '\r': result.append("|r"); break; + case '\'': result.append("|'"); break; + case '|': result.append("||"); break; + case ']': result.append("|]"); break; + default: result.append(1, c); + } + } + + return result; +} + +void TeamcityMessages::openMsg(const string &name) { + // endl for http://jetbrains.net/tracker/issue/TW-4412 + *m_out << endl << "##teamcity[" << name; +} + +void TeamcityMessages::closeMsg() { + *m_out << "]"; + // endl for http://jetbrains.net/tracker/issue/TW-4412 + *m_out << endl; + m_out->flush(); +} + +void TeamcityMessages::writeProperty(string name, string value) { + *m_out << " " << name << "='" << escape(value) << "'"; +} + +void TeamcityMessages::suiteStarted(string name, string flowid) { + openMsg("testSuiteStarted"); + writeProperty("name", name); + if(flowid.length() > 0) { + writeProperty("flowId", flowid); + } + + closeMsg(); +} + +void TeamcityMessages::suiteFinished(string name, string flowid) { + openMsg("testSuiteFinished"); + writeProperty("name", name); + if(flowid.length() > 0) { + writeProperty("flowId", flowid); + } + + closeMsg(); +} + +void TeamcityMessages::testStarted(string name, string flowid) { + openMsg("testStarted"); + writeProperty("name", name); + if(flowid.length() > 0) { + writeProperty("flowId", flowid); + } + + closeMsg(); +} + +void TeamcityMessages::testFinished(string name, int durationMs, string flowid) { + openMsg("testFinished"); + + writeProperty("name", name); + + if(flowid.length() > 0) { + writeProperty("flowId", flowid); + } + + if(durationMs >= 0) { + stringstream out; + out << durationMs; + writeProperty("duration", out.str()); + } + + closeMsg(); +} + +void TeamcityMessages::testFailed(string name, string message, string details, string flowid) { + openMsg("testFailed"); + writeProperty("name", name); + writeProperty("message", message); + writeProperty("details", details); + if(flowid.length() > 0) { + writeProperty("flowId", flowid); + } + + closeMsg(); +} + +void TeamcityMessages::testIgnored(std::string name, std::string message, string flowid) { + openMsg("testIgnored"); + writeProperty("name", name); + writeProperty("message", message); + if(flowid.length() > 0) { + writeProperty("flowId", flowid); + } + + closeMsg(); +} + +} http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/modules/platforms/cpp/odbc-test/src/utility_test.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/src/utility_test.cpp b/modules/platforms/cpp/odbc-test/src/utility_test.cpp new file mode 100644 index 0000000..6c4d104 --- /dev/null +++ b/modules/platforms/cpp/odbc-test/src/utility_test.cpp @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MSC_VER +# define BOOST_TEST_DYN_LINK +#endif + +#include <boost/test/unit_test.hpp> + +#include <ignite/impl/binary/binary_writer_impl.h> + +#include <ignite/odbc/utility.h> + +using namespace ignite::utility; + +BOOST_AUTO_TEST_SUITE(UtilityTestSuite) + +BOOST_AUTO_TEST_CASE(TestUtilityRemoveSurroundingSpaces) +{ + std::string inStr(" \r \n \t some meaningfull data \n\n \t \r "); + std::string expectedOutStr("some meaningfull data"); + + std::string realOutStr(RemoveSurroundingSpaces(inStr.begin(), inStr.end())); + + BOOST_REQUIRE(expectedOutStr == realOutStr); +} + +BOOST_AUTO_TEST_CASE(TestUtilityCopyStringToBuffer) +{ + char buffer[1024]; + + std::string str("Some data. And some more data here."); + + CopyStringToBuffer(str, buffer, sizeof(buffer)); + + BOOST_REQUIRE(!strcmp(buffer, str.c_str())); + + CopyStringToBuffer(str, buffer, 11); + + BOOST_REQUIRE(!strcmp(buffer, str.substr(0, 10).c_str())); +} + +BOOST_AUTO_TEST_CASE(TestUtilityReadString) +{ + using namespace ignite::impl::binary; + using namespace ignite::impl::interop; + + std::string inputStr("Hello World!"); + std::string outputStr; + + ignite::impl::interop::InteropUnpooledMemory mem(1024); + InteropOutputStream outStream(&mem); + BinaryWriterImpl writer(&outStream, 0); + + writer.WriteString(inputStr.data(), static_cast<int32_t>(inputStr.size())); + + outStream.Synchronize(); + + InteropInputStream inStream(&mem); + BinaryReaderImpl reader(&inStream); + + ReadString(reader, outputStr); + + BOOST_REQUIRE(inputStr == outputStr); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/modules/platforms/cpp/odbc/Makefile.am ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/Makefile.am b/modules/platforms/cpp/odbc/Makefile.am new file mode 100644 index 0000000..cb9a2aa --- /dev/null +++ b/modules/platforms/cpp/odbc/Makefile.am @@ -0,0 +1,84 @@ +## +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +ACLOCAL_AMFLAGS =-I m4 + +lib_LTLIBRARIES = libignite-odbc.la + +SUBDIRS = \ + include + +AM_CPPFLAGS = \ + -I$(srcdir)/include \ + -I@top_srcdir@/common/include \ + -I@top_srcdir@/common/os/linux/include \ + -I@top_srcdir@/binary/include \ + -DIGNITE_IMPL + +AM_CXXFLAGS = \ + -Wall \ + -std=c++0x + +libignite_odbc_la_LIBADD = \ + @top_srcdir@/binary/libignite-binary.la + +libignite_odbc_la_LDFLAGS = \ + -no-undefined \ + -ldl \ + -version-info 0:0:0 \ + -release $(PACKAGE_VERSION) + +libignite_odbc_la_DEPENDENCIES = \ + @top_srcdir@/binary/libignite-binary.la + +libignite_odbc_la_SOURCES = \ + os/linux/src/system/socket_client.cpp \ + src/app/application_data_buffer.cpp \ + src/app/parameter.cpp \ + src/common_types.cpp \ + src/config/configuration.cpp \ + src/config/connection_info.cpp \ + src/connection.cpp \ + src/cursor.cpp \ + src/decimal.cpp \ + src/diagnostic/diagnosable_adapter.cpp \ + src/diagnostic/diagnostic_record.cpp \ + src/diagnostic/diagnostic_record_storage.cpp \ + src/environment.cpp \ + src/meta/column_meta.cpp \ + src/meta/table_meta.cpp \ + src/odbc.cpp \ + src/entry_points.cpp \ + src/query/column_metadata_query.cpp \ + src/query/data_query.cpp \ + src/query/foreign_keys_query.cpp \ + src/query/primary_keys_query.cpp \ + src/query/table_metadata_query.cpp \ + src/query/type_info_query.cpp \ + src/query/special_columns_query.cpp \ + src/result_page.cpp \ + src/row.cpp \ + src/column.cpp \ + src/statement.cpp \ + src/type_traits.cpp \ + src/utility.cpp + +clean-local: + $(RM) *.gcno *.gcda + +clean-docs: + $(RM) $(DX_CLEANFILES) http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/modules/platforms/cpp/odbc/README.txt ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/README.txt b/modules/platforms/cpp/odbc/README.txt new file mode 100644 index 0000000..e9d423f --- /dev/null +++ b/modules/platforms/cpp/odbc/README.txt @@ -0,0 +1,88 @@ +Apache Ignite ODBC driver +======================================= + +Apache Ignite provides ODBC driver that can be used to retrieve distributed +data from cache using standard SQL queries and native ODBC API. + +For more info on ODBC please refer to ODBC Programmer's Reference at +https://msdn.microsoft.com/en-us/library/ms714177.aspx + +To use Apache Ignite ODBC driver you first need to build and install it for +your system. You can find driver installation instructions below. For build +instruction please refer to $IGNITE_HOME/platforms/cpp/DEVNOTES.txt. + +Connection string and DSN arguments +======================================= + +Apache Ignite ODBC driver supports and uses following connection string/DSN +arguments: + +1. Address of the node to connect to: + SERVER=<host_name_or_IP_address>; + +2. Port on which OdbcProcessor of the node is listening: + PORT=<TCP_port>; + +3. Datagrid cache to connect to: + CACHE=<cache_name>; + +All arguments are case-insensitive so "SERVER", "Server" and "server" all are +valid server address arguments. + +Installing ODBC driver on Linux +======================================= + +To be able to build and install ODBC driver on Linux you first need to install +ODBC Driver Manager. Apache Ignite ODBC driver has been tested with UnixODBC +(http://www.unixodbc.org). + +Once you have built and installed Ignite ODBC Driver i.e. libignite-odbc.so it +is most likely placed to /usr/local/lib. To install and be able to use Ignite +ODBC driver you should perfrom the following steps: + +1. Ensure linker is able to locate all dependencies of the ODBC driver. You + can check it using "ldd" command like this (assuming ODBC driver is located + under /usr/local/lib): + $ ldd /usr/local/lib/libignite-odbc.so. + +2. Edit file $IGNITE_HOME/platforms/cpp/odbc/install/ignite-odbc-install.ini + and ensure that "Driver" parameter of the "Apache Ignite" section points + to the right location where libignite-odbc.so is located. + +3. To install Apache Ignite ODBC driver use the following command: + $ odbcinst -i -d -f $IGNITE_HOME/platforms/cpp/odbc/install/ignite-odbc-install.ini + To perform this command you most likely will need root privileges. + +Installing ODBC driver on Windows +======================================= + +For 32-bit Windows you should use 32-bit version of the driver while for the +64-bit Windows you can use 64-bit driver as well as 32-bit. + +To install driver on Windows you should first choose a directory on your +filesystem where your driver or drivers will be located. Once you have +choosen the place you should put your driver there and ensure that all driver +dependencies can be resolved i.e. they can be found either in the %PATH% or +in the same directory as the driver. + +After that you should use one of the install scripts from the directory +%IGNITE_HOME%/platforms/cpp/odbc/install: + +For the 32-bit Windows you should use file install_x86.cmd like that: +$ install_x86 <absolute_path_to_32_bit_driver> + +For the 64-bit Windows you should use file install_amd64.cmd like that: +$ install_amd64 <absolute_path_to_64_bit_driver> [<absolute_path_to_32_bit_driver>] + +Most likely you will need OS administrator privileges to execute these scripts. + +Thats it. Your driver/drivers are installed. + +After the installation +======================================= + +Now Apache Ignite ODBC driver is installed and ready for use. You can connect +to it and use it like to any other ODBC driver. + +For further instruction on the usage of the ODBC driver please refer to the +official ODBC documentation. http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/modules/platforms/cpp/odbc/include/Makefile.am ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/Makefile.am b/modules/platforms/cpp/odbc/include/Makefile.am new file mode 100644 index 0000000..db4ffe0 --- /dev/null +++ b/modules/platforms/cpp/odbc/include/Makefile.am @@ -0,0 +1,58 @@ +## +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +ACLOCAL_AMFLAGS =-I m4 + +noinst_HEADERS = \ + ignite/odbc.h \ + ignite/odbc/query/table_metadata_query.h \ + ignite/odbc/query/special_columns_query.h \ + ignite/odbc/query/type_info_query.h \ + ignite/odbc/query/data_query.h \ + ignite/odbc/query/foreign_keys_query.h \ + ignite/odbc/query/column_metadata_query.h \ + ignite/odbc/query/query.h \ + ignite/odbc/query/primary_keys_query.h \ + ignite/odbc/statement.h \ + ignite/odbc/config/configuration.h \ + ignite/odbc/config/connection_info.h \ + ignite/odbc/column.h \ + ignite/odbc/parser.h \ + ignite/odbc/app/application_data_buffer.h \ + ignite/odbc/app/parameter.h \ + ignite/odbc/row.h \ + ignite/odbc/utility.h \ + ignite/odbc/environment.h \ + ignite/odbc/system/odbc_constants.h \ + ignite/odbc/system/socket_client.h \ + ignite/odbc/meta/primary_key_meta.h \ + ignite/odbc/meta/column_meta.h \ + ignite/odbc/meta/table_meta.h \ + ignite/odbc/diagnostic/diagnostic_record.h \ + ignite/odbc/diagnostic/diagnostic_record_storage.h \ + ignite/odbc/diagnostic/diagnosable.h \ + ignite/odbc/diagnostic/diagnosable_adapter.h \ + ignite/odbc/connection.h \ + ignite/odbc/message.h \ + ignite/odbc/cursor.h \ + ignite/odbc/common_types.h \ + ignite/odbc/result_page.h \ + ignite/odbc/decimal.h \ + ignite/odbc/type_traits.h + +uninstall-hook: + if [ -d ${includedir}/ignite ]; then find ${includedir}/ignite -type d -empty -delete; fi http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/modules/platforms/cpp/odbc/include/ignite/odbc.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc.h b/modules/platforms/cpp/odbc/include/ignite/odbc.h new file mode 100644 index 0000000..40158dd --- /dev/null +++ b/modules/platforms/cpp/odbc/include/ignite/odbc.h @@ -0,0 +1,257 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _IGNITE_ODBC_ODBC +#define _IGNITE_ODBC_ODBC + +#include "ignite/odbc/system/odbc_constants.h" + +/** + * @file odbc.h + * + * Functions here are placed to the ignite namespace so there are no + * collisions with standard ODBC functions when we call driver API + * functions from other API functions. I.e, when we call SQLAllocEnv + * from SQLAllocHandle linker can place Driver Manager call here, + * instead of internal driver call. On other hand if we call + * ignite::SQLAllocEnv from ignite::SQLAllocHandle we can be sure + * there are no collisions. + */ + +namespace ignite +{ + BOOL ConfigDSN(HWND hwndParent, + WORD req, + LPCSTR driver, + LPCSTR attributes); + + SQLRETURN SQLGetInfo(SQLHDBC conn, + SQLUSMALLINT infoType, + SQLPOINTER infoValue, + SQLSMALLINT infoValueMax, + SQLSMALLINT* length); + + SQLRETURN SQLAllocHandle(SQLSMALLINT type, SQLHANDLE parent, SQLHANDLE* result); + + SQLRETURN SQLAllocEnv(SQLHENV* env); + + SQLRETURN SQLAllocConnect(SQLHENV env, SQLHDBC* conn); + + SQLRETURN SQLAllocStmt(SQLHDBC conn, SQLHSTMT* stmt); + + SQLRETURN SQLFreeHandle(SQLSMALLINT type, SQLHANDLE handle); + + SQLRETURN SQLFreeEnv(SQLHENV env); + + SQLRETURN SQLFreeConnect(SQLHDBC conn); + + SQLRETURN SQLFreeStmt(SQLHSTMT stmt, SQLUSMALLINT option); + + SQLRETURN SQLCloseCursor(SQLHSTMT stmt); + + SQLRETURN SQLDriverConnect(SQLHDBC conn, + SQLHWND windowHandle, + SQLCHAR* inConnectionString, + SQLSMALLINT inConnectionStringLen, + SQLCHAR* outConnectionString, + SQLSMALLINT outConnectionStringBufferLen, + SQLSMALLINT* outConnectionStringLen, + SQLUSMALLINT driverCompletion); + + SQLRETURN SQLConnect(SQLHDBC conn, + SQLCHAR* serverName, + SQLSMALLINT serverNameLen, + SQLCHAR* userName, + SQLSMALLINT userNameLen, + SQLCHAR* auth, + SQLSMALLINT authLen); + + SQLRETURN SQLDisconnect(SQLHDBC conn); + + SQLRETURN SQLPrepare(SQLHSTMT stmt, SQLCHAR* query, SQLINTEGER queryLen); + + SQLRETURN SQLExecute(SQLHSTMT stmt); + + SQLRETURN SQLExecDirect(SQLHSTMT stmt, SQLCHAR* query, SQLINTEGER queryLen); + + SQLRETURN SQLBindCol(SQLHSTMT stmt, + SQLUSMALLINT colNum, + SQLSMALLINT targetType, + SQLPOINTER targetValue, + SQLLEN bufferLength, + SQLLEN* strLengthOrIndicator); + + SQLRETURN SQLFetch(SQLHSTMT stmt); + + SQLRETURN SQLFetchScroll(SQLHSTMT stmt, SQLSMALLINT orientation, SQLLEN offset); + + SQLRETURN SQLExtendedFetch(SQLHSTMT stmt, + SQLUSMALLINT orientation, + SQLLEN offset, + SQLULEN* rowCount, + SQLUSMALLINT* rowStatusArray); + + SQLRETURN SQLNumResultCols(SQLHSTMT stmt, SQLSMALLINT *columnNum); + + SQLRETURN SQLTables(SQLHSTMT stmt, + SQLCHAR* catalogName, + SQLSMALLINT catalogNameLen, + SQLCHAR* schemaName, + SQLSMALLINT schemaNameLen, + SQLCHAR* tableName, + SQLSMALLINT tableNameLen, + SQLCHAR* tableType, + SQLSMALLINT tableTypeLen); + + SQLRETURN SQLColumns(SQLHSTMT stmt, + SQLCHAR* catalogName, + SQLSMALLINT catalogNameLen, + SQLCHAR* schemaName, + SQLSMALLINT schemaNameLen, + SQLCHAR* tableName, + SQLSMALLINT tableNameLen, + SQLCHAR* columnName, + SQLSMALLINT columnNameLen); + + SQLRETURN SQLMoreResults(SQLHSTMT stmt); + + SQLRETURN SQLBindParameter(SQLHSTMT stmt, + SQLUSMALLINT paramIdx, + SQLSMALLINT ioType, + SQLSMALLINT bufferType, + SQLSMALLINT paramSqlType, + SQLULEN columnSize, + SQLSMALLINT decDigits, + SQLPOINTER buffer, + SQLLEN bufferLen, + SQLLEN* resLen); + + SQLRETURN SQLNativeSql(SQLHDBC conn, + SQLCHAR* inQuery, + SQLINTEGER inQueryLen, + SQLCHAR* outQueryBuffer, + SQLINTEGER outQueryBufferLen, + SQLINTEGER* outQueryLen); + + SQLRETURN SQLColAttribute(SQLHSTMT stmt, + SQLUSMALLINT columnNum, + SQLUSMALLINT fieldId, + SQLPOINTER strAttr, + SQLSMALLINT bufferLen, + SQLSMALLINT* strAttrLen, + SQLLEN* numericAttr); + + SQLRETURN SQLDescribeCol(SQLHSTMT stmt, + SQLUSMALLINT columnNum, + SQLCHAR* columnNameBuf, + SQLSMALLINT columnNameBufLen, + SQLSMALLINT* columnNameLen, + SQLSMALLINT* dataType, + SQLULEN* columnSize, + SQLSMALLINT* decimalDigits, + SQLSMALLINT* nullable); + + SQLRETURN SQLRowCount(SQLHSTMT stmt, SQLLEN* rowCnt); + + SQLRETURN SQLForeignKeys(SQLHSTMT stmt, + SQLCHAR* primaryCatalogName, + SQLSMALLINT primaryCatalogNameLen, + SQLCHAR* primarySchemaName, + SQLSMALLINT primarySchemaNameLen, + SQLCHAR* primaryTableName, + SQLSMALLINT primaryTableNameLen, + SQLCHAR* foreignCatalogName, + SQLSMALLINT foreignCatalogNameLen, + SQLCHAR* foreignSchemaName, + SQLSMALLINT foreignSchemaNameLen, + SQLCHAR* foreignTableName, + SQLSMALLINT foreignTableNameLen); + + SQLRETURN SQLGetStmtAttr(SQLHSTMT stmt, + SQLINTEGER attr, + SQLPOINTER valueBuf, + SQLINTEGER valueBufLen, + SQLINTEGER* valueResLen); + + SQLRETURN SQLSetStmtAttr(SQLHSTMT stmt, + SQLINTEGER attr, + SQLPOINTER value, + SQLINTEGER valueLen); + + SQLRETURN SQLPrimaryKeys(SQLHSTMT stmt, + SQLCHAR* catalogName, + SQLSMALLINT catalogNameLen, + SQLCHAR* schemaName, + SQLSMALLINT schemaNameLen, + SQLCHAR* tableName, + SQLSMALLINT tableNameLen); + + SQLRETURN SQLNumParams(SQLHSTMT stmt, SQLSMALLINT* paramCnt); + + SQLRETURN SQLGetDiagField(SQLSMALLINT handleType, + SQLHANDLE handle, + SQLSMALLINT recNum, + SQLSMALLINT diagId, + SQLPOINTER buffer, + SQLSMALLINT bufferLen, + SQLSMALLINT* resLen); + + SQLRETURN SQLGetDiagRec(SQLSMALLINT handleType, + SQLHANDLE handle, + SQLSMALLINT recNum, + SQLCHAR* sqlState, + SQLINTEGER* nativeError, + SQLCHAR* msgBuffer, + SQLSMALLINT msgBufferLen, + SQLSMALLINT* msgLen); + + SQLRETURN SQLGetTypeInfo(SQLHSTMT stmt, SQLSMALLINT type); + + SQLRETURN SQLEndTran(SQLSMALLINT handleType, SQLHANDLE handle, SQLSMALLINT completionType); + + SQLRETURN SQLGetData(SQLHSTMT stmt, + SQLUSMALLINT colNum, + SQLSMALLINT targetType, + SQLPOINTER targetValue, + SQLLEN bufferLength, + SQLLEN* strLengthOrIndicator); + + SQLRETURN SQLSetEnvAttr(SQLHENV env, + SQLINTEGER attr, + SQLPOINTER value, + SQLINTEGER valueLen); + + SQLRETURN SQLGetEnvAttr(SQLHENV env, + SQLINTEGER attr, + SQLPOINTER valueBuf, + SQLINTEGER valueBufLen, + SQLINTEGER* valueResLen); + + SQLRETURN SQLSpecialColumns(SQLHSTMT stmt, + SQLSMALLINT idType, + SQLCHAR* catalogName, + SQLSMALLINT catalogNameLen, + SQLCHAR* schemaName, + SQLSMALLINT schemaNameLen, + SQLCHAR* tableName, + SQLSMALLINT tableNameLen, + SQLSMALLINT scope, + SQLSMALLINT nullable); + +} // namespace ignite + +#endif //_IGNITE_ODBC \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/modules/platforms/cpp/odbc/include/ignite/odbc/app/application_data_buffer.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/app/application_data_buffer.h b/modules/platforms/cpp/odbc/include/ignite/odbc/app/application_data_buffer.h new file mode 100644 index 0000000..4d7460b --- /dev/null +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/app/application_data_buffer.h @@ -0,0 +1,379 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _IGNITE_ODBC_APP_APPLICATION_DATA_BUFFER +#define _IGNITE_ODBC_APP_APPLICATION_DATA_BUFFER + +#include <stdint.h> + +#include <map> + +#include <ignite/guid.h> +#include <ignite/date.h> +#include <ignite/timestamp.h> + +#include "ignite/odbc/decimal.h" +#include "ignite/odbc/common_types.h" +#include "ignite/odbc/type_traits.h" + +namespace ignite +{ + namespace odbc + { + namespace app + { + /** + * User application data buffer. + */ + class ApplicationDataBuffer + { + public: + /** + * Default constructor. + */ + ApplicationDataBuffer(); + + /** + * Constructor. + * + * @param type Underlying data type. + * @param buffer Data buffer pointer. + * @param buflen Data buffer length. + * @param reslen Resulting data length. + * @param offset Pointer to buffer and reslen offset pointer. + */ + ApplicationDataBuffer(type_traits::IgniteSqlType type, void* buffer, SqlLen buflen, SqlLen* reslen, size_t** offset = 0); + + /** + * Copy constructor. + * + * @param other Other instance. + */ + ApplicationDataBuffer(const ApplicationDataBuffer& other); + + /** + * Destructor. + */ + ~ApplicationDataBuffer(); + + /** + * Copy assigment operator. + * + * @param other Other instance. + * @return This. + */ + ApplicationDataBuffer& operator=(const ApplicationDataBuffer& other); + + /** + * Set pointer to offset pointer. + * + * @param offset Pointer to offset pointer. + */ + void SetPtrToOffsetPtr(size_t** offset) + { + this->offset = offset; + } + + /** + * Put in buffer value of type int8_t. + * + * @param value Value. + */ + void PutInt8(int8_t value); + + /** + * Put in buffer value of type int16_t. + * + * @param value Value. + */ + void PutInt16(int16_t value); + + /** + * Put in buffer value of type int32_t. + * + * @param value Value. + */ + void PutInt32(int32_t value); + + /** + * Put in buffer value of type int64_t. + * + * @param value Value. + */ + void PutInt64(int64_t value); + + /** + * Put in buffer value of type float. + * + * @param value Value. + */ + void PutFloat(float value); + + /** + * Put in buffer value of type double. + * + * @param value Value. + */ + void PutDouble(double value); + + /** + * Put in buffer value of type string. + * + * @param value Value. + * @return Number of bytes that have been put in buffer. + */ + int32_t PutString(const std::string& value); + + /** + * Put in buffer value of type GUID. + * + * @param value Value. + */ + void PutGuid(const Guid& value); + + /** + * Put binary data in buffer. + * + * @param data Data pointer. + * @param len Data length. + * @return Number of bytes that have been put in buffer. + */ + int32_t PutBinaryData(void* data, size_t len); + + /** + * Put NULL. + */ + void PutNull(); + + /** + * Put decimal value to buffer. + * + * @param value Value to put. + */ + void PutDecimal(const Decimal& value); + + /** + * Put date to buffer. + * + * @param value Value to put. + */ + void PutDate(const Date& value); + + /** + * Put timestamp to buffer. + * + * @param value Value to put. + */ + void PutTimestamp(const Timestamp& value); + + /** + * Get string. + * + * @return String value of buffer. + */ + std::string GetString(size_t maxLen) const; + + /** + * Get value of type int8_t. + * + * @return Integer value of type int8_t. + */ + int8_t GetInt8() const; + + /** + * Get value of type int16_t. + * + * @return Integer value of type int16_t. + */ + int16_t GetInt16() const; + + /** + * Get value of type int32_t. + * + * @return Integer value of type int32_t. + */ + int32_t GetInt32() const; + + /** + * Get value of type int64_t. + * + * @return Integer value of type int64_t. + */ + int64_t GetInt64() const; + + /** + * Get value of type float. + * + * @return Integer value of type float. + */ + float GetFloat() const; + + /** + * Get value of type double. + * + * @return Value of type double. + */ + double GetDouble() const; + + /** + * Get value of type GUID. + * + * @return Value of type Guid. + */ + Guid GetGuid() const; + + /** + * Get value of type Date. + * + * @return Value of type Date. + */ + Date GetDate() const; + + /** + * Get value of type Timestamp. + * + * @return Value of type Timestamp. + */ + Timestamp GetTimestamp() const; + + /** + * Get raw data. + * + * @return Buffer data. + */ + const void* GetData() const; + + /** + * Get result data length. + * + * @return Data length pointer. + */ + const SqlLen* GetResLen() const; + + /** + * Get buffer size in bytes. + * + * @return Buffer size. + */ + SqlLen GetSize() const + { + return buflen; + } + + private: + /** + * Get raw data. + * + * @return Buffer data. + */ + void* GetData(); + + /** + * Get result data length. + * + * @return Data length pointer. + */ + SqlLen* GetResLen(); + + /** + * Put value of numeric type in the buffer. + * + * @param value Numeric value to put. + */ + template<typename T> + void PutNum(T value); + + /** + * Put numeric value to numeric buffer. + * + * @param value Numeric value. + */ + template<typename Tbuf, typename Tin> + void PutNumToNumBuffer(Tin value); + + /** + * Put value to string buffer. + * + * @param value Value that can be converted to string. + */ + template<typename CharT, typename Tin> + void PutValToStrBuffer(const Tin& value); + + /** + * Put value to string buffer. + * Specialisation for int8_t. + * @param value Value that can be converted to string. + */ + template<typename CharT> + void PutValToStrBuffer(const int8_t & value); + + /** + * Put string to string buffer. + * + * @param value String value. + */ + template<typename OutCharT, typename InCharT> + void PutStrToStrBuffer(const std::basic_string<InCharT>& value); + + /** + * Put raw data to any buffer. + * + * @param data Data pointer. + * @param len Data length. + */ + void PutRawDataToBuffer(void *data, size_t len); + + /** + * Get int of type T. + * + * @return Integer value of specified type. + */ + template<typename T> + T GetNum() const; + + /** + * Apply buffer offset to pointer. + * Adds offset to pointer if offset pointer is not null. + * @param ptr Pointer. + * @return Pointer with applied offset. + */ + template<typename T> + T* ApplyOffset(T* ptr) const; + + /** Underlying data type. */ + type_traits::IgniteSqlType type; + + /** Buffer pointer. */ + void* buffer; + + /** Buffer length. */ + SqlLen buflen; + + /** Result length. */ + SqlLen* reslen; + + /** Pointer to implementation pointer to application offset */ + size_t** offset; + }; + + /** Column binging map type alias. */ + typedef std::map<uint16_t, ApplicationDataBuffer> ColumnBindingMap; + } + } +} + +#endif //_IGNITE_ODBC_APP_APPLICATION_DATA_BUFFER \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/modules/platforms/cpp/odbc/include/ignite/odbc/app/parameter.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/app/parameter.h b/modules/platforms/cpp/odbc/include/ignite/odbc/app/parameter.h new file mode 100644 index 0000000..d1ea697 --- /dev/null +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/app/parameter.h @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _IGNITE_ODBC_APP_PARAMETER +#define _IGNITE_ODBC_APP_PARAMETER + +#include <stdint.h> + +#include <map> + +#include <ignite/guid.h> +#include <ignite/impl/binary/binary_writer_impl.h> +#include <ignite/impl/binary/binary_reader_impl.h> + +#include "ignite/odbc/app/application_data_buffer.h" +#include "ignite/odbc/type_traits.h" + +namespace ignite +{ + namespace odbc + { + namespace app + { + /** + * Statement parameter. + */ + class Parameter + { + public: + /** + * Default constructor. + */ + Parameter(); + + /** + * Constructor. + * + * @param buffer Underlying data buffer. + * @param sqlType IPD type. + * @param columnSize IPD column size. + * @param decDigits IPD decimal digits. + */ + Parameter(const ApplicationDataBuffer& buffer, int16_t sqlType, + size_t columnSize, int16_t decDigits); + + /** + * Copy constructor. + * + * @param other Other instance. + */ + Parameter(const Parameter& other); + + /** + * Destructor. + */ + ~Parameter(); + + /** + * Copy assigment operator. + * + * @param other Other instance. + * @return This. + */ + Parameter& operator=(const Parameter& other); + + /** + * Write request using provided writer. + * @param writer Writer. + */ + void Write(ignite::impl::binary::BinaryWriterImpl& writer) const; + + /** + * Get data buffer. + * + * @return underlying ApplicationDataBuffer instance. + */ + ApplicationDataBuffer& GetBuffer(); + + private: + /** Underlying data buffer. */ + ApplicationDataBuffer buffer; + + /** IPD type. */ + int16_t sqlType; + + /** IPD column size. */ + size_t columnSize; + + /** IPD decimal digits. */ + int16_t decDigits; + }; + + /** Parameter binging map type alias. */ + typedef std::map<uint16_t, Parameter> ParameterBindingMap; + } + } +} + +#endif //_IGNITE_ODBC_APP_PARAMETER \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/764c97b9/modules/platforms/cpp/odbc/include/ignite/odbc/column.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/column.h b/modules/platforms/cpp/odbc/include/ignite/odbc/column.h new file mode 100644 index 0000000..cd48a40 --- /dev/null +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/column.h @@ -0,0 +1,149 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _IGNITE_ODBC_COLUMN +#define _IGNITE_ODBC_COLUMN + +#include <stdint.h> + +#include <ignite/impl/binary/binary_reader_impl.h> + +#include "ignite/odbc/app/application_data_buffer.h" + +namespace ignite +{ + namespace odbc + { + /** + * Result set column. + */ + class Column + { + public: + /** + * Default constructor. + */ + Column(); + + /** + * Copy constructor. + * + * @param other Another instance. + */ + Column(const Column& other); + + /** + * Copy operator. + * + * @param other Another instance. + * @return This. + */ + Column& operator=(const Column& other); + + /** + * Destructor. + */ + ~Column(); + + /** + * Constructor. + * + * @param reader Reader to be used to retrieve column data. + */ + Column(ignite::impl::binary::BinaryReaderImpl& reader); + + /** + * Get column size in bytes. + * + * @return Column size. + */ + int32_t GetSize() const + { + return size; + } + + /** + * Read column data and store it in application data buffer. + * + * @param dataBuf Application data buffer. + * @return Operation result. + */ + SqlResult ReadToBuffer(ignite::impl::binary::BinaryReaderImpl& reader, + app::ApplicationDataBuffer& dataBuf); + + /** + * Check if the column is in valid state. + * + * @return True if valid. + */ + bool IsValid() const + { + return startPos >= 0; + } + + /** + * Get unread data length. + * Find out how many bytes of data are left unread. + * + * @return Lengh of unread data in bytes. + */ + int32_t GetUnreadDataLength() const + { + return size - offset; + } + + /** + * Get unread data length. + * Find out how many bytes of data are left unread. + * + * @return Lengh of unread data in bytes. + */ + int32_t GetEndPosition() const + { + return endPos; + } + + private: + /** + * Increase offset. + * + * Increases offset on specified value and makes sure resulting + * offset does not exceed column size. + * + * @param value Offset is incremented on this value. + */ + void IncreaseOffset(int32_t value); + + /** Column type */ + int8_t type; + + /** Column position in current row. */ + int32_t startPos; + + /** Column end position in current row. */ + int32_t endPos; + + /** Current offset in column. */ + int32_t offset; + + /** Column data size in bytes. */ + int32_t size; + }; + } +} + +#endif //_IGNITE_ODBC_COLUMN \ No newline at end of file
