IGNITE-3577: ODBC: Added simplified "Address" porperty. This closes #898.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/8386dd86 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/8386dd86 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/8386dd86 Branch: refs/heads/master Commit: 8386dd867a82e9814b43d54cca588a5d7a82ef4b Parents: 33d35b3 Author: isapego <isap...@gridgain.com> Authored: Thu Jul 28 13:42:32 2016 +0300 Committer: vozerov-gridgain <voze...@gridgain.com> Committed: Thu Jul 28 13:42:32 2016 +0300 ---------------------------------------------------------------------- .../cpp/common/include/ignite/common/utils.h | 18 ++ .../cpp/core-test/config/cache-query.xml | 3 +- .../cpp/odbc-test/config/queries-test.xml | 9 +- .../cpp/odbc-test/src/configuration_test.cpp | 110 ++++++--- .../cpp/odbc-test/src/queries_test.cpp | 91 +++++--- .../include/ignite/odbc/config/configuration.h | 121 ++++++++-- .../cpp/odbc/include/ignite/odbc/connection.h | 38 ++-- .../cpp/odbc/src/config/configuration.cpp | 227 +++++++++---------- modules/platforms/cpp/odbc/src/connection.cpp | 47 ++-- modules/platforms/cpp/odbc/src/odbc.cpp | 27 ++- 10 files changed, 436 insertions(+), 255 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/8386dd86/modules/platforms/cpp/common/include/ignite/common/utils.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/common/include/ignite/common/utils.h b/modules/platforms/cpp/common/include/ignite/common/utils.h index c1046e2..331fcb2 100644 --- a/modules/platforms/cpp/common/include/ignite/common/utils.h +++ b/modules/platforms/cpp/common/include/ignite/common/utils.h @@ -179,6 +179,24 @@ namespace ignite return res; } + + /** + * Check if the predicate returns true for all the elements of the + * sequence. + * + * @return True if the predicate returns true for all the elements + * of the sequence and false otherwise. + */ + template<typename Iter, typename Pred> + bool AllOf(Iter begin, Iter end, Pred pred) + { + Iter i = begin; + + while (i != end && pred(*i)) + ++i; + + return i == end; + } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/8386dd86/modules/platforms/cpp/core-test/config/cache-query.xml ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core-test/config/cache-query.xml b/modules/platforms/cpp/core-test/config/cache-query.xml index 06bc7f5..c3b5389 100644 --- a/modules/platforms/cpp/core-test/config/cache-query.xml +++ b/modules/platforms/cpp/core-test/config/cache-query.xml @@ -119,11 +119,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/8386dd86/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..054da42 100644 --- a/modules/platforms/cpp/odbc-test/config/queries-test.xml +++ b/modules/platforms/cpp/odbc-test/config/queries-test.xml @@ -26,12 +26,14 @@ 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"> - <bean class="org.apache.ignite.configuration.OdbcConfiguration"></bean> + <bean class="org.apache.ignite.configuration.OdbcConfiguration"> + <property name="endpointAddress" value="127.0.0.1:11110"/> + </bean> </property> <property name="cacheConfiguration"> @@ -89,6 +91,7 @@ </property> </bean> </property> + <property name="socketTimeout" value="300" /> </bean> </property> </bean> http://git-wip-us.apache.org/repos/asf/ignite/blob/8386dd86/modules/platforms/cpp/odbc-test/src/configuration_test.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/src/configuration_test.cpp b/modules/platforms/cpp/odbc-test/src/configuration_test.cpp index 85aa3ff..10fd137 100644 --- a/modules/platforms/cpp/odbc-test/src/configuration_test.cpp +++ b/modules/platforms/cpp/odbc-test/src/configuration_test.cpp @@ -24,47 +24,70 @@ #include <boost/test/unit_test.hpp> #include <ignite/odbc/config/configuration.h> +#include <ignite/ignite_error.h> +#include <ignite/common/utils.h> using namespace ignite::odbc::config; namespace { - const char* testDriverName = "Ignite"; - const char* testServerHost = "testhost.com"; + const std::string testDriverName = "Ignite Driver"; + const std::string testServerHost = "testhost.com"; const uint16_t testServerPort = 4242; - const char* testCacheName = "TestCache"; - const char* testDsn = "Ignite DSN"; + const std::string testCacheName = "TestCache"; + const std::string testDsn = "Ignite DSN"; + + const std::string testAddress = testServerHost + ':' + ignite::common::LexicalCast<std::string>(testServerPort); } -BOOST_AUTO_TEST_SUITE(ConfigurationTestSuite) +void CheckValidAddress(const char* connectStr, uint16_t port) +{ + Configuration cfg; + + BOOST_CHECK_NO_THROW(cfg.FillFromConnectString(connectStr)); + + BOOST_CHECK_EQUAL(cfg.GetPort(), port); +} void CheckConnectionConfig(const Configuration& cfg) { - BOOST_REQUIRE(cfg.GetDriver() == testDriverName); - BOOST_REQUIRE(cfg.GetHost() == testServerHost); - BOOST_REQUIRE(cfg.GetPort() == testServerPort); - BOOST_REQUIRE(cfg.GetCache() == testCacheName); - BOOST_REQUIRE(cfg.GetDsn().empty()); + BOOST_CHECK_EQUAL(cfg.GetDriver(), testDriverName); + BOOST_CHECK_EQUAL(cfg.GetHost(), testServerHost); + BOOST_CHECK_EQUAL(cfg.GetPort(), testServerPort); + BOOST_CHECK_EQUAL(cfg.GetAddress(), testAddress); + BOOST_CHECK_EQUAL(cfg.GetCache(), testCacheName); + BOOST_CHECK_EQUAL(cfg.GetDsn(), std::string()); std::stringstream constructor; - constructor << "driver={" << testDriverName << "};" - << "server=" << testServerHost << ";" - << "port=" << testServerPort << ";" - << "cache=" << testCacheName << ";"; + constructor << "address=" << testAddress << ';' + << "cache=" << testCacheName << ';' + << "driver={" << testDriverName << "};"; const std::string& expectedStr = constructor.str(); - BOOST_REQUIRE(cfg.ToConnectString() == expectedStr); + BOOST_CHECK_EQUAL(cfg.ToConnectString(), expectedStr); } void CheckDsnConfig(const Configuration& cfg) { - BOOST_REQUIRE(cfg.GetDriver() == testDriverName); - BOOST_REQUIRE(cfg.GetDsn() == testDsn); - BOOST_REQUIRE(cfg.GetHost().empty()); - BOOST_REQUIRE(cfg.GetCache().empty()); - BOOST_REQUIRE(cfg.GetPort() == 0); + BOOST_CHECK_EQUAL(cfg.GetDriver(), testDriverName); + BOOST_CHECK_EQUAL(cfg.GetDsn(), testDsn); + BOOST_CHECK_EQUAL(cfg.GetCache(), Configuration::DefaultValue::cache); + BOOST_CHECK_EQUAL(cfg.GetAddress(), Configuration::DefaultValue::address); + BOOST_CHECK_EQUAL(cfg.GetHost(), std::string()); + BOOST_CHECK_EQUAL(cfg.GetPort(), Configuration::DefaultValue::uintPort); +} + +BOOST_AUTO_TEST_SUITE(ConfigurationTestSuite) + +BOOST_AUTO_TEST_CASE(CheckTestValuesNotEquealDefault) +{ + BOOST_CHECK_NE(testDriverName, Configuration::DefaultValue::driver); + BOOST_CHECK_NE(testAddress, Configuration::DefaultValue::address); + BOOST_CHECK_NE(testServerPort, Configuration::DefaultValue::uintPort); + BOOST_CHECK_NE(testCacheName, Configuration::DefaultValue::cache); + BOOST_CHECK_NE(testDsn, Configuration::DefaultValue::dsn); } BOOST_AUTO_TEST_CASE(TestConnectStringUppercase) @@ -74,13 +97,12 @@ BOOST_AUTO_TEST_CASE(TestConnectStringUppercase) std::stringstream constructor; constructor << "DRIVER={" << testDriverName << "};" - << "SERVER=" << testServerHost <<";" - << "PORT=" << testServerPort << ";" + << "ADDRESS=" << testAddress << ';' << "CACHE=" << testCacheName; const std::string& connectStr = constructor.str(); - cfg.FillFromConnectString(connectStr.c_str(), connectStr.size()); + cfg.FillFromConnectString(connectStr); CheckConnectionConfig(cfg); } @@ -92,13 +114,12 @@ BOOST_AUTO_TEST_CASE(TestConnectStringLowercase) std::stringstream constructor; constructor << "driver={" << testDriverName << "};" - << "server=" << testServerHost << ";" - << "port=" << testServerPort << ";" + << "address=" << testAddress << ';' << "cache=" << testCacheName; const std::string& connectStr = constructor.str(); - cfg.FillFromConnectString(connectStr.c_str(), connectStr.size()); + cfg.FillFromConnectString(connectStr); CheckConnectionConfig(cfg); } @@ -110,8 +131,7 @@ BOOST_AUTO_TEST_CASE(TestConnectStringZeroTerminated) std::stringstream constructor; constructor << "driver={" << testDriverName << "};" - << "server=" << testServerHost << ";" - << "port=" << testServerPort << ";" + << "address=" << testAddress << ';' << "cache=" << testCacheName; const std::string& connectStr = constructor.str(); @@ -128,13 +148,12 @@ BOOST_AUTO_TEST_CASE(TestConnectStringMixed) std::stringstream constructor; constructor << "Driver={" << testDriverName << "};" - << "Server=" << testServerHost << ";" - << "Port=" << testServerPort << ";" + << "Address=" << testAddress << ';' << "Cache=" << testCacheName; const std::string& connectStr = constructor.str(); - cfg.FillFromConnectString(connectStr.c_str(), connectStr.size()); + cfg.FillFromConnectString(connectStr); CheckConnectionConfig(cfg); } @@ -146,17 +165,40 @@ BOOST_AUTO_TEST_CASE(TestConnectStringWhitepaces) std::stringstream constructor; constructor << "DRIVER = {" << testDriverName << "} ;\n" - << " SERVER =" << testServerHost << " ; \n" - << "PORT= " << testServerPort << "; " + << " ADDRESS =" << testAddress << "; " << "CACHE = \n\r" << testCacheName; const std::string& connectStr = constructor.str(); - cfg.FillFromConnectString(connectStr.c_str(), connectStr.size()); + cfg.FillFromConnectString(connectStr); CheckConnectionConfig(cfg); } +BOOST_AUTO_TEST_CASE(TestConnectStringInvalidAddress) +{ + Configuration cfg; + + BOOST_CHECK_THROW(cfg.FillFromConnectString("Address=example.com:0;"), ignite::IgniteError); + BOOST_CHECK_THROW(cfg.FillFromConnectString("Address=example.com:00000;"), ignite::IgniteError); + BOOST_CHECK_THROW(cfg.FillFromConnectString("Address=example.com:fdsf;"), ignite::IgniteError); + BOOST_CHECK_THROW(cfg.FillFromConnectString("Address=example.com:123:1;"), ignite::IgniteError); + BOOST_CHECK_THROW(cfg.FillFromConnectString("Address=example.com:12322221;"), ignite::IgniteError); + BOOST_CHECK_THROW(cfg.FillFromConnectString("Address=example.com:12322a;"), ignite::IgniteError); + BOOST_CHECK_THROW(cfg.FillFromConnectString("Address=example.com:;"), ignite::IgniteError); +} + +BOOST_AUTO_TEST_CASE(TestConnectStringValidAddress) +{ + Configuration cfg; + + CheckValidAddress("Address=example.com:1;", 1); + CheckValidAddress("Address=example.com:31242;", 31242); + CheckValidAddress("Address=example.com:55555;", 55555); + CheckValidAddress("Address=example.com:110;", 110); + CheckValidAddress("Address=example.com;", Configuration::DefaultValue::uintPort); +} + BOOST_AUTO_TEST_CASE(TestDsnStringUppercase) { Configuration cfg; http://git-wip-us.apache.org/repos/asf/ignite/blob/8386dd86/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..ccb3a4d 100644 --- a/modules/platforms/cpp/odbc-test/src/queries_test.cpp +++ b/modules/platforms/cpp/odbc-test/src/queries_test.cpp @@ -24,6 +24,7 @@ #include <vector> #include <string> +#include <algorithm> #ifndef _MSC_VER # define BOOST_TEST_DYN_LINK @@ -76,39 +77,12 @@ std::string GetOdbcErrorMessage(SQLSMALLINT handleType, SQLHANDLE handle) struct QueriesTestSuiteFixture { /** - * Constructor. + * Establish connection to node. + * + * @param connectStr Connection string. */ - QueriesTestSuiteFixture() : testCache(0), env(NULL), dbc(NULL), stmt(NULL) + void Connect(const std::string& connectStr) { - 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); @@ -123,13 +97,16 @@ struct QueriesTestSuiteFixture BOOST_REQUIRE(dbc != NULL); // Connect string - SQLCHAR connectStr[] = "DRIVER={Apache Ignite};SERVER=localhost;PORT=10800;CACHE=cache"; + std::vector<SQLCHAR> connectStr0; + + connectStr0.reserve(connectStr.size() + 1); + std::copy(connectStr.begin(), connectStr.end(), std::back_inserter(connectStr0)); SQLCHAR outstr[ODBC_BUFFER_SIZE]; SQLSMALLINT outstrlen; // Connecting to ODBC server. - SQLRETURN ret = SQLDriverConnect(dbc, NULL, connectStr, static_cast<SQLSMALLINT>(sizeof(connectStr)), + SQLRETURN ret = SQLDriverConnect(dbc, NULL, &connectStr0[0], static_cast<SQLSMALLINT>(connectStr0.size()), outstr, sizeof(outstr), &outstrlen, SQL_DRIVER_COMPLETE); if (!SQL_SUCCEEDED(ret)) @@ -146,6 +123,41 @@ 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"); + } + + /** * Destructor. */ ~QueriesTestSuiteFixture() @@ -166,6 +178,8 @@ struct QueriesTestSuiteFixture template<typename T> void CheckTwoRowsInt(SQLSMALLINT type) { + Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;CACHE=cache"); + 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)); @@ -273,6 +287,11 @@ struct QueriesTestSuiteFixture BOOST_FIXTURE_TEST_SUITE(QueriesTestSuite, QueriesTestSuiteFixture) +BOOST_AUTO_TEST_CASE(TestLegacyConnection) +{ + Connect("DRIVER={Apache Ignite};SERVER=127.0.0.1;PORT=11110;CACHE=cache"); +} + BOOST_AUTO_TEST_CASE(TestTwoRowsInt8) { CheckTwoRowsInt<int8_t>(SQL_C_STINYINT); @@ -315,6 +334,8 @@ BOOST_AUTO_TEST_CASE(TestTwoRowsUint64) BOOST_AUTO_TEST_CASE(TestTwoRowsString) { + Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;CACHE=cache"); + 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)); @@ -408,6 +429,8 @@ BOOST_AUTO_TEST_CASE(TestTwoRowsString) BOOST_AUTO_TEST_CASE(TestOneRowString) { + Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;CACHE=cache"); + SQLRETURN ret; TestType in(1, 2, 3, 4, "5", 6.0f, 7.0, true, Guid(8, 9), BinaryUtils::MakeDateGmt(1987, 6, 5), BinaryUtils::MakeTimestampGmt(1998, 12, 27, 1, 2, 3, 456)); @@ -469,6 +492,8 @@ BOOST_AUTO_TEST_CASE(TestOneRowString) BOOST_AUTO_TEST_CASE(TestOneRowStringLen) { + Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;CACHE=cache"); + SQLRETURN ret; TestType in(1, 2, 3, 4, "5", 6.0f, 7.0, true, Guid(8, 9), BinaryUtils::MakeDateGmt(1987, 6, 5), BinaryUtils::MakeTimestampGmt(1998, 12, 27, 1, 2, 3, 456)); http://git-wip-us.apache.org/repos/asf/ignite/blob/8386dd86/modules/platforms/cpp/odbc/include/ignite/odbc/config/configuration.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/config/configuration.h b/modules/platforms/cpp/odbc/include/ignite/odbc/config/configuration.h index d6d7944..05fe8bf 100644 --- a/modules/platforms/cpp/odbc/include/ignite/odbc/config/configuration.h +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/config/configuration.h @@ -23,6 +23,7 @@ #include <map> #include <ignite/common/common.h> +#include <ignite/common/utils.h> namespace ignite { @@ -36,6 +37,68 @@ namespace ignite class Configuration { public: + /** Map containing connect arguments. */ + typedef std::map<std::string, std::string> ArgumentMap; + + /** Connection attribute keywords. */ + struct Key + { + /** Connection attribute keyword for DSN attribute. */ + static const std::string dsn; + + /** Connection attribute keyword for Driver attribute. */ + static const std::string driver; + + /** Connection attribute keyword for cache attribute. */ + static const std::string cache; + + /** Connection attribute keyword for address attribute. */ + static const std::string address; + + /** Connection attribute keyword for server attribute. */ + static const std::string server; + + /** Connection attribute keyword for port attribute. */ + static const std::string port; + }; + + /** Default values for configuration. */ + struct DefaultValue + { + /** Default value for DSN attribute. */ + static const std::string dsn; + + /** Default value for Driver attribute. */ + static const std::string driver; + + /** Default value for cache attribute. */ + static const std::string cache; + + /** Default value for address attribute. */ + static const std::string address; + + /** Default value for server attribute. */ + static const std::string server; + + /** Default value for port attribute. */ + static const std::string port; + + /** Default value for port attribute. Uint16 value. */ + static const uint16_t uintPort; + }; + + /** + * Connection end point structure. + */ + struct EndPoint + { + /** Remote host. */ + std::string host; + + /** TCP port. */ + uint16_t port; + }; + /** * Default constructor. */ @@ -83,7 +146,7 @@ namespace ignite */ uint16_t GetPort() const { - return port; + return endPoint.port; } /** @@ -93,7 +156,7 @@ namespace ignite */ const std::string& GetDsn() const { - return dsn; + return GetStringValue(Key::dsn, DefaultValue::dsn); } /** @@ -103,7 +166,7 @@ namespace ignite */ const std::string& GetDriver() const { - return driver; + return GetStringValue(Key::driver, DefaultValue::driver); } /** @@ -113,7 +176,7 @@ namespace ignite */ const std::string& GetHost() const { - return host; + return endPoint.host; } /** @@ -123,15 +186,29 @@ namespace ignite */ const std::string& GetCache() const { - return cache; + return GetStringValue(Key::cache, DefaultValue::cache); } - private: - IGNITE_NO_COPY_ASSIGNMENT(Configuration); + /** + * Get address. + * + * @return Address. + */ + const std::string& GetAddress() const + { + return GetStringValue(Key::address, DefaultValue::address); + } - /** Map containing connect arguments. */ - typedef std::map<std::string, std::string> ArgumentMap; + /** + * Get string value from the config. + * + * @param key Configuration key. + * @param dflt Default value to be returned if there is no value stored. + * @return Found or default value. + */ + const std::string& GetStringValue(const std::string& key, const std::string& dflt) const; + private: /** * Parse connect string into key-value storage. * @@ -139,22 +216,22 @@ namespace ignite * @param len String length. * @param params Parsing result. */ - void ParseAttributeList(const char* str, size_t len, char delimeter, ArgumentMap& args) const; + static void ParseAttributeList(const char* str, size_t len, char delimeter, ArgumentMap& args); - /** Data Source Name. */ - std::string dsn; - - /** Driver name. */ - std::string driver; - - /** Server hostname. */ - std::string host; + /** + * Parse address and extract connection end-point. + * + * @throw IgniteException if address can not be parsed. + * @param address Address string to parse. + * @param res Result is placed here. + */ + static void ParseAddress(const std::string& address, EndPoint& res); - /** Port of the server. */ - uint16_t port; + /** Arguments. */ + ArgumentMap arguments; - /** Cache name. */ - std::string cache; + /** Connection end-point. */ + EndPoint endPoint; }; } http://git-wip-us.apache.org/repos/asf/ignite/blob/8386dd86/modules/platforms/cpp/odbc/include/ignite/odbc/connection.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/connection.h b/modules/platforms/cpp/odbc/include/ignite/odbc/connection.h index 10ceb19..00bdfc8 100644 --- a/modules/platforms/cpp/odbc/include/ignite/odbc/connection.h +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/connection.h @@ -25,6 +25,7 @@ #include "ignite/odbc/parser.h" #include "ignite/odbc/system/socket_client.h" #include "ignite/odbc/config/connection_info.h" +#include "ignite/odbc/config/configuration.h" #include "ignite/odbc/diagnostic/diagnosable_adapter.h" namespace ignite @@ -74,18 +75,16 @@ namespace ignite /** * Establish connection to ODBC server. * - * @param server Server (DSN). + * @param connectStr Connection string. */ - void Establish(const std::string& server); + void Establish(const std::string& connectStr); /** * Establish connection to ODBC server. * - * @param host Host. - * @param port Port. - * @param cache Cache name to connect to. + * @param cfg Configuration. */ - void Establish(const std::string& host, uint16_t port, const std::string& cache); + void Establish(const config::Configuration cfg); /** * Release established connection. @@ -124,6 +123,13 @@ namespace ignite const std::string& GetCache() const; /** + * Get configuration. + * + * @return Connection configuration. + */ + const config::Configuration& GetConfiguration() const; + + /** * Create diagnostic record associated with the Connection instance. * * @param sqlState SQL state. @@ -132,8 +138,8 @@ namespace ignite * @param columnNum Associated column number. * @return DiagnosticRecord associated with the instance. */ - diagnostic::DiagnosticRecord CreateStatusRecord(SqlState sqlState, - const std::string& message, int32_t rowNum = 0, int32_t columnNum = 0) const; + static diagnostic::DiagnosticRecord CreateStatusRecord(SqlState sqlState, + const std::string& message, int32_t rowNum = 0, int32_t columnNum = 0); /** * Synchronously send request message and receive response. @@ -172,21 +178,19 @@ namespace ignite * Establish connection to ODBC server. * Internal call. * - * @param server Server (DNS). + * @param connectStr Connection string. * @return Operation result. */ - SqlResult InternalEstablish(const std::string& server); + SqlResult InternalEstablish(const std::string& connectStr); /** * Establish connection to ODBC server. * Internal call. * - * @param host Host. - * @param port Port. - * @param cache Cache name to connect to. + * @param cfg Configuration. * @return Operation result. */ - SqlResult InternalEstablish(const std::string& host, uint16_t port, const std::string& cache); + SqlResult InternalEstablish(const config::Configuration cfg); /** * Release established connection. @@ -269,11 +273,11 @@ namespace ignite /** State flag. */ bool connected; - /** Cache name. */ - std::string cache; - /** Message parser. */ Parser parser; + + /** Configuration. */ + config::Configuration config; }; } } http://git-wip-us.apache.org/repos/asf/ignite/blob/8386dd86/modules/platforms/cpp/odbc/src/config/configuration.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/config/configuration.cpp b/modules/platforms/cpp/odbc/src/config/configuration.cpp index 8d57dee..45b0507 100644 --- a/modules/platforms/cpp/odbc/src/config/configuration.cpp +++ b/modules/platforms/cpp/odbc/src/config/configuration.cpp @@ -15,8 +15,6 @@ * limitations under the License. */ -#include <cstring> - #include <string> #include <sstream> #include <algorithm> @@ -31,50 +29,25 @@ namespace ignite { namespace config { - /** Default values for configuration. */ - namespace dflt - { - /** Default value for DSN attribute. */ - const std::string dsn = "Default Apache Ignite DSN"; - - /** Default value for Driver attribute. */ - const std::string driver = "Apache Ignite"; - - /** Default value for host attribute. */ - const std::string host = "localhost"; - - /** Default value for port attribute. */ - const uint16_t port = 10800; - - /** Default value for cache attribute. */ - const std::string cache = ""; - } - - /** Connection attribute keywords. */ - namespace attrkey - { - /** Connection attribute keyword for DSN attribute. */ - const std::string dsn = "dsn"; - - /** Connection attribute keyword for Driver attribute. */ - const std::string driver = "driver"; - - /** Connection attribute keyword for server host attribute. */ - const std::string host = "server"; - - /** Connection attribute keyword for server port attribute. */ - const std::string port = "port"; - - /** Connection attribute keyword for cache attribute. */ - const std::string cache = "cache"; - } + const std::string Configuration::Key::dsn = "dsn"; + const std::string Configuration::Key::driver = "driver"; + const std::string Configuration::Key::cache = "cache"; + const std::string Configuration::Key::address = "address"; + const std::string Configuration::Key::server = "server"; + const std::string Configuration::Key::port = "port"; + + const std::string Configuration::DefaultValue::dsn = "Apache Ignite DSN"; + const std::string Configuration::DefaultValue::driver = "Apache Ignite"; + const std::string Configuration::DefaultValue::cache = ""; + const std::string Configuration::DefaultValue::address = ""; + const std::string Configuration::DefaultValue::server = ""; + const std::string Configuration::DefaultValue::port = "10800"; + const uint16_t Configuration::DefaultValue::uintPort = common::LexicalCast<uint16_t>(port); Configuration::Configuration() : - dsn(dflt::dsn), driver(dflt::driver), - host(dflt::host), port(dflt::port), - cache(dflt::cache) + arguments() { - // No-op. + ParseAddress(DefaultValue::address, endPoint); } Configuration::~Configuration() @@ -84,7 +57,11 @@ namespace ignite void Configuration::FillFromConnectString(const char* str, size_t len) { - ArgumentMap connect_attributes; + // Initializing map. + arguments.clear(); + + // Initializing DSN to empty string. + arguments[Key::dsn].clear(); // Ignoring terminating zero byte if present. // Some Driver Managers pass zero-terminated connection string @@ -92,39 +69,19 @@ namespace ignite if (len && !str[len - 1]) --len; - ParseAttributeList(str, len, ';', connect_attributes); - - ArgumentMap::const_iterator it; + ParseAttributeList(str, len, ';', arguments); - it = connect_attributes.find(attrkey::dsn); - if (it != connect_attributes.end()) - dsn = it->second; - else - dsn.clear(); - - it = connect_attributes.find(attrkey::driver); - if (it != connect_attributes.end()) - driver = it->second; - else - driver = dflt::driver; - - it = connect_attributes.find(attrkey::host); - if (it != connect_attributes.end()) - host = it->second; - else - host = dflt::host; - - it = connect_attributes.find(attrkey::port); - if (it != connect_attributes.end()) - port = atoi(it->second.c_str()); - else - port = dflt::port; - - it = connect_attributes.find(attrkey::cache); - if (it != connect_attributes.end()) - cache = it->second; + ArgumentMap::const_iterator it = arguments.find(Key::address); + if (it != arguments.end()) + { + // Parsing address. + ParseAddress(it->second, endPoint); + } else - cache = dflt::cache; + { + endPoint.host = GetStringValue(Key::server, DefaultValue::server); + endPoint.port = common::LexicalCast<uint16_t>(GetStringValue(Key::port, DefaultValue::port)); + } } void Configuration::FillFromConnectString(const std::string& str) @@ -136,27 +93,27 @@ namespace ignite { std::stringstream connect_string_buffer; - if (!driver.empty()) - connect_string_buffer << attrkey::driver << "={" << driver << "};"; - - if (!host.empty()) - connect_string_buffer << attrkey::host << '=' << host << ';'; - - if (port) - connect_string_buffer << attrkey::port << '=' << port << ';'; + for (ArgumentMap::const_iterator it = arguments.begin(); it != arguments.end(); ++it) + { + const std::string& key = it->first; + const std::string& value = it->second; - if (!dsn.empty()) - connect_string_buffer << attrkey::dsn << '=' << dsn << ';'; + if (value.empty()) + continue; - if (!cache.empty()) - connect_string_buffer << attrkey::cache << '=' << cache << ';'; + if (value.find(' ') == std::string::npos) + connect_string_buffer << key << '=' << value << ';'; + else + connect_string_buffer << key << "={" << value << "};"; + } return connect_string_buffer.str(); } void Configuration::FillFromConfigAttributes(const char * attributes) { - ArgumentMap config_attributes; + // Initializing map. + arguments.clear(); size_t len = 0; @@ -166,45 +123,34 @@ namespace ignite ++len; - ParseAttributeList(attributes, len, '\0', config_attributes); - - ArgumentMap::const_iterator it; - - it = config_attributes.find(attrkey::dsn); - if (it != config_attributes.end()) - dsn = it->second; - else - dsn = dflt::dsn; + ParseAttributeList(attributes, len, '\0', arguments); - it = config_attributes.find(attrkey::driver); - if (it != config_attributes.end()) - driver = it->second; + ArgumentMap::const_iterator it = arguments.find(Key::address); + if (it != arguments.end()) + { + // Parsing address. + ParseAddress(it->second, endPoint); + } else - driver.clear(); + { + endPoint.host = GetStringValue(Key::server, DefaultValue::server); + endPoint.port = common::LexicalCast<uint16_t>(GetStringValue(Key::port, DefaultValue::port)); + } + } - it = config_attributes.find(attrkey::host); - if (it != config_attributes.end()) - host = it->second; - else - host.clear(); + const std::string& Configuration::GetStringValue(const std::string& key, const std::string& dflt) const + { + ArgumentMap::const_iterator it = arguments.find(common::ToLower(key)); - it = config_attributes.find(attrkey::port); - if (it != config_attributes.end()) - port = atoi(it->second.c_str()); - else - port = 0; + if (it != arguments.end()) + return it->second; - it = config_attributes.find(attrkey::cache); - if (it != config_attributes.end()) - cache = it->second; - else - cache.clear(); + return dflt; } - void Configuration::ParseAttributeList(const char * str, size_t len, char delimeter, ArgumentMap & args) const + void Configuration::ParseAttributeList(const char * str, size_t len, char delimeter, ArgumentMap & args) { std::string connect_str(str, len); - args.clear(); while (!connect_str.empty()) { @@ -245,6 +191,51 @@ namespace ignite connect_str.erase(attr_begin - 1); } } + + void Configuration::ParseAddress(const std::string& address, EndPoint& res) + { + int64_t colonNum = std::count(address.begin(), address.end(), ':'); + + if (colonNum == 0) + { + res.host = address; + res.port = DefaultValue::uintPort; + } + else if (colonNum == 1) + { + size_t pos = address.find(':'); + + if (pos == address.size() - 1) + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, + "Invalid address format: no port after colon"); + + res.host = address.substr(0, pos); + + std::string port = address.substr(pos + 1); + + if (!common::AllOf(port.begin(), port.end(), isdigit)) + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, + "Invalid address format: port can only contain digits"); + + int32_t intPort = common::LexicalCast<int32_t>(port); + + if (port.size() > sizeof("65535") - 1 || intPort > UINT16_MAX) + { + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, + "Invalid address format: Port value is too large," + " valid value should be in range from 1 to 65535"); + } + + if (intPort == 0) + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, + "Invalid address format: Port value can not be zero"); + + res.port = static_cast<uint16_t>(intPort); + } + else + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, + "Invalid address format: too many colons"); + } } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/8386dd86/modules/platforms/cpp/odbc/src/connection.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/connection.cpp b/modules/platforms/cpp/odbc/src/connection.cpp index 2441759..844ad70 100644 --- a/modules/platforms/cpp/odbc/src/connection.cpp +++ b/modules/platforms/cpp/odbc/src/connection.cpp @@ -41,7 +41,11 @@ namespace ignite { const std::string Connection::PROTOCOL_VERSION_SINCE = "1.6.0"; - Connection::Connection() : socket(), connected(false), cache(), parser() + Connection::Connection() : + socket(), + connected(false), + parser(), + config() { // No-op. } @@ -53,8 +57,8 @@ namespace ignite const config::ConnectionInfo& Connection::GetInfo() const { - // Connection info is the same for all connections now. - static config::ConnectionInfo info; + // Connection info is constant and the same for all connections now. + const static config::ConnectionInfo info; return info; } @@ -76,32 +80,38 @@ namespace ignite return res; } - void Connection::Establish(const std::string& server) + void Connection::Establish(const std::string& connectStr) { - IGNITE_ODBC_API_CALL(InternalEstablish(server)); + IGNITE_ODBC_API_CALL(InternalEstablish(connectStr)); } - SqlResult Connection::InternalEstablish(const std::string& server) + SqlResult Connection::InternalEstablish(const std::string& connectStr) { config::Configuration config; - if (server != config.GetDsn()) + try + { + config.FillFromConnectString(connectStr); + } + catch (IgniteError& e) { - AddStatusRecord(SQL_STATE_HY000_GENERAL_ERROR, "Unknown server."); + AddStatusRecord(SQL_STATE_HY000_GENERAL_ERROR, e.GetText()); return SQL_RESULT_ERROR; } - return InternalEstablish(config.GetHost(), config.GetPort(), config.GetCache()); + return InternalEstablish(config); } - void Connection::Establish(const std::string& host, uint16_t port, const std::string& cache) + void Connection::Establish(const config::Configuration cfg) { - IGNITE_ODBC_API_CALL(InternalEstablish(host, port, cache)); + IGNITE_ODBC_API_CALL(InternalEstablish(cfg)); } - SqlResult Connection::InternalEstablish(const std::string & host, uint16_t port, const std::string & cache) + SqlResult Connection::InternalEstablish(const config::Configuration cfg) { + config = cfg; + if (connected) { AddStatusRecord(SQL_STATE_08002_ALREADY_CONNECTED, "Already connected."); @@ -109,9 +119,7 @@ namespace ignite return SQL_RESULT_ERROR; } - this->cache = cache; - - connected = socket.Connect(host.c_str(), port); + connected = socket.Connect(cfg.GetHost().c_str(), cfg.GetPort()); if (!connected) { @@ -262,11 +270,16 @@ namespace ignite const std::string& Connection::GetCache() const { - return cache; + return config.GetCache(); + } + + const config::Configuration& Connection::GetConfiguration() const + { + return config; } diagnostic::DiagnosticRecord Connection::CreateStatusRecord(SqlState sqlState, - const std::string& message, int32_t rowNum, int32_t columnNum) const + const std::string& message, int32_t rowNum, int32_t columnNum) { return diagnostic::DiagnosticRecord(sqlState, message, "", "", rowNum, columnNum); } http://git-wip-us.apache.org/repos/asf/ignite/blob/8386dd86/modules/platforms/cpp/odbc/src/odbc.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/odbc.cpp b/modules/platforms/cpp/odbc/src/odbc.cpp index 3b31f1d..9b4179e 100644 --- a/modules/platforms/cpp/odbc/src/odbc.cpp +++ b/modules/platforms/cpp/odbc/src/odbc.cpp @@ -42,7 +42,16 @@ namespace ignite ignite::odbc::config::Configuration config; - config.FillFromConfigAttributes(attributes); + try + { + config.FillFromConfigAttributes(attributes); + } + catch (IgniteError& e) + { + SQLPostInstallerError(e.GetCode(), e.GetText()); + + return SQL_FALSE; + } if (!SQLValidDSN(config.GetDsn().c_str())) return SQL_FALSE; @@ -323,18 +332,14 @@ namespace ignite std::string connectStr = SqlStringToString(inConnectionString, inConnectionStringLen); - ignite::odbc::config::Configuration config; - - config.FillFromConnectString(connectStr); - - connection->Establish(config.GetHost(), config.GetPort(), config.GetCache()); + connection->Establish(connectStr); const DiagnosticRecordStorage& diag = connection->GetDiagnosticRecords(); if (!diag.IsSuccessful()) return diag.GetReturnCode(); - std::string outConnectStr = config.ToConnectString(); + std::string outConnectStr = connection->GetConfiguration().ToConnectString(); size_t reslen = CopyStringToBuffer(outConnectStr, reinterpret_cast<char*>(outConnectionString), @@ -357,7 +362,7 @@ namespace ignite SQLSMALLINT authLen) { using ignite::odbc::Connection; - using ignite::odbc::diagnostic::DiagnosticRecordStorage; + using ignite::odbc::config::Configuration; using ignite::utility::SqlStringToString; LOG_MSG("SQLConnect called\n"); @@ -367,9 +372,11 @@ namespace ignite if (!connection) return SQL_INVALID_HANDLE; - std::string server = SqlStringToString(serverName, serverNameLen); + //std::string server = SqlStringToString(serverName, serverNameLen); + + Configuration config; - connection->Establish(server); + connection->Establish(config); return connection->GetDiagnosticRecords().GetReturnCode(); }