IGNITE-3736: ODBC: Added support for string scalar functions. This closes #979.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/c02ad87f Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/c02ad87f Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/c02ad87f Branch: refs/heads/master Commit: c02ad87f863bd730e60fb7052547fa0848e7eb77 Parents: 118db2f Author: isapego <[email protected]> Authored: Wed Aug 24 17:21:48 2016 +0300 Committer: vozerov-gridgain <[email protected]> Committed: Wed Aug 24 17:21:48 2016 +0300 ---------------------------------------------------------------------- modules/platforms/cpp/odbc-test/Makefile.am | 2 + .../cpp/odbc-test/config/queries-test.xml | 7 +- .../platforms/cpp/odbc-test/include/Makefile.am | 3 +- .../cpp/odbc-test/include/test_utils.h | 45 ++ .../cpp/odbc-test/project/vs/odbc-test.vcxproj | 3 + .../project/vs/odbc-test.vcxproj.filters | 9 + .../cpp/odbc-test/src/queries_test.cpp | 41 +- .../odbc-test/src/sql_string_functions_test.cpp | 515 +++++++++++++++++++ .../platforms/cpp/odbc-test/src/test_utils.cpp | 36 ++ .../cpp/odbc/src/config/connection_info.cpp | 64 +-- .../platforms/cpp/odbc/src/query/data_query.cpp | 6 +- 11 files changed, 653 insertions(+), 78 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/c02ad87f/modules/platforms/cpp/odbc-test/Makefile.am ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/Makefile.am b/modules/platforms/cpp/odbc-test/Makefile.am index 48b193a..cc84a7f 100644 --- a/modules/platforms/cpp/odbc-test/Makefile.am +++ b/modules/platforms/cpp/odbc-test/Makefile.am @@ -61,6 +61,8 @@ ignite_odbc_tests_SOURCES = \ src/row_test.cpp \ src/utility_test.cpp \ src/queries_test.cpp \ + src/test_utils.cpp \ + src/sql_string_functions_test.cpp \ ../odbc/src/cursor.cpp \ ../odbc/src/config/connection_info.cpp \ ../odbc/src/app/application_data_buffer.cpp \ http://git-wip-us.apache.org/repos/asf/ignite/blob/c02ad87f/modules/platforms/cpp/odbc-test/config/queries-test.xml ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/config/queries-test.xml b/modules/platforms/cpp/odbc-test/config/queries-test.xml index f08f86d..67415fb 100644 --- a/modules/platforms/cpp/odbc-test/config/queries-test.xml +++ b/modules/platforms/cpp/odbc-test/config/queries-test.xml @@ -26,8 +26,8 @@ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <bean id="grid.cfg" class="org.apache.ignite.configuration.IgniteConfiguration"> - <!-- Set to true to enable distributed class loading for examples, default is false. --> - <property name="peerClassLoadingEnabled" value="true"/> + <property name="localHost" value="127.0.0.1"/> + <property name="connectorConfiguration"><null/></property> <!-- Enabling ODBC. --> <property name="odbcConfiguration"> @@ -84,11 +84,12 @@ <property name="addresses"> <list> <!-- In distributed environment, replace with actual host IP address. --> - <value>127.0.0.1:47500..47501</value> + <value>127.0.0.1:47500</value> </list> </property> </bean> </property> + <property name="socketTimeout" value="300" /> </bean> </property> </bean> http://git-wip-us.apache.org/repos/asf/ignite/blob/c02ad87f/modules/platforms/cpp/odbc-test/include/Makefile.am ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/include/Makefile.am b/modules/platforms/cpp/odbc-test/include/Makefile.am index 6b2d8b6..7b17102 100644 --- a/modules/platforms/cpp/odbc-test/include/Makefile.am +++ b/modules/platforms/cpp/odbc-test/include/Makefile.am @@ -19,5 +19,6 @@ ACLOCAL_AMFLAGS =-I m4 noinst_HEADERS = \ teamcity/teamcity_messages.h \ - test_type.h + test_type.h \ + test_utils.h http://git-wip-us.apache.org/repos/asf/ignite/blob/c02ad87f/modules/platforms/cpp/odbc-test/include/test_utils.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/include/test_utils.h b/modules/platforms/cpp/odbc-test/include/test_utils.h new file mode 100644 index 0000000..e8cd089 --- /dev/null +++ b/modules/platforms/cpp/odbc-test/include/test_utils.h @@ -0,0 +1,45 @@ +/* + * 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_TEST_TEST_UTILS +#define _IGNITE_ODBC_TEST_TEST_UTILS + +#ifdef _WIN32 +# include <windows.h> +#endif + +#include <sql.h> +#include <sqlext.h> + +#include <string> + +namespace ignite +{ + /** 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); +} + +#endif // _IGNITE_ODBC_TEST_TEST_UTILS \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/c02ad87f/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj b/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj index fbc0929..619b4b2 100644 --- a/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj +++ b/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj @@ -168,13 +168,16 @@ <ClCompile Include="..\..\src\queries_test.cpp" /> <ClCompile Include="..\..\src\parser_test.cpp" /> <ClCompile Include="..\..\src\row_test.cpp" /> + <ClCompile Include="..\..\src\sql_string_functions_test.cpp" /> <ClCompile Include="..\..\src\teamcity\teamcity_boost.cpp" /> <ClCompile Include="..\..\src\teamcity\teamcity_messages.cpp" /> + <ClCompile Include="..\..\src\test_utils.cpp" /> <ClCompile Include="..\..\src\utility_test.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\include\teamcity\teamcity_messages.h" /> <ClInclude Include="..\..\include\test_type.h" /> + <ClInclude Include="..\..\include\test_utils.h" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\..\..\binary\project\vs\binary.vcxproj"> http://git-wip-us.apache.org/repos/asf/ignite/blob/c02ad87f/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj.filters ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj.filters b/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj.filters index 2e38c24..1871149 100644 --- a/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj.filters +++ b/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj.filters @@ -76,6 +76,12 @@ <ClCompile Include="..\..\src\queries_test.cpp"> <Filter>Code</Filter> </ClCompile> + <ClCompile Include="..\..\src\sql_string_functions_test.cpp"> + <Filter>Code</Filter> + </ClCompile> + <ClCompile Include="..\..\src\test_utils.cpp"> + <Filter>Code</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\include\test_type.h"> @@ -84,6 +90,9 @@ <ClInclude Include="..\..\include\teamcity\teamcity_messages.h"> <Filter>Code\TeamCity</Filter> </ClInclude> + <ClInclude Include="..\..\include\test_utils.h"> + <Filter>Code</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <None Include="..\..\config\queries-test.xml"> http://git-wip-us.apache.org/repos/asf/ignite/blob/c02ad87f/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 cc3fa8e..2d9bd58 100644 --- a/modules/platforms/cpp/odbc-test/src/queries_test.cpp +++ b/modules/platforms/cpp/odbc-test/src/queries_test.cpp @@ -36,6 +36,7 @@ #include "ignite/impl/binary/binary_utils.h" #include "test_type.h" +#include "test_utils.h" using namespace ignite; using namespace ignite::cache; @@ -46,30 +47,6 @@ 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. */ @@ -98,7 +75,9 @@ struct QueriesTestSuiteFixture char* cfgPath = getenv("IGNITE_NATIVE_TEST_ODBC_CONFIG_PATH"); - cfg.springCfgPath = std::string(cfgPath).append("/").append("queries-test.xml"); + BOOST_REQUIRE(cfgPath != 0); + + cfg.springCfgPath.assign(cfgPath).append("/queries-test.xml"); IgniteError err; @@ -178,7 +157,7 @@ struct QueriesTestSuiteFixture T columns[columnsCnt] = { 0 }; - // Binding colums. + // Binding columns. for (SQLSMALLINT i = 0; i < columnsCnt; ++i) { ret = SQLBindCol(stmt, i + 1, type, &columns[i], sizeof(columns[i]), 0); @@ -214,7 +193,7 @@ struct QueriesTestSuiteFixture SQLLEN columnLens[columnsCnt] = { 0 }; - // Binding colums. + // Binding columns. for (SQLSMALLINT i = 0; i < columnsCnt; ++i) { ret = SQLBindCol(stmt, i + 1, type, &columns[i], sizeof(columns[i]), &columnLens[i]); @@ -327,7 +306,7 @@ BOOST_AUTO_TEST_CASE(TestTwoRowsString) SQLCHAR columns[columnsCnt][ODBC_BUFFER_SIZE] = { 0 }; - // Binding colums. + // Binding columns. for (SQLSMALLINT i = 0; i < columnsCnt; ++i) { ret = SQLBindCol(stmt, i + 1, SQL_C_CHAR, &columns[i], ODBC_BUFFER_SIZE, 0); @@ -364,7 +343,7 @@ BOOST_AUTO_TEST_CASE(TestTwoRowsString) SQLLEN columnLens[columnsCnt] = { 0 }; - // Binding colums. + // Binding columns. for (SQLSMALLINT i = 0; i < columnsCnt; ++i) { ret = SQLBindCol(stmt, i + 1, SQL_C_CHAR, &columns[i], ODBC_BUFFER_SIZE, &columnLens[i]); @@ -420,7 +399,7 @@ BOOST_AUTO_TEST_CASE(TestOneRowString) SQLLEN columnLens[columnsCnt] = { 0 }; - // Binding colums. + // Binding columns. for (SQLSMALLINT i = 0; i < columnsCnt; ++i) { ret = SQLBindCol(stmt, i + 1, SQL_C_CHAR, &columns[i], ODBC_BUFFER_SIZE, &columnLens[i]); @@ -479,7 +458,7 @@ BOOST_AUTO_TEST_CASE(TestOneRowStringLen) SQLLEN columnLens[columnsCnt] = { 0 }; - // Binding colums. + // Binding columns. for (SQLSMALLINT i = 0; i < columnsCnt; ++i) { ret = SQLBindCol(stmt, i + 1, SQL_C_CHAR, 0, 0, &columnLens[i]); http://git-wip-us.apache.org/repos/asf/ignite/blob/c02ad87f/modules/platforms/cpp/odbc-test/src/sql_string_functions_test.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/src/sql_string_functions_test.cpp b/modules/platforms/cpp/odbc-test/src/sql_string_functions_test.cpp new file mode 100644 index 0000000..e84aba6 --- /dev/null +++ b/modules/platforms/cpp/odbc-test/src/sql_string_functions_test.cpp @@ -0,0 +1,515 @@ +/* + * 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. + */ + +#define _USE_MATH_DEFINES + +#ifdef _WIN32 +# include <windows.h> +#endif + +#include <sql.h> +#include <sqlext.h> + +#include <cmath> + +#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" +#include "test_utils.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; + +/** + * Test setup fixture. + */ +struct SqlStringFunctionTestSuiteFixture +{ + /** + * Constructor. + */ + SqlStringFunctionTestSuiteFixture() : + 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"); + + BOOST_REQUIRE(cfgPath != 0); + + cfg.springCfgPath.assign(cfgPath).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. + */ + ~SqlStringFunctionTestSuiteFixture() + { + // 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); + } + + void CheckSingleResult0(const char* request, SQLSMALLINT type, void* column, SQLLEN bufSize, SQLLEN* resSize) + { + SQLRETURN ret; + + ret = SQLBindCol(stmt, 1, type, column, bufSize, resSize); + + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + ret = SQLExecDirect(stmt, reinterpret_cast<SQLCHAR*>(const_cast<char*>(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)); + + ret = SQLFetch(stmt); + BOOST_CHECK(ret == SQL_NO_DATA); + } + + /** + * Run query returning single result and check it to be equal to expected. + * + * @param request SQL request. + * @param expected Expected result. + */ + template<typename T> + void CheckSingleResult(const char* request, const T& expected) + { + BOOST_FAIL("Function is not defined for the type."); + } + + /** + * Run query returning single result and check it to be equal to expected. + * + * @param request SQL request. + * @param expected Expected result. + * @param type Result type. + */ + template<typename T> + void CheckSingleResultNum0(const char* request, const T& expected, SQLSMALLINT type) + { + T res = 0; + + CheckSingleResult0(request, type, &res, 0, 0); + + BOOST_CHECK_EQUAL(res, expected); + } + + + /** 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; +}; + +template<> +void SqlStringFunctionTestSuiteFixture::CheckSingleResult<std::string>(const char* request, const std::string& expected) +{ + SQLCHAR res[ODBC_BUFFER_SIZE] = { 0 }; + SQLLEN resLen = 0; + + CheckSingleResult0(request, SQL_C_CHAR, res, ODBC_BUFFER_SIZE, &resLen); + + BOOST_CHECK_EQUAL(std::string(reinterpret_cast<char*>(res), static_cast<size_t>(resLen)), expected); +} + +template<> +void SqlStringFunctionTestSuiteFixture::CheckSingleResult<int64_t>(const char* request, const int64_t& expected) +{ + CheckSingleResultNum0<int64_t>(request, expected, SQL_C_SBIGINT); +} + +template<> +void SqlStringFunctionTestSuiteFixture::CheckSingleResult<int32_t>(const char* request, const int32_t& expected) +{ + CheckSingleResultNum0<int32_t>(request, expected, SQL_C_SLONG); +} + +template<> +void SqlStringFunctionTestSuiteFixture::CheckSingleResult<int16_t>(const char* request, const int16_t& expected) +{ + CheckSingleResultNum0<int16_t>(request, expected, SQL_C_SSHORT); +} + +template<> +void SqlStringFunctionTestSuiteFixture::CheckSingleResult<int8_t>(const char* request, const int8_t& expected) +{ + CheckSingleResultNum0<int8_t>(request, expected, SQL_C_STINYINT); +} + +template<> +void SqlStringFunctionTestSuiteFixture::CheckSingleResult<float>(const char* request, const float& expected) +{ + SQLFLOAT res = 0; + + CheckSingleResult0(request, SQL_C_FLOAT, &res, 0, 0); + + BOOST_CHECK_CLOSE(static_cast<float>(res), expected, 1E-6f); +} + +template<> +void SqlStringFunctionTestSuiteFixture::CheckSingleResult<double>(const char* request, const double& expected) +{ + SQLDOUBLE res = 0; + + CheckSingleResult0(request, SQL_C_DOUBLE, &res, 0, 0); + + BOOST_CHECK_CLOSE(static_cast<double>(res), expected, 1E-6); +} + +BOOST_FIXTURE_TEST_SUITE(SqlStringFunctionTestSuite, SqlStringFunctionTestSuiteFixture) + +BOOST_AUTO_TEST_CASE(TestStringFunctionAscii) +{ + TestType in; + + in.strField = "Hi"; + + testCache.Put(1, in); + + CheckSingleResult<int32_t>("SELECT {fn ASCII(strField)} FROM TestType", static_cast<int32_t>('H')); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionBitLength) +{ + TestType in; + in.strField = "Lorem ipsum dolor"; + + testCache.Put(1, in); + + CheckSingleResult<int64_t>("SELECT {fn BIT_LENGTH(strField)} FROM TestType", in.strField.size() * 16); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionChar) +{ + TestType in; + + in.i32Field = static_cast<int32_t>('H'); + + testCache.Put(1, in); + + CheckSingleResult<std::string>("SELECT {fn CHAR(i32Field)} FROM TestType", "H"); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionCharLength) +{ + TestType in; + in.strField = "Lorem ipsum dolor"; + + testCache.Put(1, in); + + CheckSingleResult<int64_t>("SELECT {fn CHAR_LENGTH(strField)} FROM TestType", in.strField.size()); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionCharacterLength) +{ + TestType in; + in.strField = "Lorem ipsum dolor"; + + testCache.Put(1, in); + + CheckSingleResult<int64_t>("SELECT {fn CHARACTER_LENGTH(strField)} FROM TestType", in.strField.size()); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionConcat) +{ + TestType in; + in.strField = "Lorem ipsum dolor sit amet,"; + + testCache.Put(1, in); + + CheckSingleResult<std::string>("SELECT {fn CONCAT(strField, \' consectetur adipiscing elit\')} FROM TestType", + in.strField + " consectetur adipiscing elit"); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionDifference) +{ + TestType in; + in.strField = "Hello"; + + testCache.Put(1, in); + + CheckSingleResult<int32_t>("SELECT {fn DIFFERENCE(strField, \'Hola!\')} FROM TestType", 4); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionInsert) +{ + TestType in; + in.strField = "Hello World!"; + + testCache.Put(1, in); + + CheckSingleResult<std::string>("SELECT {fn INSERT(strField, 7, 5, \'Ignite\')} FROM TestType", "Hello Ignite!"); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionLcase) +{ + TestType in; + in.strField = "Hello World!"; + + testCache.Put(1, in); + + CheckSingleResult<std::string>("SELECT {fn LCASE(strField)} FROM TestType", "hello world!"); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionLeft) +{ + TestType in; + in.strField = "Hello World!"; + + testCache.Put(1, in); + + CheckSingleResult<std::string>("SELECT {fn LEFT(strField, 5)} FROM TestType", "Hello"); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionLength) +{ + TestType in; + in.strField = "Lorem ipsum dolor sit amet, consectetur adipiscing elit"; + + testCache.Put(1, in); + + CheckSingleResult<int64_t>("SELECT {fn LENGTH(strField)} FROM TestType", in.strField.size()); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionLocate) +{ + TestType in; + in.strField = "Lorem ipsum dolor sit amet, consectetur adipiscing elit"; + + testCache.Put(1, in); + + CheckSingleResult<int64_t>("SELECT {fn LOCATE(\'ip\', strField)} FROM TestType", 7); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionLocate2) +{ + TestType in; + in.strField = "Lorem ipsum dolor sit amet, consectetur adipiscing elit"; + + testCache.Put(1, in); + + CheckSingleResult<int64_t>("SELECT {fn LOCATE(\'ip\', strField, 10)} FROM TestType", 43); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionLtrim) +{ + TestType in; + in.strField = " Lorem ipsum "; + + testCache.Put(1, in); + + CheckSingleResult<std::string>("SELECT {fn LTRIM(strField)} FROM TestType", "Lorem ipsum "); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionOctetLength) +{ + TestType in; + in.strField = "Lorem ipsum dolor sit amet, consectetur adipiscing elit"; + + testCache.Put(1, in); + + CheckSingleResult<int64_t>("SELECT {fn OCTET_LENGTH(strField)} FROM TestType", in.strField.size() * 2); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionPosition) +{ + TestType in; + in.strField = "Lorem ipsum dolor sit amet, consectetur adipiscing elit"; + + testCache.Put(1, in); + + CheckSingleResult<int64_t>("SELECT {fn POSITION(\'sit\', strField)} FROM TestType", 19); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionRepeat) +{ + TestType in; + in.strField = "Test"; + + testCache.Put(1, in); + + CheckSingleResult<std::string>("SELECT {fn REPEAT(strField,4)} FROM TestType", "TestTestTestTest"); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionReplace) +{ + TestType in; + in.strField = "Hello Ignite!"; + + testCache.Put(1, in); + + CheckSingleResult<std::string>("SELECT {fn REPLACE(strField, \'Ignite\', \'World\')} FROM TestType", "Hello World!"); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionRight) +{ + TestType in; + in.strField = "Hello World!"; + + testCache.Put(1, in); + + CheckSingleResult<std::string>("SELECT {fn RIGHT(strField, 6)} FROM TestType", "World!"); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionRtrim) +{ + TestType in; + in.strField = " Lorem ipsum "; + + testCache.Put(1, in); + + CheckSingleResult<std::string>("SELECT {fn RTRIM(strField)} FROM TestType", " Lorem ipsum"); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionSoundex) +{ + TestType in; + in.strField = "Hello Ignite!"; + + testCache.Put(1, in); + + CheckSingleResult<std::string>("SELECT {fn SOUNDEX(strField)} FROM TestType", "H425"); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionSpace) +{ + CheckSingleResult<std::string>("SELECT {fn SPACE(10)}", " "); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionSubstring) +{ + TestType in; + in.strField = "Hello Ignite!"; + + testCache.Put(1, in); + + CheckSingleResult<std::string>("SELECT {fn SUBSTRING(strField, 7, 6)} FROM TestType", "Ignite"); +} + +BOOST_AUTO_TEST_CASE(TestStringFunctionUcase) +{ + TestType in; + in.strField = "Hello World!"; + + testCache.Put(1, in); + + CheckSingleResult<std::string>("SELECT {fn UCASE(strField)} FROM TestType", "HELLO WORLD!"); +} + +BOOST_AUTO_TEST_SUITE_END() http://git-wip-us.apache.org/repos/asf/ignite/blob/c02ad87f/modules/platforms/cpp/odbc-test/src/test_utils.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/src/test_utils.cpp b/modules/platforms/cpp/odbc-test/src/test_utils.cpp new file mode 100644 index 0000000..48f409b --- /dev/null +++ b/modules/platforms/cpp/odbc-test/src/test_utils.cpp @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#include "test_utils.h" + +namespace ignite +{ + + 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); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/c02ad87f/modules/platforms/cpp/odbc/src/config/connection_info.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/config/connection_info.cpp b/modules/platforms/cpp/odbc/src/config/connection_info.cpp index 7f0e3bd..f35b790 100644 --- a/modules/platforms/cpp/odbc/src/config/connection_info.cpp +++ b/modules/platforms/cpp/odbc/src/config/connection_info.cpp @@ -124,7 +124,7 @@ namespace ignite #ifdef SQL_COLUMN_ALIAS // A character string: "Y" if the data source supports column // aliases; otherwise, "N". - strParams[SQL_COLUMN_ALIAS] = "N"; + strParams[SQL_COLUMN_ALIAS] = "Y"; #endif // SQL_COLUMN_ALIAS #ifdef SQL_IDENTIFIER_QUOTE_CHAR @@ -192,7 +192,7 @@ namespace ignite #ifdef SQL_GETDATA_EXTENSIONS // Bitmask enumerating extensions to SQLGetData. - intParams[SQL_GETDATA_EXTENSIONS] = SQL_GD_ANY_COLUMN; + intParams[SQL_GETDATA_EXTENSIONS] = SQL_GD_ANY_COLUMN | SQL_GD_ANY_ORDER | SQL_GD_BOUND; #endif // SQL_GETDATA_EXTENSIONS #ifdef SQL_ODBC_INTERFACE_CONFORMANCE @@ -203,7 +203,7 @@ namespace ignite #ifdef SQL_SQL_CONFORMANCE // Indicates the level of SQL-92 supported by the driver. - intParams[SQL_SQL_CONFORMANCE] = 0; // SQL_SC_SQL92_ENTRY; + intParams[SQL_SQL_CONFORMANCE] = SQL_SC_SQL92_ENTRY; #endif // SQL_SQL_CONFORMANCE #ifdef SQL_CATALOG_USAGE @@ -213,7 +213,8 @@ namespace ignite #ifdef SQL_SCHEMA_USAGE // Bitmask enumerating the statements in which schemas can be used. - intParams[SQL_SCHEMA_USAGE] = 0; + intParams[SQL_SCHEMA_USAGE] = SQL_SU_DML_STATEMENTS | + SQL_SU_TABLE_DEFINITION | SQL_SU_PRIVILEGE_DEFINITION; #endif // SQL_SCHEMA_USAGE #ifdef SQL_MAX_IDENTIFIER_LEN @@ -224,21 +225,24 @@ namespace ignite #ifdef SQL_AGGREGATE_FUNCTIONS // Bitmask enumerating support for aggregation functions. - intParams[SQL_AGGREGATE_FUNCTIONS] = SQL_AF_ALL | SQL_AF_AVG | - SQL_AF_COUNT | SQL_AF_DISTINCT | SQL_AF_MAX | SQL_AF_MIN | - SQL_AF_SUM; + intParams[SQL_AGGREGATE_FUNCTIONS] = 0; #endif // SQL_AGGREGATE_FUNCTIONS #ifdef SQL_NUMERIC_FUNCTIONS // Bitmask enumerating the scalar numeric functions supported by // the driver and associated data source. - intParams[SQL_NUMERIC_FUNCTIONS] = SQL_FN_NUM_ABS; + intParams[SQL_NUMERIC_FUNCTIONS] = 0; #endif // SQL_NUMERIC_FUNCTIONS #ifdef SQL_STRING_FUNCTIONS // Bitmask enumerating the scalar string functions supported by the // driver and associated data source. - intParams[SQL_STRING_FUNCTIONS] = 0; + intParams[SQL_STRING_FUNCTIONS] = SQL_FN_STR_ASCII | SQL_FN_STR_BIT_LENGTH | SQL_FN_STR_CHAR | + SQL_FN_STR_CONCAT | SQL_FN_STR_DIFFERENCE | SQL_FN_STR_INSERT | SQL_FN_STR_LEFT | + SQL_FN_STR_LENGTH | SQL_FN_STR_LOCATE | SQL_FN_STR_LTRIM | SQL_FN_STR_OCTET_LENGTH | + SQL_FN_STR_POSITION | SQL_FN_STR_REPEAT | SQL_FN_STR_REPLACE | SQL_FN_STR_RIGHT | SQL_FN_STR_RTRIM | + SQL_FN_STR_SOUNDEX | SQL_FN_STR_SPACE | SQL_FN_STR_SUBSTRING | SQL_FN_STR_LCASE | SQL_FN_STR_UCASE | + SQL_FN_STR_LOCATE_2 | SQL_FN_STR_CHAR_LENGTH | SQL_FN_STR_CHARACTER_LENGTH; #endif // SQL_STRING_FUNCTIONS #ifdef SQL_TIMEDATE_FUNCTIONS @@ -262,15 +266,7 @@ namespace ignite #ifdef SQL_DATETIME_LITERALS // Bitmask enumerating the SQL-92 datetime literals supported by // the data source. - intParams[SQL_DATETIME_LITERALS] = SQL_DL_SQL92_INTERVAL_HOUR | - SQL_DL_SQL92_DATE | SQL_DL_SQL92_INTERVAL_MINUTE_TO_SECOND | - SQL_DL_SQL92_TIME | SQL_DL_SQL92_INTERVAL_HOUR_TO_SECOND | - SQL_DL_SQL92_TIMESTAMP | SQL_DL_SQL92_INTERVAL_HOUR_TO_MINUTE | - SQL_DL_SQL92_INTERVAL_YEAR | SQL_DL_SQL92_INTERVAL_DAY_TO_SECOND | - SQL_DL_SQL92_INTERVAL_MONTH | SQL_DL_SQL92_INTERVAL_DAY_TO_HOUR | - SQL_DL_SQL92_INTERVAL_DAY | SQL_DL_SQL92_INTERVAL_DAY_TO_MINUTE | - SQL_DL_SQL92_INTERVAL_MINUTE | SQL_DL_SQL92_INTERVAL_SECOND | - SQL_DL_SQL92_INTERVAL_YEAR_TO_MONTH; + intParams[SQL_DATETIME_LITERALS] = 0; #endif // SQL_DATETIME_LITERALS #ifdef SQL_SYSTEM_FUNCTIONS @@ -288,9 +284,7 @@ namespace ignite #ifdef SQL_OJ_CAPABILITIES // Bitmask enumerating the types of outer joins supported by the // driver and data source. - intParams[SQL_OJ_CAPABILITIES] = SQL_OJ_LEFT | SQL_OJ_RIGHT | - SQL_OJ_FULL | SQL_OJ_NESTED | SQL_OJ_INNER | - SQL_OJ_ALL_COMPARISON_OPS; + intParams[SQL_OJ_CAPABILITIES] = 0; #endif // SQL_OJ_CAPABILITIES #ifdef SQL_POS_OPERATIONS @@ -305,42 +299,36 @@ namespace ignite #ifdef SQL_SQL92_STRING_FUNCTIONS // Bitmask enumerating the string scalar functions. - intParams[SQL_SQL92_STRING_FUNCTIONS] = 0; + intParams[SQL_SQL92_STRING_FUNCTIONS] = SQL_SSF_CONVERT | SQL_SSF_LOWER | SQL_SSF_UPPER | + SQL_SSF_SUBSTRING | SQL_SSF_TRANSLATE; #endif // SQL_SQL92_STRING_FUNCTIONS #ifdef SQL_SQL92_DATETIME_FUNCTIONS // Bitmask enumerating the datetime scalar functions. - intParams[SQL_SQL92_DATETIME_FUNCTIONS] = SQL_SDF_CURRENT_DATE | - SQL_SDF_CURRENT_TIMESTAMP; + intParams[SQL_SQL92_DATETIME_FUNCTIONS] = 0; #endif // SQL_SQL92_DATETIME_FUNCTIONS #ifdef SQL_SQL92_VALUE_EXPRESSIONS // Bitmask enumerating the value expressions supported, // as defined in SQL-92. intParams[SQL_SQL92_VALUE_EXPRESSIONS] = SQL_SVE_CASE | - SQL_SVE_COALESCE | SQL_SVE_NULLIF; + SQL_SVE_CAST | SQL_SVE_COALESCE | SQL_SVE_NULLIF; #endif // SQL_SQL92_VALUE_EXPRESSIONS #ifdef SQL_SQL92_PREDICATES // Bitmask enumerating the datetime scalar functions. - intParams[SQL_SQL92_PREDICATES] = SQL_SP_BETWEEN | - SQL_SP_COMPARISON | SQL_SP_EXISTS | SQL_SP_IN | - SQL_SP_ISNOTNULL | SQL_SP_ISNULL | SQL_SP_LIKE | - SQL_SP_MATCH_FULL | SQL_SP_MATCH_PARTIAL | - SQL_SP_MATCH_UNIQUE_FULL | SQL_SP_MATCH_UNIQUE_PARTIAL | - SQL_SP_OVERLAPS | SQL_SP_QUANTIFIED_COMPARISON | - SQL_SP_UNIQUE; + intParams[SQL_SQL92_PREDICATES] = SQL_SP_BETWEEN | SQL_SP_COMPARISON | SQL_SP_EXISTS | SQL_SP_IN | + SQL_SP_ISNOTNULL | SQL_SP_ISNULL | SQL_SP_LIKE | SQL_SP_MATCH_FULL | SQL_SP_MATCH_PARTIAL | + SQL_SP_MATCH_UNIQUE_FULL | SQL_SP_MATCH_UNIQUE_PARTIAL | SQL_SP_OVERLAPS | SQL_SP_UNIQUE | + SQL_SP_QUANTIFIED_COMPARISON; #endif // SQL_SQL92_PREDICATES #ifdef SQL_SQL92_RELATIONAL_JOIN_OPERATORS // Bitmask enumerating the relational join operators supported // in a SELECT statement, as defined in SQL-92. - intParams[SQL_SQL92_RELATIONAL_JOIN_OPERATORS] = - SQL_SRJO_CORRESPONDING_CLAUSE | SQL_SRJO_CROSS_JOIN | - SQL_SRJO_EXCEPT_JOIN | SQL_SRJO_EXCEPT_JOIN | - SQL_SRJO_INNER_JOIN | SQL_SRJO_INTERSECT_JOIN | - SQL_SRJO_LEFT_OUTER_JOIN | SQL_SRJO_NATURAL_JOIN | - SQL_SRJO_RIGHT_OUTER_JOIN | SQL_SRJO_UNION_JOIN; + intParams[SQL_SQL92_RELATIONAL_JOIN_OPERATORS] = SQL_SRJO_CORRESPONDING_CLAUSE | SQL_SRJO_CROSS_JOIN | + SQL_SRJO_EXCEPT_JOIN | SQL_SRJO_INNER_JOIN | SQL_SRJO_LEFT_OUTER_JOIN| SQL_SRJO_RIGHT_OUTER_JOIN | + SQL_SRJO_NATURAL_JOIN | SQL_SRJO_INTERSECT_JOIN | SQL_SRJO_UNION_JOIN; #endif // SQL_SQL92_RELATIONAL_JOIN_OPERATORS //========================= Short Params ========================== http://git-wip-us.apache.org/repos/asf/ignite/blob/c02ad87f/modules/platforms/cpp/odbc/src/query/data_query.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/query/data_query.cpp b/modules/platforms/cpp/odbc/src/query/data_query.cpp index e96f1da..183bbb5 100644 --- a/modules/platforms/cpp/odbc/src/query/data_query.cpp +++ b/modules/platforms/cpp/odbc/src/query/data_query.cpp @@ -141,11 +141,7 @@ namespace ignite SqlResult DataQuery::Close() { if (!cursor.get()) - { - diag.AddStatusRecord(SQL_STATE_HY010_SEQUENCE_ERROR, "Query cursor is not in open state."); - - return SQL_RESULT_ERROR; - } + return SQL_RESULT_SUCCESS; SqlResult result = MakeRequestClose();
