You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by is...@apache.org on 2018/03/19 11:27:00 UTC

[1/3] ignite git commit: IGNITE-7811: Implemented connection failover for ODBC

Repository: ignite
Updated Branches:
  refs/heads/master e666fc5dd -> 6ddc6d701


http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/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 11105b6..7b06ea7 100644
--- a/modules/platforms/cpp/odbc/src/connection.cpp
+++ b/modules/platforms/cpp/odbc/src/connection.cpp
@@ -19,6 +19,7 @@
 #include <cstddef>
 
 #include <sstream>
+#include <algorithm>
 
 #include <ignite/common/fixed_size_array.h>
 
@@ -27,11 +28,13 @@
 #include "ignite/odbc/statement.h"
 #include "ignite/odbc/connection.h"
 #include "ignite/odbc/message.h"
-#include "ignite/odbc/config/configuration.h"
 #include "ignite/odbc/ssl/ssl_mode.h"
 #include "ignite/odbc/ssl/ssl_gateway.h"
 #include "ignite/odbc/ssl/secure_socket_client.h"
 #include "ignite/odbc/system/tcp_socket_client.h"
+#include "ignite/odbc/dsn_config.h"
+#include "ignite/odbc/config/configuration.h"
+#include "ignite/odbc/config/connection_string_parser.h"
 
 // Uncomment for per-byte debug.
 //#define PER_BYTE_DEBUG
@@ -104,16 +107,14 @@ namespace ignite
         {
             config::Configuration config;
 
-            try
-            {
-                config.FillFromConnectString(connectStr);
-            }
-            catch (IgniteError& e)
-            {
-                AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, e.GetText());
+            config::ConnectionStringParser parser(config);
 
-                return SqlResult::AI_ERROR;
-            }
+            parser.ParseConnectionString(connectStr, &GetDiagnosticRecords());
+
+            std::string dsn = config.GetDsn();
+
+            if (!dsn.empty())
+                ReadDsnConfiguration(dsn.c_str(), config);
 
             return InternalEstablish(config);
         }
@@ -123,7 +124,7 @@ namespace ignite
             IGNITE_ODBC_API_CALL(InternalEstablish(cfg));
         }
 
-        SqlResult::Type Connection::InternalEstablish(const config::Configuration cfg)
+        SqlResult::Type Connection::InternalEstablish(const config::Configuration& cfg)
         {
             using ssl::SslMode;
 
@@ -136,7 +137,14 @@ namespace ignite
                 return SqlResult::AI_ERROR;
             }
 
-            SslMode::T sslMode = SslMode::FromString(cfg.GetSslMode(), SslMode::DISABLE);
+            if (!config.IsHostSet() && config.IsAddressesSet() && config.GetAddresses().empty())
+            {
+                AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "No valid address to connect.");
+
+                return SqlResult::AI_ERROR;
+            }
+
+            SslMode::Type sslMode = config.GetSslMode();
 
             if (sslMode != SslMode::DISABLE)
             {
@@ -150,30 +158,24 @@ namespace ignite
                     return SqlResult::AI_ERROR;
                 }
 
-                socket.reset(new ssl::SecureSocketClient(cfg.GetSslCertFile(), cfg.GetSslKeyFile(), cfg.GetSslCaFile()));
+                socket.reset(new ssl::SecureSocketClient(config.GetSslCertFile(),
+                    config.GetSslKeyFile(), config.GetSslCaFile()));
             }
             else
                 socket.reset(new system::TcpSocketClient());
 
-            bool connected = socket->Connect(cfg.GetHost().c_str(), cfg.GetTcpPort(), *this);
+            bool connected = TryRestoreConnection();
 
             if (!connected)
             {
                 AddStatusRecord(SqlState::S08001_CANNOT_CONNECT, "Failed to establish connection with the host.");
 
-                Close();
-
                 return SqlResult::AI_ERROR;
             }
 
-            SqlResult::Type res = MakeRequestHandshake();
-
-            if (res == SqlResult::AI_ERROR)
-                Close();
-            else
-                parser.SetProtocolVersion(config.GetProtocolVersion());
+            bool errors = GetDiagnosticRecords().GetStatusRecordsNumber() > 0;
 
-            return res;
+            return errors ? SqlResult::AI_SUCCESS_WITH_INFO : SqlResult::AI_SUCCESS;
         }
 
         void Connection::Release()
@@ -513,30 +515,7 @@ namespace ignite
 
         SqlResult::Type Connection::MakeRequestHandshake()
         {
-            bool distributedJoins = false;
-            bool enforceJoinOrder = false;
-            bool replicatedOnly = false;
-            bool collocated = false;
-            bool lazy = false;
-            bool skipReducerOnUpdate = false;
-            ProtocolVersion protocolVersion;
-
-            try
-            {
-                protocolVersion = config.GetProtocolVersion();
-                distributedJoins = config.IsDistributedJoins();
-                enforceJoinOrder = config.IsEnforceJoinOrder();
-                replicatedOnly = config.IsReplicatedOnly();
-                collocated = config.IsCollocated();
-                lazy = config.IsLazy();
-                skipReducerOnUpdate = config.IsSkipReducerOnUpdate();
-            }
-            catch (const IgniteError& err)
-            {
-                AddStatusRecord(SqlState::S01S00_INVALID_CONNECTION_STRING_ATTRIBUTE, err.GetText());
-
-                return SqlResult::AI_ERROR;
-            }
+            ProtocolVersion protocolVersion = config.GetProtocolVersion();
 
             if (!protocolVersion.IsSupported())
             {
@@ -546,6 +525,13 @@ namespace ignite
                 return SqlResult::AI_ERROR;
             }
 
+            bool distributedJoins = config.IsDistributedJoins();
+            bool enforceJoinOrder = config.IsEnforceJoinOrder();
+            bool replicatedOnly = config.IsReplicatedOnly();
+            bool collocated = config.IsCollocated();
+            bool lazy = config.IsLazy();
+            bool skipReducerOnUpdate = config.IsSkipReducerOnUpdate();
+
             HandshakeRequest req(protocolVersion, distributedJoins, enforceJoinOrder, replicatedOnly, collocated, lazy,
                 skipReducerOnUpdate);
             HandshakeResponse rsp;
@@ -554,7 +540,7 @@ namespace ignite
             {
                 // Workaround for some Linux systems that report connection on non-blocking
                 // sockets as successful but fail to establish real connection.
-                bool sent = SyncMessage(req, rsp, SocketClient::CONNECT_TIMEOUT);
+                bool sent = InternalSyncMessage(req, rsp, SocketClient::CONNECT_TIMEOUT);
 
                 if (!sent)
                 {
@@ -599,6 +585,74 @@ namespace ignite
 
             return SqlResult::AI_SUCCESS;
         }
+
+        void Connection::EnsureConnected()
+        {
+            if (socket.get() != 0)
+                return;
+
+            bool success = TryRestoreConnection();
+
+            if (!success)
+                throw OdbcError(SqlState::S08001_CANNOT_CONNECT,
+                    "Failed to establish connection with any provided hosts");
+        }
+
+        bool Connection::TryRestoreConnection()
+        {
+            std::vector<EndPoint> addrs;
+
+            CollectAddresses(config, addrs);
+
+            bool connected = false;
+
+            while (!addrs.empty() && !connected)
+            {
+                const EndPoint& addr = addrs.back();
+
+                for (uint16_t port = addr.port; port <= addr.port + addr.range; ++port)
+                {
+                    connected = socket->Connect(addr.host.c_str(), port, *this);
+
+                    if (connected)
+                    {
+                        SqlResult::Type res = MakeRequestHandshake();
+
+                        connected = res != SqlResult::AI_ERROR;
+
+                        if (connected)
+                            break;
+                    }
+                }
+
+                addrs.pop_back();
+            }
+
+            if (!connected)
+                Close();
+            else
+                parser.SetProtocolVersion(config.GetProtocolVersion());
+
+            return connected;
+        }
+
+        void Connection::CollectAddresses(const config::Configuration& cfg, std::vector<EndPoint>& endPoints)
+        {
+            endPoints.clear();
+
+            if (!cfg.IsAddressesSet())
+            {
+                LOG_MSG("'Address' is not set. Using legacy connection method.");
+
+                endPoints.push_back(EndPoint(cfg.GetHost(), cfg.GetTcpPort()));
+
+                return;
+            }
+
+            endPoints = cfg.GetAddresses();
+
+            std::random_shuffle(endPoints.begin(), endPoints.end());
+        }
     }
 }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record_storage.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record_storage.cpp b/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record_storage.cpp
index 4b90e44..dde1a94 100644
--- a/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record_storage.cpp
+++ b/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record_storage.cpp
@@ -50,6 +50,11 @@ namespace ignite
                 rowsAffected = 0;
             }
 
+            void DiagnosticRecordStorage::AddStatusRecord(SqlState::Type sqlState, const std::string& message)
+            {
+                statusRecords.push_back(DiagnosticRecord(sqlState, message, "", "", 0, 0));
+            }
+
             void DiagnosticRecordStorage::AddStatusRecord(const DiagnosticRecord& record)
             {
                 statusRecords.push_back(record);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc/src/dsn_config.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/dsn_config.cpp b/modules/platforms/cpp/odbc/src/dsn_config.cpp
index 845c8bd..da9d61f 100644
--- a/modules/platforms/cpp/odbc/src/dsn_config.cpp
+++ b/modules/platforms/cpp/odbc/src/dsn_config.cpp
@@ -15,16 +15,18 @@
  * limitations under the License.
  */
 
-#include <set>
+#include <ignite/common/fixed_size_array.h>
 
 #include "ignite/odbc/utility.h"
+#include "ignite/odbc/config/connection_string_parser.h"
 #include "ignite/odbc/system/odbc_constants.h"
-
 #include "ignite/odbc/dsn_config.h"
+#include "ignite/odbc/config/config_tools.h"
+
 
-using ignite::odbc::config::Configuration;
+using namespace ignite::odbc::config;
 
-#define BUFFER_SIZE 1024
+#define BUFFER_SIZE (1024 * 1024)
 #define CONFIG_FILE "ODBC.INI"
 
 namespace ignite
@@ -34,13 +36,13 @@ namespace ignite
         void ThrowLastSetupError()
         {
             DWORD code;
-            char msg[BUFFER_SIZE];
+            common::FixedSizeArray<char> msg(BUFFER_SIZE);
 
-            SQLInstallerError(1, &code, msg, sizeof(msg), NULL);
+            SQLInstallerError(1, &code, msg.GetData(), msg.GetSize(), NULL);
 
             std::stringstream buf;
 
-            buf << "Message: \"" << msg << "\", Code: " << code;
+            buf << "Message: \"" << msg.GetData() << "\", Code: " << code;
 
             throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, buf.str().c_str());
         }
@@ -51,98 +53,155 @@ namespace ignite
                 ThrowLastSetupError();
         }
 
-        std::string ReadDsnString(const char* dsn, const std::string& key, const std::string& dflt)
+        SettableValue<std::string> ReadDsnString(const char* dsn, const std::string& key, const std::string& dflt = "")
         {
-            char buf[BUFFER_SIZE];
+            static const char* unique = "35a920dd-8837-43d2-a846-e01a2e7b5f84";
 
-            memset(buf, 0, sizeof(buf));
+            SettableValue<std::string> val(dflt);
 
-            SQLGetPrivateProfileString(dsn, key.c_str(), dflt.c_str(), buf, sizeof(buf), CONFIG_FILE);
+            common::FixedSizeArray<char> buf(BUFFER_SIZE);
 
-            return std::string(buf);
-        }
+            int ret = SQLGetPrivateProfileString(dsn, key.c_str(), unique, buf.GetData(), buf.GetSize(), CONFIG_FILE);
 
-        int ReadDsnInt(const char* dsn, const std::string& key, int dflt)
-        {
-            char buf[BUFFER_SIZE];
+            if (ret > BUFFER_SIZE)
+            {
+                buf.Reset(ret + 1);
 
-            memset(buf, 0, sizeof(buf));
+                ret = SQLGetPrivateProfileString(dsn, key.c_str(), unique, buf.GetData(), buf.GetSize(), CONFIG_FILE);
+            }
 
-            std::string dflt0 = common::LexicalCast<std::string>(dflt);
+            std::string res(buf.GetData());
 
-            SQLGetPrivateProfileString(dsn, key.c_str(), dflt0.c_str(), buf, sizeof(buf), CONFIG_FILE);
+            if (res == unique)
+                return val;
 
-            return common::LexicalCast<int, std::string>(buf);
+            val.SetValue(res);
+
+            return val;
         }
 
-        bool ReadDsnBool(const char* dsn, const std::string& key, bool dflt)
+        SettableValue<int32_t> ReadDsnInt(const char* dsn, const std::string& key, int32_t dflt = 0)
         {
-            char buf[BUFFER_SIZE];
+            SettableValue<std::string> str = ReadDsnString(dsn, key, "");
+
+            SettableValue<int32_t> res(dflt);
 
-            memset(buf, 0, sizeof(buf));
+            if (str.IsSet())
+                res.SetValue(common::LexicalCast<int, std::string>(str.GetValue()));
 
-            std::string dflt0 = dflt ? "true" : "false";
+            return res;
+        }
 
-            SQLGetPrivateProfileString(dsn, key.c_str(), dflt0.c_str(), buf, sizeof(buf), CONFIG_FILE);
+        SettableValue<bool> ReadDsnBool(const char* dsn, const std::string& key, bool dflt = false)
+        {
+            SettableValue<std::string> str = ReadDsnString(dsn, key, "");
 
-            return std::string(buf) == "true";
+            SettableValue<bool> res(dflt);
+
+            if (str.IsSet())
+                res.SetValue(str.GetValue() == "true");
+
+            return res;
         }
 
         void ReadDsnConfiguration(const char* dsn, Configuration& config)
         {
-            std::string address = ReadDsnString(dsn, Configuration::Key::address, config.GetAddress());
+            SettableValue<std::string> address = ReadDsnString(dsn, ConnectionStringParser::Key::address);
+
+            if (address.IsSet() && !config.IsAddressesSet())
+            {
+                std::vector<EndPoint> endPoints;
+
+                ParseAddress(address.GetValue(), endPoints, 0);
+
+                config.SetAddresses(endPoints);
+            }
+
+            SettableValue<std::string> server = ReadDsnString(dsn, ConnectionStringParser::Key::server);
+
+            if (server.IsSet() && !config.IsHostSet())
+                config.SetHost(server.GetValue());
+
+            SettableValue<int32_t> port = ReadDsnInt(dsn, ConnectionStringParser::Key::port);
+
+            if (port.IsSet() && !config.IsTcpPortSet())
+                config.SetTcpPort(static_cast<uint16_t>(port.GetValue()));
+
+            SettableValue<std::string> schema = ReadDsnString(dsn, ConnectionStringParser::Key::schema);
+
+            if (schema.IsSet() && !config.IsSchemaSet())
+                config.SetSchema(schema.GetValue());
+
+            SettableValue<bool> distributedJoins = ReadDsnBool(dsn, ConnectionStringParser::Key::distributedJoins);
+
+            if (distributedJoins.IsSet() && !config.IsDistributedJoinsSet())
+                config.SetDistributedJoins(distributedJoins.GetValue());
+
+            SettableValue<bool> enforceJoinOrder = ReadDsnBool(dsn, ConnectionStringParser::Key::enforceJoinOrder);
+
+            if (enforceJoinOrder.IsSet() && !config.IsEnforceJoinOrderSet())
+                config.SetEnforceJoinOrder(enforceJoinOrder.GetValue());
+
+            SettableValue<bool> replicatedOnly = ReadDsnBool(dsn, ConnectionStringParser::Key::replicatedOnly);
+
+            if (replicatedOnly.IsSet() && !config.IsReplicatedOnlySet())
+                config.SetReplicatedOnly(replicatedOnly.GetValue());
+
+            SettableValue<bool> collocated = ReadDsnBool(dsn, ConnectionStringParser::Key::collocated);
+
+            if (collocated.IsSet() && !config.IsCollocatedSet())
+                config.SetCollocated(collocated.GetValue());
+
+            SettableValue<bool> lazy = ReadDsnBool(dsn, ConnectionStringParser::Key::lazy);
+
+            if (lazy.IsSet() && !config.IsLazySet())
+                config.SetLazy(lazy.GetValue());
 
-            std::string server = ReadDsnString(dsn, Configuration::Key::server, config.GetHost());
+            SettableValue<bool> skipReducerOnUpdate = ReadDsnBool(dsn, ConnectionStringParser::Key::skipReducerOnUpdate);
 
-            uint16_t port = ReadDsnInt(dsn, Configuration::Key::port, config.GetTcpPort());
+            if (skipReducerOnUpdate.IsSet() && !config.IsSkipReducerOnUpdateSet())
+                config.SetSkipReducerOnUpdate(skipReducerOnUpdate.GetValue());
 
-            std::string schema = ReadDsnString(dsn, Configuration::Key::schema, config.GetSchema());
+            SettableValue<std::string> versionStr = ReadDsnString(dsn, ConnectionStringParser::Key::protocolVersion);
 
-            bool distributedJoins = ReadDsnBool(dsn, Configuration::Key::distributedJoins, config.IsDistributedJoins());
+            if (versionStr.IsSet() && !config.IsProtocolVersionSet())
+            {
+                ProtocolVersion version = ProtocolVersion::FromString(versionStr.GetValue());
 
-            bool enforceJoinOrder = ReadDsnBool(dsn, Configuration::Key::enforceJoinOrder, config.IsEnforceJoinOrder());
+                if (!version.IsSupported())
+                    version = Configuration::DefaultValue::protocolVersion;
 
-            bool replicatedOnly = ReadDsnBool(dsn, Configuration::Key::replicatedOnly, config.IsReplicatedOnly());
+                config.SetProtocolVersion(version);
+            }
 
-            bool collocated = ReadDsnBool(dsn, Configuration::Key::collocated, config.IsCollocated());
+            SettableValue<int32_t> pageSize = ReadDsnInt(dsn, ConnectionStringParser::Key::pageSize);
 
-            bool lazy = ReadDsnBool(dsn, Configuration::Key::lazy, config.IsLazy());
+            if (pageSize.IsSet() && !config.IsPageSizeSet() && pageSize.GetValue() > 0)
+                config.SetPageSize(pageSize.GetValue());
 
-            bool skipReducerOnUpdate =
-                ReadDsnBool(dsn, Configuration::Key::skipReducerOnUpdate, config.IsSkipReducerOnUpdate());
+            SettableValue<std::string> sslModeStr = ReadDsnString(dsn, ConnectionStringParser::Key::sslMode);
 
-            std::string version = ReadDsnString(dsn, Configuration::Key::protocolVersion,
-                config.GetProtocolVersion().ToString());
+            if (sslModeStr.IsSet() && !config.IsSslModeSet())
+            {
+                ssl::SslMode::Type sslMode = ssl::SslMode::FromString(sslModeStr.GetValue(), ssl::SslMode::DISABLE);
 
-            int32_t pageSize = ReadDsnInt(dsn, Configuration::Key::pageSize, config.GetPageSize());
+                config.SetSslMode(sslMode);
+            }
 
-            if (pageSize <= 0)
-                pageSize = config.GetPageSize();
+            SettableValue<std::string> sslKeyFile = ReadDsnString(dsn, ConnectionStringParser::Key::sslKeyFile);
 
-            std::string sslMode = ReadDsnString(dsn, Configuration::Key::sslMode, config.GetSslMode());
+            if (sslKeyFile.IsSet() && !config.IsSslKeyFileSet())
+                config.SetSslKeyFile(sslKeyFile.GetValue());
 
-            std::string sslKeyFile = ReadDsnString(dsn, Configuration::Key::sslKeyFile, config.GetSslKeyFile());
+            SettableValue<std::string> sslCertFile = ReadDsnString(dsn, ConnectionStringParser::Key::sslCertFile);
 
-            std::string sslCertFile = ReadDsnString(dsn, Configuration::Key::sslCertFile, config.GetSslCertFile());
+            if (sslCertFile.IsSet() && !config.IsSslCertFileSet())
+                config.SetSslCertFile(sslCertFile.GetValue());
 
-            std::string sslCaFile = ReadDsnString(dsn, Configuration::Key::sslCaFile, config.GetSslCaFile());
+            SettableValue<std::string> sslCaFile = ReadDsnString(dsn, ConnectionStringParser::Key::sslCaFile);
 
-            config.SetAddress(address);
-            config.SetHost(server);
-            config.SetTcpPort(port);
-            config.SetSchema(schema);
-            config.SetDistributedJoins(distributedJoins);
-            config.SetEnforceJoinOrder(enforceJoinOrder);
-            config.SetReplicatedOnly(replicatedOnly);
-            config.SetCollocated(collocated);
-            config.SetLazy(lazy);
-            config.SetSkipReducerOnUpdate(skipReducerOnUpdate);
-            config.SetProtocolVersion(version);
-            config.SetPageSize(pageSize);
-            config.SetSslMode(sslMode);
-            config.SetSslKeyFile(sslKeyFile);
-            config.SetSslCertFile(sslCertFile);
-            config.SetSslCaFile(sslCaFile);
+            if (sslCaFile.IsSet() && !config.IsSslCaFileSet())
+                config.SetSslCaFile(sslCaFile.GetValue());
         }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc/src/environment.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/environment.cpp b/modules/platforms/cpp/odbc/src/environment.cpp
index 6182fa2..417fedc 100644
--- a/modules/platforms/cpp/odbc/src/environment.cpp
+++ b/modules/platforms/cpp/odbc/src/environment.cpp
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+#include <cstdlib>
+
 #include "ignite/odbc/system/odbc_constants.h"
 #include "ignite/odbc/connection.h"
 #include "ignite/odbc/environment.h"
@@ -24,9 +26,10 @@ namespace ignite
     namespace odbc
     {
         Environment::Environment() : 
-            odbcVersion(SQL_OV_ODBC3), odbcNts(SQL_TRUE)
+            odbcVersion(SQL_OV_ODBC3),
+            odbcNts(SQL_TRUE)
         {
-            // No-op.
+            srand(common::GetRandSeed());
         }
 
         Environment::~Environment()

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/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 dfa2dec..3aad52f 100644
--- a/modules/platforms/cpp/odbc/src/odbc.cpp
+++ b/modules/platforms/cpp/odbc/src/odbc.cpp
@@ -24,6 +24,7 @@
 #include "ignite/odbc/utility.h"
 #include "ignite/odbc/system/odbc_constants.h"
 
+#include "ignite/odbc/config/connection_string_parser.h"
 #include "ignite/odbc/config/configuration.h"
 #include "ignite/odbc/type_traits.h"
 #include "ignite/odbc/environment.h"
@@ -270,16 +271,7 @@ namespace ignite
 
         std::string connectStr = SqlStringToString(inConnectionString, inConnectionStringLen);
 
-        odbc::config::Configuration config;
-
-        config.FillFromConnectString(connectStr);
-
-        std::string dsn = config.GetDsn();
-
-        if (!dsn.empty())
-            odbc::ReadDsnConfiguration(dsn.c_str(), config);
-
-        connection->Establish(config);
+        connection->Establish(connectStr);
 
         const DiagnosticRecordStorage& diag = connection->GetDiagnosticRecords();
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc/src/ssl/ssl_mode.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/ssl/ssl_mode.cpp b/modules/platforms/cpp/odbc/src/ssl/ssl_mode.cpp
index 0bdbc60..3a8e923 100644
--- a/modules/platforms/cpp/odbc/src/ssl/ssl_mode.cpp
+++ b/modules/platforms/cpp/odbc/src/ssl/ssl_mode.cpp
@@ -24,7 +24,7 @@ namespace ignite
     {
         namespace ssl
         {
-            SslMode::T SslMode::FromString(const std::string& val, T dflt)
+            SslMode::Type SslMode::FromString(const std::string& val, Type dflt)
             {
                 std::string lowerVal = common::ToLower(val);
 
@@ -38,6 +38,22 @@ namespace ignite
 
                 return dflt;
             }
+
+            std::string SslMode::ToString(Type val)
+            {
+                switch (val)
+                {
+                    case SslMode::DISABLE:
+                        return "disable";
+
+                    case SslMode::REQUIRE:
+                        return "require";
+
+                    case SslMode::UNKNOWN:
+                    default:
+                        return "unknown";
+                }
+            }
         }
     }
 }


[3/3] ignite git commit: IGNITE-7811: Implemented connection failover for ODBC

Posted by is...@apache.org.
IGNITE-7811: Implemented connection failover for ODBC

This closes #3643


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/6ddc6d70
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/6ddc6d70
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/6ddc6d70

Branch: refs/heads/master
Commit: 6ddc6d701db10c51406a7ff02b5f8cc3c1e2397f
Parents: e666fc5
Author: Igor Sapego <is...@gridgain.com>
Authored: Mon Mar 19 14:17:33 2018 +0300
Committer: Igor Sapego <is...@gridgain.com>
Committed: Mon Mar 19 14:17:33 2018 +0300

----------------------------------------------------------------------
 .../include/ignite/common/platform_utils.h      |   7 +
 .../os/linux/src/common/platform_utils.cpp      |  15 +
 .../common/os/win/src/common/platform_utils.cpp |   5 +
 modules/platforms/cpp/odbc-test/Makefile.am     |   8 +-
 .../cpp/odbc-test/include/odbc_test_suite.h     |  29 +
 .../cpp/odbc-test/project/vs/odbc-test.vcxproj  |   6 +
 .../project/vs/odbc-test.vcxproj.filters        |  20 +-
 .../cpp/odbc-test/src/api_robustness_test.cpp   |  25 -
 .../cpp/odbc-test/src/attributes_test.cpp       | 165 +++---
 .../cpp/odbc-test/src/configuration_test.cpp    | 223 +++++---
 .../cpp/odbc-test/src/odbc_test_suite.cpp       |  25 +
 .../cpp/odbc-test/src/queries_test.cpp          |  40 --
 .../cpp/odbc-test/src/sql_get_info_test.cpp     |   3 +-
 modules/platforms/cpp/odbc/Makefile.am          |   2 +
 .../include/ignite/odbc/config/config_tools.h   |  92 ++++
 .../include/ignite/odbc/config/configuration.h  | 527 +++++++++----------
 .../odbc/config/connection_string_parser.h      | 188 +++++++
 .../include/ignite/odbc/config/settable_value.h | 101 ++++
 .../cpp/odbc/include/ignite/odbc/connection.h   |  61 ++-
 .../odbc/diagnostic/diagnosable_adapter.h       |  26 +-
 .../odbc/diagnostic/diagnostic_record_storage.h |  13 +-
 .../cpp/odbc/include/ignite/odbc/end_point.h    |  72 +++
 .../cpp/odbc/include/ignite/odbc/ssl/ssl_mode.h |  13 +-
 .../cpp/odbc/include/ignite/odbc/utility.h      |   3 +-
 .../src/system/ui/dsn_configuration_window.cpp  | 127 +++--
 .../cpp/odbc/os/win/src/system_dsn.cpp          |  24 +-
 .../platforms/cpp/odbc/project/vs/odbc.vcxproj  |   6 +
 .../cpp/odbc/project/vs/odbc.vcxproj.filters    |  18 +
 .../cpp/odbc/src/config/config_tools.cpp        | 250 +++++++++
 .../cpp/odbc/src/config/configuration.cpp       | 507 +++++++++++-------
 .../src/config/connection_string_parser.cpp     | 452 ++++++++++++++++
 modules/platforms/cpp/odbc/src/connection.cpp   | 150 ++++--
 .../diagnostic/diagnostic_record_storage.cpp    |   5 +
 modules/platforms/cpp/odbc/src/dsn_config.cpp   | 183 ++++---
 modules/platforms/cpp/odbc/src/environment.cpp  |   7 +-
 modules/platforms/cpp/odbc/src/odbc.cpp         |  12 +-
 modules/platforms/cpp/odbc/src/ssl/ssl_mode.cpp |  18 +-
 37 files changed, 2521 insertions(+), 907 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/common/include/ignite/common/platform_utils.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/common/include/ignite/common/platform_utils.h b/modules/platforms/cpp/common/include/ignite/common/platform_utils.h
index 83da6ec..a46caba 100644
--- a/modules/platforms/cpp/common/include/ignite/common/platform_utils.h
+++ b/modules/platforms/cpp/common/include/ignite/common/platform_utils.h
@@ -104,6 +104,13 @@ namespace ignite
          * @return The same stream for chaining.
          */
         IGNITE_IMPORT_EXPORT StdCharOutStream& Dle(StdCharOutStream& ostr);
+
+        /**
+         * Get random seed.
+         *
+         * @return Random seed.
+         */
+        unsigned GetRandSeed();
     }
 }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/common/os/linux/src/common/platform_utils.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/common/os/linux/src/common/platform_utils.cpp b/modules/platforms/cpp/common/os/linux/src/common/platform_utils.cpp
index 88ba8ed..2cbbd1d 100644
--- a/modules/platforms/cpp/common/os/linux/src/common/platform_utils.cpp
+++ b/modules/platforms/cpp/common/os/linux/src/common/platform_utils.cpp
@@ -18,9 +18,11 @@
 #include <time.h>
 
 #include <sys/stat.h>
+#include <sys/time.h>
 #include <dirent.h>
 #include <dlfcn.h>
 #include <glob.h>
+#include <unistd.h>
 
 #include <ignite/common/utils.h>
 
@@ -104,5 +106,18 @@ namespace ignite
 
             return ostr;
         }
+
+        unsigned GetRandSeed()
+        {
+            timespec ts;
+
+            clock_gettime(CLOCK_MONOTONIC, &ts);
+
+            unsigned res = static_cast<unsigned>(ts.tv_sec);
+            res ^= static_cast<unsigned>(ts.tv_nsec);
+            res ^= static_cast<unsigned>(getpid());
+
+            return res;
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/common/os/win/src/common/platform_utils.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/common/os/win/src/common/platform_utils.cpp b/modules/platforms/cpp/common/os/win/src/common/platform_utils.cpp
index 057a3d4..c2244c5 100644
--- a/modules/platforms/cpp/common/os/win/src/common/platform_utils.cpp
+++ b/modules/platforms/cpp/common/os/win/src/common/platform_utils.cpp
@@ -106,5 +106,10 @@ namespace ignite
 
             return ostr;
         }
+
+        unsigned GetRandSeed()
+        {
+            return static_cast<unsigned>(GetTickCount() ^ GetCurrentProcessId());
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/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 cda4071..89e27dd 100644
--- a/modules/platforms/cpp/odbc-test/Makefile.am
+++ b/modules/platforms/cpp/odbc-test/Makefile.am
@@ -86,12 +86,18 @@ ignite_odbc_tests_SOURCES = \
     src/types_test.cpp \
     ../odbc/src/log.cpp \
     ../odbc/src/cursor.cpp \
+    ../odbc/src/diagnostic/diagnostic_record.cpp \
+    ../odbc/src/diagnostic/diagnostic_record_storage.cpp \
+    ../odbc/src/config/config_tools.cpp \
+    ../odbc/src/config/configuration.cpp \
     ../odbc/src/config/connection_info.cpp \
+    ../odbc/src/config/connection_string_parser.cpp \
     ../odbc/src/app/application_data_buffer.cpp \
-    ../odbc/src/config/configuration.cpp \
+    ../odbc/src/ssl/ssl_mode.cpp \
     ../odbc/src/row.cpp \
     ../odbc/src/protocol_version.cpp \
     ../odbc/src/column.cpp \
+    ../odbc/src/common_types.cpp \
     ../odbc/src/utility.cpp \
     ../odbc/src/result_page.cpp
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc-test/include/odbc_test_suite.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/include/odbc_test_suite.h b/modules/platforms/cpp/odbc-test/include/odbc_test_suite.h
index c535679..33bd819 100644
--- a/modules/platforms/cpp/odbc-test/include/odbc_test_suite.h
+++ b/modules/platforms/cpp/odbc-test/include/odbc_test_suite.h
@@ -108,8 +108,37 @@ namespace ignite
              */
             void InsertNonFullBatchSelect(int recordsNum, int splitAt);
 
+            /**
+             * Get test string.
+             *
+             * @param ind Index.
+             * @return Corresponding test string.
+             */
             static std::string getTestString(int64_t ind);
 
+            /**
+             * Check that SQL error has expected SQL state.
+             *
+             * @param handleType Handle type.
+             * @param handle Handle.
+             * @param expectSqlState Expected state.
+             */
+            void CheckSQLDiagnosticError(int16_t handleType, SQLHANDLE handle, const std::string& expectSqlState);
+
+            /**
+             * Check that statement SQL error has expected SQL state.
+             *
+             * @param expectSqlState Expected state.
+             */
+            void CheckSQLStatementDiagnosticError(const std::string& expectSqlState);
+
+            /**
+             * Check that connection SQL error has expected SQL state.
+             *
+             * @param expectSqlState Expected state.
+             */
+            void CheckSQLConnectionDiagnosticError(const std::string& expectSqlState);
+
             /** ODBC Environment. */
             SQLHENV env;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/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 b1074b2..30cafa3 100644
--- a/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj
+++ b/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj
@@ -155,13 +155,19 @@
   <ItemGroup>
     <ClCompile Include="..\..\..\odbc\src\app\application_data_buffer.cpp" />
     <ClCompile Include="..\..\..\odbc\src\column.cpp" />
+    <ClCompile Include="..\..\..\odbc\src\common_types.cpp" />
     <ClCompile Include="..\..\..\odbc\src\config\configuration.cpp" />
+    <ClCompile Include="..\..\..\odbc\src\config\config_tools.cpp" />
     <ClCompile Include="..\..\..\odbc\src\config\connection_info.cpp" />
+    <ClCompile Include="..\..\..\odbc\src\config\connection_string_parser.cpp" />
     <ClCompile Include="..\..\..\odbc\src\cursor.cpp" />
+    <ClCompile Include="..\..\..\odbc\src\diagnostic\diagnostic_record.cpp" />
+    <ClCompile Include="..\..\..\odbc\src\diagnostic\diagnostic_record_storage.cpp" />
     <ClCompile Include="..\..\..\odbc\src\log.cpp" />
     <ClCompile Include="..\..\..\odbc\src\protocol_version.cpp" />
     <ClCompile Include="..\..\..\odbc\src\result_page.cpp" />
     <ClCompile Include="..\..\..\odbc\src\row.cpp" />
+    <ClCompile Include="..\..\..\odbc\src\ssl\ssl_mode.cpp" />
     <ClCompile Include="..\..\..\odbc\src\utility.cpp" />
     <ClCompile Include="..\..\src\api_robustness_test.cpp" />
     <ClCompile Include="..\..\src\application_data_buffer_test.cpp" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/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 417fac9..bd0e200 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
@@ -142,6 +142,24 @@
     <ClCompile Include="..\..\src\queries_ssl_test.cpp">
       <Filter>Code</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\..\odbc\src\config\connection_string_parser.cpp">
+      <Filter>Externals</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\odbc\src\config\config_tools.cpp">
+      <Filter>Externals</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\odbc\src\ssl\ssl_mode.cpp">
+      <Filter>Externals</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\odbc\src\diagnostic\diagnostic_record_storage.cpp">
+      <Filter>Externals</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\odbc\src\diagnostic\diagnostic_record.cpp">
+      <Filter>Externals</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\odbc\src\common_types.cpp">
+      <Filter>Externals</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\include\test_type.h">
@@ -180,4 +198,4 @@
       <Filter>Configs</Filter>
     </None>
   </ItemGroup>
-</Project>
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp b/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp
index 293d8bc..eca0e00 100644
--- a/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp
@@ -121,31 +121,6 @@ struct ApiRobustnessTestSuiteFixture : public odbc::OdbcTestSuite
         CheckSQLStatementDiagnosticError("HY106");
     }
 
-    void CheckSQLDiagnosticError(int16_t handleType, SQLHANDLE handle, const std::string& expectSqlState)
-    {
-        SQLCHAR state[ODBC_BUFFER_SIZE];
-        SQLINTEGER nativeError = 0;
-        SQLCHAR message[ODBC_BUFFER_SIZE];
-        SQLSMALLINT messageLen = 0;
-
-        SQLRETURN ret = SQLGetDiagRec(handleType, handle, 1, state, &nativeError, message, sizeof(message), &messageLen);
-
-        const std::string sqlState = reinterpret_cast<char*>(state);
-        BOOST_REQUIRE_EQUAL(ret, SQL_SUCCESS);
-        BOOST_REQUIRE_EQUAL(sqlState, expectSqlState);
-        BOOST_REQUIRE(messageLen > 0);
-    }
-
-    void CheckSQLStatementDiagnosticError(const std::string& expectSqlState)
-    {
-        CheckSQLDiagnosticError(SQL_HANDLE_STMT, stmt, expectSqlState);
-    }
-
-    void CheckSQLConnectionDiagnosticError(const std::string& expectSqlState)
-    {
-        CheckSQLDiagnosticError(SQL_HANDLE_DBC, dbc, expectSqlState);
-    }
-
     /**
      * Destructor.
      */

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc-test/src/attributes_test.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/attributes_test.cpp b/modules/platforms/cpp/odbc-test/src/attributes_test.cpp
index c4c2433..3dc226d 100644
--- a/modules/platforms/cpp/odbc-test/src/attributes_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/attributes_test.cpp
@@ -37,6 +37,7 @@
 
 #include "test_type.h"
 #include "test_utils.h"
+#include "odbc_test_suite.h"
 
 using namespace ignite;
 using namespace ignite::cache;
@@ -51,74 +52,13 @@ using ignite::impl::binary::BinaryUtils;
 /**
  * Test setup fixture.
  */
-struct AttributesTestSuiteFixture
+struct AttributesTestSuiteFixture : odbc::OdbcTestSuite
 {
-    void Prepare()
-    {
-        // 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);
-    }
-
-    /**
-     * Establish connection to node.
-     *
-     * @param connectStr Connection string.
-     */
-    void Connect(const std::string& connectStr)
-    {
-        Prepare();
-
-        // Connect string
-        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, &connectStr0[0], static_cast<SQLSMALLINT>(connectStr0.size()),
-            outstr, sizeof(outstr), &outstrlen, SQL_DRIVER_COMPLETE);
-
-        ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_DBC, dbc);
-
-        // Allocate a statement handle
-        SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
-
-        BOOST_REQUIRE(stmt != NULL);
-    }
-
-    void Disconnect()
-    {
-        // 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);
-    }
-
     /**
      * Constructor.
      */
     AttributesTestSuiteFixture() :
-        env(NULL),
-        dbc(NULL),
-        stmt(NULL)
+        grid()
     {
         const char* config = NULL;
 
@@ -131,26 +71,6 @@ struct AttributesTestSuiteFixture
         grid = StartNode(config, "NodeMain");
     }
 
-    void CheckSQLDiagnosticError(int16_t handleType, SQLHANDLE handle, const std::string& expectSqlState)
-    {
-        SQLCHAR state[ODBC_BUFFER_SIZE];
-        SQLINTEGER nativeError = 0;
-        SQLCHAR message[ODBC_BUFFER_SIZE];
-        SQLSMALLINT messageLen = 0;
-
-        SQLRETURN ret = SQLGetDiagRec(handleType, handle, 1, state, &nativeError, message, sizeof(message), &messageLen);
-
-        const std::string sqlState = reinterpret_cast<char*>(state);
-        BOOST_REQUIRE_EQUAL(ret, SQL_SUCCESS);
-        BOOST_REQUIRE_EQUAL(sqlState, expectSqlState);
-        BOOST_REQUIRE(messageLen > 0);
-    }
-
-    void CheckSQLConnectionDiagnosticError(const std::string& expectSqlState)
-    {
-        CheckSQLDiagnosticError(SQL_HANDLE_DBC, dbc, expectSqlState);
-    }
-
     /**
      * Destructor.
      */
@@ -163,18 +83,81 @@ struct AttributesTestSuiteFixture
 
     /** Node started during the test. */
     Ignite grid;
+};
 
-    /** ODBC Environment. */
-    SQLHENV env;
+BOOST_FIXTURE_TEST_SUITE(AttributesTestSuite, AttributesTestSuiteFixture)
 
-    /** ODBC Connect. */
-    SQLHDBC dbc;
+BOOST_AUTO_TEST_CASE(TestLegacyConnection)
+{
+    Connect("DRIVER={Apache Ignite};SERVER=127.0.0.1;PORT=11110;SCHEMA=cache");
 
-    /** ODBC Statement. */
-    SQLHSTMT stmt;
-};
+    InsertTestStrings(10, false);
+    InsertTestBatch(11, 20, 9);
+}
 
-BOOST_FIXTURE_TEST_SUITE(AttributesTestSuite, AttributesTestSuiteFixture)
+BOOST_AUTO_TEST_CASE(TestConnectionProtocolVersion_2_1_0)
+{
+    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache;PROTOCOL_VERSION=2.1.0");
+
+    InsertTestStrings(10, false);
+    InsertTestBatch(11, 20, 9);
+}
+
+BOOST_AUTO_TEST_CASE(TestConnectionProtocolVersion_2_1_5)
+{
+    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache;PROTOCOL_VERSION=2.1.5");
+
+    InsertTestStrings(10, false);
+    InsertTestBatch(11, 20, 9);
+}
+
+BOOST_AUTO_TEST_CASE(TestConnectionProtocolVersion_2_3_0)
+{
+    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache;PROTOCOL_VERSION=2.3.0");
+
+    InsertTestStrings(10, false);
+    InsertTestBatch(11, 20, 9);
+}
+
+BOOST_AUTO_TEST_CASE(TestConnectionProtocolVersion_2_3_2)
+{
+    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache;PROTOCOL_VERSION=2.3.2");
+
+    InsertTestStrings(10, false);
+    InsertTestBatch(11, 20, 9);
+}
+
+BOOST_AUTO_TEST_CASE(TestConnectionRangeBegin)
+{
+    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110..11115;SCHEMA=cache");
+
+    InsertTestStrings(10, false);
+    InsertTestBatch(11, 20, 9);
+}
+
+BOOST_AUTO_TEST_CASE(TestConnectionRangeEnd)
+{
+    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11108..11110;SCHEMA=cache");
+
+    InsertTestStrings(10, false);
+    InsertTestBatch(11, 20, 9);
+}
+
+BOOST_AUTO_TEST_CASE(TestConnectionRangeMiddle)
+{
+    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11108..11115;SCHEMA=cache");
+
+    InsertTestStrings(10, false);
+    InsertTestBatch(11, 20, 9);
+}
+
+BOOST_AUTO_TEST_CASE(TestConnectionMultipleAddresses)
+{
+    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:4242,127.0.0.1:11109..11115,127.0.0.1;SCHEMA=cache");
+
+    InsertTestStrings(10, false);
+    InsertTestBatch(11, 20, 9);
+}
 
 BOOST_AUTO_TEST_CASE(ConnectionAttributeConnectionDeadGet)
 {

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/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 3165c4d..4cfc940 100644
--- a/modules/platforms/cpp/odbc-test/src/configuration_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/configuration_test.cpp
@@ -25,9 +25,13 @@
 #include <boost/test/unit_test.hpp>
 
 #include <ignite/odbc/config/configuration.h>
-#include <ignite/ignite_error.h>
+#include <ignite/odbc/config/connection_string_parser.h>
+#include <ignite/odbc/config/config_tools.h>
+#include <ignite/odbc/odbc_error.h>
 #include <ignite/common/utils.h>
+#include "ignite/odbc/diagnostic/diagnostic_record_storage.h"
 
+using namespace ignite::odbc;
 using namespace ignite::odbc::config;
 
 namespace
@@ -45,7 +49,9 @@ namespace
     const bool testLazy = true;
     const bool testSkipReducerOnUpdate = true;
 
-    const std::string testAddress = testServerHost + ':' + ignite::common::LexicalCast<std::string>(testServerPort);
+    const std::string testAddressStr = testServerHost + ':' + ignite::common::LexicalCast<std::string>(testServerPort);
+
+    const EndPoint testAddress(testServerHost, testServerPort, 10);
 }
 
 const char* BoolToStr(bool val, bool lowerCase = true)
@@ -56,77 +62,128 @@ const char* BoolToStr(bool val, bool lowerCase = true)
     return val ? "TRUE" : "FALSE";
 }
 
-void CheckValidAddress(const char* connectStr, uint16_t port)
+void ParseValidDsnString(const std::string& dsnStr, Configuration& cfg)
+{
+    ConnectionStringParser parser(cfg);
+
+    diagnostic::DiagnosticRecordStorage diag;
+
+    BOOST_CHECK_NO_THROW(parser.ParseConfigAttributes(dsnStr.c_str(), &diag));
+
+    if (diag.GetStatusRecordsNumber() != 0)
+        BOOST_FAIL(diag.GetStatusRecord(1).GetMessageText());
+}
+
+void ParseValidConnectString(const std::string& connectStr, Configuration& cfg)
+{
+    ConnectionStringParser parser(cfg);
+
+    diagnostic::DiagnosticRecordStorage diag;
+
+    BOOST_CHECK_NO_THROW(parser.ParseConnectionString(connectStr, &diag));
+
+    if (diag.GetStatusRecordsNumber() != 0)
+        BOOST_FAIL(diag.GetStatusRecord(1).GetMessageText());
+}
+
+void ParseConnectStringWithError(const std::string& connectStr, Configuration& cfg)
+{
+    ConnectionStringParser parser(cfg);
+
+    diagnostic::DiagnosticRecordStorage diag;
+
+    BOOST_CHECK_NO_THROW(parser.ParseConnectionString(connectStr, &diag));
+
+    BOOST_CHECK_NE(diag.GetStatusRecordsNumber(), 0);
+}
+
+void CheckValidAddress(const char* connectStr, const EndPoint& endPoint)
 {
     Configuration cfg;
 
-    BOOST_CHECK_NO_THROW(cfg.FillFromConnectString(connectStr));
+    ParseValidConnectString(connectStr, cfg);
+
+    const std::vector<EndPoint>& addrs = cfg.GetAddresses();
 
-    BOOST_CHECK_EQUAL(cfg.GetTcpPort(), port);
+    BOOST_REQUIRE_EQUAL(addrs.size(), 1);
+    BOOST_CHECK_EQUAL(addrs[0].host, endPoint.host);
+    BOOST_CHECK_EQUAL(addrs[0].port, endPoint.port);
 }
 
-void CheckValidProtocolVersion(const char* connectStr, ignite::odbc::ProtocolVersion version)
+void CheckValidAddresses(const char* connectStr, const std::vector<EndPoint>& endPoints)
 {
     Configuration cfg;
 
-    BOOST_CHECK_NO_THROW(cfg.FillFromConnectString(connectStr));
+    ParseValidConnectString(connectStr, cfg);
 
-    BOOST_CHECK(cfg.GetProtocolVersion() == version);
+    const std::vector<EndPoint>& addrs = cfg.GetAddresses();
+
+    BOOST_REQUIRE_EQUAL(addrs.size(), endPoints.size());
+
+    for (size_t i = 0; i < addrs.size(); ++i)
+    {
+        BOOST_CHECK_EQUAL(addrs[i].host, endPoints[i].host);
+        BOOST_CHECK_EQUAL(addrs[i].port, endPoints[i].port);
+    }
 }
 
-void CheckSupportedProtocolVersion(const char* connectStr)
+void CheckValidProtocolVersion(const char* connectStr, ProtocolVersion version)
 {
     Configuration cfg;
 
-    BOOST_CHECK_NO_THROW(cfg.FillFromConnectString(connectStr));
+    ParseValidConnectString(connectStr, cfg);
 
-    BOOST_CHECK(cfg.GetProtocolVersion().IsSupported());
+    BOOST_CHECK(cfg.GetProtocolVersion() == version);
 }
 
-void CheckInvalidProtocolVersion(const char* connectStr)
+void CheckSupportedProtocolVersion(const char* connectStr)
 {
     Configuration cfg;
 
-    cfg.FillFromConnectString(connectStr);
+    ParseValidConnectString(connectStr, cfg);
 
-    BOOST_CHECK_THROW(cfg.GetProtocolVersion(), ignite::IgniteError);
+    BOOST_CHECK(cfg.GetProtocolVersion().IsSupported());
 }
 
-void CheckUnsupportedProtocolVersion(const char* connectStr)
+void CheckInvalidProtocolVersion(const char* connectStr)
 {
     Configuration cfg;
 
-    cfg.FillFromConnectString(connectStr);
+    ParseConnectStringWithError(connectStr, cfg);
 
-    BOOST_CHECK(!cfg.GetProtocolVersion().IsSupported());
+    BOOST_CHECK(cfg.GetProtocolVersion() == Configuration::DefaultValue::protocolVersion);
 }
 
 void CheckValidBoolValue(const std::string& connectStr, const std::string& key, bool val)
 {
     Configuration cfg;
 
-    BOOST_CHECK_NO_THROW(cfg.FillFromConnectString(connectStr));
+    ParseValidConnectString(connectStr, cfg);
+
+    Configuration::ArgumentMap map;
+    cfg.ToMap(map);
+
+    std::string expected = val ? "true" : "false";
 
-    BOOST_CHECK_EQUAL(cfg.GetBoolValue(key, val), val);
+    BOOST_CHECK_EQUAL(map[key], expected);
 }
 
 void CheckInvalidBoolValue(const std::string& connectStr, const std::string& key)
 {
     Configuration cfg;
 
-    cfg.FillFromConnectString(connectStr);
+    ParseConnectStringWithError(connectStr, cfg);
 
-    BOOST_CHECK_THROW(cfg.GetBoolValue(key, false), ignite::IgniteError);
+    Configuration::ArgumentMap map;
+    cfg.ToMap(map);
+
+    BOOST_CHECK(map[key].empty());
 }
 
 void CheckConnectionConfig(const Configuration& cfg)
 {
     BOOST_CHECK_EQUAL(cfg.GetDriver(), testDriverName);
-    BOOST_CHECK_EQUAL(cfg.GetHost(), testServerHost);
-    BOOST_CHECK_EQUAL(cfg.GetTcpPort(), testServerPort);
-    BOOST_CHECK_EQUAL(cfg.GetAddress(), testAddress);
     BOOST_CHECK_EQUAL(cfg.GetSchema(), testSchemaName);
-    BOOST_CHECK_EQUAL(cfg.GetDsn(), std::string());
     BOOST_CHECK_EQUAL(cfg.GetPageSize(), testPageSize);
     BOOST_CHECK_EQUAL(cfg.IsDistributedJoins(), testDistributedJoins);
     BOOST_CHECK_EQUAL(cfg.IsEnforceJoinOrder(), testEnforceJoinOrder);
@@ -135,9 +192,21 @@ void CheckConnectionConfig(const Configuration& cfg)
     BOOST_CHECK_EQUAL(cfg.IsLazy(), testLazy);
     BOOST_CHECK_EQUAL(cfg.IsSkipReducerOnUpdate(), testSkipReducerOnUpdate);
 
+    BOOST_CHECK(!cfg.IsDsnSet());
+    BOOST_CHECK(!cfg.IsHostSet());
+    BOOST_CHECK(!cfg.IsTcpPortSet());
+
+    BOOST_CHECK(cfg.IsAddressesSet());
+
+    const std::vector<EndPoint>& addrs = cfg.GetAddresses();
+
+    BOOST_REQUIRE(!addrs.empty());
+    BOOST_CHECK_EQUAL(addrs[0].host, testAddress.host);
+    BOOST_CHECK_EQUAL(addrs[0].port, testAddress.port);
+
     std::stringstream constructor;
 
-    constructor << "address=" << testAddress << ';'
+    constructor << "address=" << testAddressStr << ';'
                 << "collocated=" << BoolToStr(testCollocated) << ';'
                 << "distributed_joins=" << BoolToStr(testDistributedJoins) << ';'
                 << "driver={" << testDriverName << "};"
@@ -158,7 +227,6 @@ void CheckDsnConfig(const Configuration& cfg)
     BOOST_CHECK_EQUAL(cfg.GetDriver(), testDriverName);
     BOOST_CHECK_EQUAL(cfg.GetDsn(), testDsn);
     BOOST_CHECK_EQUAL(cfg.GetSchema(), Configuration::DefaultValue::schema);
-    BOOST_CHECK_EQUAL(cfg.GetAddress(), Configuration::DefaultValue::address);
     BOOST_CHECK_EQUAL(cfg.GetHost(), std::string());
     BOOST_CHECK_EQUAL(cfg.GetTcpPort(), Configuration::DefaultValue::port);
     BOOST_CHECK_EQUAL(cfg.GetPageSize(), Configuration::DefaultValue::pageSize);
@@ -168,6 +236,7 @@ void CheckDsnConfig(const Configuration& cfg)
     BOOST_CHECK_EQUAL(cfg.IsCollocated(), false);
     BOOST_CHECK_EQUAL(cfg.IsLazy(), false);
     BOOST_CHECK_EQUAL(cfg.IsSkipReducerOnUpdate(), false);
+    BOOST_CHECK(cfg.GetAddresses().empty());
 }
 
 BOOST_AUTO_TEST_SUITE(ConfigurationTestSuite)
@@ -175,7 +244,7 @@ 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(testAddressStr, Configuration::DefaultValue::address);
     BOOST_CHECK_NE(testServerPort, Configuration::DefaultValue::port);
     BOOST_CHECK_NE(testSchemaName, Configuration::DefaultValue::schema);
     BOOST_CHECK_NE(testDsn, Configuration::DefaultValue::dsn);
@@ -196,7 +265,7 @@ BOOST_AUTO_TEST_CASE(TestConnectStringUppercase)
 
     constructor << "DRIVER={" << testDriverName << "};"
                 << "LAZY=" << BoolToStr(testLazy, false) << ';'
-                << "ADDRESS=" << testAddress << ';'
+                << "ADDRESS=" << testAddressStr << ';'
                 << "DISTRIBUTED_JOINS=" << BoolToStr(testDistributedJoins, false) << ';'
                 << "ENFORCE_JOIN_ORDER=" << BoolToStr(testEnforceJoinOrder, false) << ';'
                 << "COLLOCATED=" << BoolToStr(testCollocated, false) << ';'
@@ -207,7 +276,7 @@ BOOST_AUTO_TEST_CASE(TestConnectStringUppercase)
 
     const std::string& connectStr = constructor.str();
 
-    cfg.FillFromConnectString(connectStr);
+    ParseValidConnectString(connectStr, cfg);
 
     CheckConnectionConfig(cfg);
 }
@@ -220,7 +289,7 @@ BOOST_AUTO_TEST_CASE(TestConnectStringLowercase)
 
     constructor << "driver={" << testDriverName << "};"
                 << "lazy=" << BoolToStr(testLazy) << ';'
-                << "address=" << testAddress << ';'
+                << "address=" << testAddressStr << ';'
                 << "page_size=" << testPageSize << ';'
                 << "distributed_joins=" << BoolToStr(testDistributedJoins) << ';'
                 << "enforce_join_order=" << BoolToStr(testEnforceJoinOrder) << ';'
@@ -231,7 +300,7 @@ BOOST_AUTO_TEST_CASE(TestConnectStringLowercase)
 
     const std::string& connectStr = constructor.str();
 
-    cfg.FillFromConnectString(connectStr);
+    ParseValidConnectString(connectStr, cfg);
 
     CheckConnectionConfig(cfg);
 }
@@ -243,7 +312,7 @@ BOOST_AUTO_TEST_CASE(TestConnectStringZeroTerminated)
     std::stringstream constructor;
 
     constructor << "driver={" << testDriverName << "};"
-                << "address=" << testAddress << ';'
+                << "address=" << testAddressStr << ';'
                 << "lazy=" << BoolToStr(testLazy) << ';'
                 << "page_size=" << testPageSize << ';'
                 << "replicated_only=" << BoolToStr(testReplicatedOnly) << ';'
@@ -253,9 +322,11 @@ BOOST_AUTO_TEST_CASE(TestConnectStringZeroTerminated)
                 << "schema=" << testSchemaName << ';'
                 << "skip_reducer_on_update=" << BoolToStr(testSkipReducerOnUpdate);
 
-    const std::string& connectStr = constructor.str();
+    std::string connectStr = constructor.str();
+
+    connectStr.push_back(0);
 
-    cfg.FillFromConnectString(connectStr.c_str(), connectStr.size() + 1);
+    ParseValidConnectString(connectStr, cfg);
 
     CheckConnectionConfig(cfg);
 }
@@ -268,7 +339,7 @@ BOOST_AUTO_TEST_CASE(TestConnectStringMixed)
 
     constructor << "Driver={" << testDriverName << "};"
                 << "Lazy=" << BoolToStr(testLazy) << ';'
-                << "Address=" << testAddress << ';'
+                << "Address=" << testAddressStr << ';'
                 << "Page_Size=" << testPageSize << ';'
                 << "Distributed_Joins=" << BoolToStr(testDistributedJoins, false) << ';'
                 << "Enforce_Join_Order=" << BoolToStr(testEnforceJoinOrder) << ';'
@@ -279,7 +350,7 @@ BOOST_AUTO_TEST_CASE(TestConnectStringMixed)
 
     const std::string& connectStr = constructor.str();
 
-    cfg.FillFromConnectString(connectStr);
+    ParseValidConnectString(connectStr, cfg);
 
     CheckConnectionConfig(cfg);
 }
@@ -291,7 +362,7 @@ BOOST_AUTO_TEST_CASE(TestConnectStringWhitepaces)
     std::stringstream constructor;
 
     constructor << "DRIVER = {" << testDriverName << "} ;\n"
-                << " ADDRESS =" << testAddress << "; "
+                << " ADDRESS =" << testAddressStr << "; "
                 << "   PAGE_SIZE= " << testPageSize << ';'
                 << "   DISTRIBUTED_JOINS=" << BoolToStr(testDistributedJoins, false) << ';'
                 << "LAZY=" << BoolToStr(testLazy, false) << ';'
@@ -303,7 +374,7 @@ BOOST_AUTO_TEST_CASE(TestConnectStringWhitepaces)
 
     const std::string& connectStr = constructor.str();
 
-    cfg.FillFromConnectString(connectStr);
+    ParseValidConnectString(connectStr, cfg);
 
     CheckConnectionConfig(cfg);
 }
@@ -312,22 +383,47 @@ 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);
+    ParseConnectStringWithError("Address=example.com:0;", cfg);
+    ParseConnectStringWithError("Address=example.com:00000;", cfg);
+    ParseConnectStringWithError("Address=example.com:fdsf;", cfg);
+    ParseConnectStringWithError("Address=example.com:123:1;", cfg);
+    ParseConnectStringWithError("Address=example.com:12322221;", cfg);
+    ParseConnectStringWithError("Address=example.com:12322a;", cfg);
+    ParseConnectStringWithError("Address=example.com:;", cfg);
 }
 
 BOOST_AUTO_TEST_CASE(TestConnectStringValidAddress)
 {
-    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::port);
+    CheckValidAddress("Address=example.com:1;", EndPoint("example.com", 1));
+    CheckValidAddress("Address=example.com:31242;", EndPoint("example.com", 31242));
+    CheckValidAddress("Address=example.com:55555;", EndPoint("example.com", 55555));
+    CheckValidAddress("Address=example.com:110;", EndPoint("example.com", 110));
+    CheckValidAddress("Address=example.com;", EndPoint("example.com", Configuration::DefaultValue::port));
+    CheckValidAddress("Address=example.com:1000..1010;", EndPoint("example.com", 1000, 10));
+}
+
+BOOST_AUTO_TEST_CASE(TestConnectStringValidAddress4)
+{
+    std::vector<EndPoint> addrs;
+
+    addrs.push_back(EndPoint("one.com", 1234));
+    addrs.push_back(EndPoint("two.net", 42, 53-42));
+    addrs.push_back(EndPoint("three.eu", Configuration::DefaultValue::port));
+    addrs.push_back(EndPoint("some.long.name.org", 50141));
+
+    CheckValidAddresses("Address=some.long.name.org:50141,three.eu,two.net:42..53,one.com:1234", addrs);
+}
+
+BOOST_AUTO_TEST_CASE(TestConnectStringValidAddress4Spaces)
+{
+    std::vector<EndPoint> addrs;
+
+    addrs.push_back(EndPoint("one.com", 1234));
+    addrs.push_back(EndPoint("two.net", 42, 53 - 42));
+    addrs.push_back(EndPoint("three.eu", Configuration::DefaultValue::port));
+    addrs.push_back(EndPoint("some.long.name.org", 50141));
+
+    CheckValidAddresses("Address = some.long.name.org:50141, three.eu, two.net: 42 .. 53, one.com:1234", addrs);
 }
 
 BOOST_AUTO_TEST_CASE(TestConnectStringInvalidVersion)
@@ -340,22 +436,17 @@ BOOST_AUTO_TEST_CASE(TestConnectStringInvalidVersion)
 
 BOOST_AUTO_TEST_CASE(TestConnectStringUnsupportedVersion)
 {
-    CheckUnsupportedProtocolVersion("Protocol_Version=1.6.1;");
-    CheckUnsupportedProtocolVersion("Protocol_Version=1.7.0;");
-    CheckUnsupportedProtocolVersion("Protocol_Version=1.8.1;");
-}
-
-BOOST_AUTO_TEST_CASE(TestConnectStringValidVersion)
-{
-    CheckValidProtocolVersion("Protocol_Version=2.1.0;", ignite::odbc::ProtocolVersion::VERSION_2_1_0);
-    CheckValidProtocolVersion("Protocol_Version=1.6.1;", ignite::odbc::ProtocolVersion(1, 6, 1));
-    CheckValidProtocolVersion("Protocol_Version=1.7.0;", ignite::odbc::ProtocolVersion(1, 7, 0));
-    CheckValidProtocolVersion("Protocol_Version=1.8.1;", ignite::odbc::ProtocolVersion(1, 8, 1));
+    CheckInvalidProtocolVersion("Protocol_Version=1.6.1;");
+    CheckInvalidProtocolVersion("Protocol_Version=1.7.0;");
+    CheckInvalidProtocolVersion("Protocol_Version=1.8.1;");
 }
 
 BOOST_AUTO_TEST_CASE(TestConnectStringSupportedVersion)
 {
     CheckSupportedProtocolVersion("Protocol_Version=2.1.0;");
+    CheckSupportedProtocolVersion("Protocol_Version=2.1.5;");
+    CheckSupportedProtocolVersion("Protocol_Version=2.3.0;");
+    CheckSupportedProtocolVersion("Protocol_Version=2.3.2;");
 }
 
 BOOST_AUTO_TEST_CASE(TestConnectStringInvalidBoolKeys)
@@ -424,7 +515,7 @@ BOOST_AUTO_TEST_CASE(TestDsnStringUppercase)
 
     const std::string& configStr = constructor.str();
 
-    cfg.FillFromConfigAttributes(configStr.data());
+    ParseValidDsnString(configStr, cfg);
 
     CheckDsnConfig(cfg);
 }
@@ -440,7 +531,7 @@ BOOST_AUTO_TEST_CASE(TestDsnStringLowercase)
 
     const std::string& configStr = constructor.str();
 
-    cfg.FillFromConfigAttributes(configStr.data());
+    ParseValidDsnString(configStr, cfg);
 
     CheckDsnConfig(cfg);
 }
@@ -456,7 +547,7 @@ BOOST_AUTO_TEST_CASE(TestDsnStringMixed)
 
     const std::string& configStr = constructor.str();
 
-    cfg.FillFromConfigAttributes(configStr.data());
+    ParseValidDsnString(configStr, cfg);
 
     CheckDsnConfig(cfg);
 }
@@ -472,7 +563,7 @@ BOOST_AUTO_TEST_CASE(TestDsnStringWhitespaces)
 
     const std::string& configStr = constructor.str();
 
-    cfg.FillFromConfigAttributes(configStr.data());
+    ParseValidDsnString(configStr, cfg);
 
     CheckDsnConfig(cfg);
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc-test/src/odbc_test_suite.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/odbc_test_suite.cpp b/modules/platforms/cpp/odbc-test/src/odbc_test_suite.cpp
index fca3604..7e84aff 100644
--- a/modules/platforms/cpp/odbc-test/src/odbc_test_suite.cpp
+++ b/modules/platforms/cpp/odbc-test/src/odbc_test_suite.cpp
@@ -145,6 +145,31 @@ namespace ignite
             return builder.str();
         }
 
+        void OdbcTestSuite::CheckSQLDiagnosticError(int16_t handleType, SQLHANDLE handle, const std::string& expectSqlState)
+        {
+            SQLCHAR state[ODBC_BUFFER_SIZE];
+            SQLINTEGER nativeError = 0;
+            SQLCHAR message[ODBC_BUFFER_SIZE];
+            SQLSMALLINT messageLen = 0;
+
+            SQLRETURN ret = SQLGetDiagRec(handleType, handle, 1, state, &nativeError, message, sizeof(message), &messageLen);
+
+            const std::string sqlState = reinterpret_cast<char*>(state);
+            BOOST_REQUIRE_EQUAL(ret, SQL_SUCCESS);
+            BOOST_REQUIRE_EQUAL(sqlState, expectSqlState);
+            BOOST_REQUIRE(messageLen > 0);
+        }
+
+        void OdbcTestSuite::CheckSQLStatementDiagnosticError(const std::string& expectSqlState)
+        {
+            CheckSQLDiagnosticError(SQL_HANDLE_STMT, stmt, expectSqlState);
+        }
+
+        void OdbcTestSuite::CheckSQLConnectionDiagnosticError(const std::string& expectSqlState)
+        {
+            CheckSQLDiagnosticError(SQL_HANDLE_DBC, dbc, expectSqlState);
+        }
+
         void OdbcTestSuite::InsertTestStrings(int recordsNum, bool merge)
         {
             SQLCHAR insertReq[] = "INSERT INTO TestType(_key, strField) VALUES(?, ?)";

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/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 45cf9dd..b47e9b7 100644
--- a/modules/platforms/cpp/odbc-test/src/queries_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/queries_test.cpp
@@ -239,46 +239,6 @@ struct QueriesTestSuiteFixture : odbc::OdbcTestSuite
 
 BOOST_FIXTURE_TEST_SUITE(QueriesTestSuite, QueriesTestSuiteFixture)
 
-BOOST_AUTO_TEST_CASE(TestLegacyConnection)
-{
-    Connect("DRIVER={Apache Ignite};SERVER=127.0.0.1;PORT=11110;SCHEMA=cache");
-
-    InsertTestStrings(10, false);
-    InsertTestBatch(11, 20, 9);
-}
-
-BOOST_AUTO_TEST_CASE(TestConnectionProtocolVersion_2_1_0)
-{
-    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache;PROTOCOL_VERSION=2.1.0");
-
-    InsertTestStrings(10, false);
-    InsertTestBatch(11, 20, 9);
-}
-
-BOOST_AUTO_TEST_CASE(TestConnectionProtocolVersion_2_1_5)
-{
-    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache;PROTOCOL_VERSION=2.1.5");
-
-    InsertTestStrings(10, false);
-    InsertTestBatch(11, 20, 9);
-}
-
-BOOST_AUTO_TEST_CASE(TestConnectionProtocolVersion_2_3_0)
-{
-    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache;PROTOCOL_VERSION=2.3.0");
-
-    InsertTestStrings(10, false);
-    InsertTestBatch(11, 20, 9);
-}
-
-BOOST_AUTO_TEST_CASE(TestConnectionProtocolVersion_2_3_2)
-{
-    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache;PROTOCOL_VERSION=2.3.2");
-
-    InsertTestStrings(10, false);
-    InsertTestBatch(11, 20, 9);
-}
-
 BOOST_AUTO_TEST_CASE(TestTwoRowsInt8)
 {
     CheckTwoRowsInt<signed char>(SQL_C_STINYINT);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc-test/src/sql_get_info_test.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/sql_get_info_test.cpp b/modules/platforms/cpp/odbc-test/src/sql_get_info_test.cpp
index 10bcb0e..4d9c809 100644
--- a/modules/platforms/cpp/odbc-test/src/sql_get_info_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/sql_get_info_test.cpp
@@ -19,8 +19,7 @@
 #   include <windows.h>
 #endif
 
-#include <sql.h>
-#include <sqlext.h>
+#include "ignite/odbc/system/odbc_constants.h"
 
 #include <vector>
 #include <string>

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc/Makefile.am
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/Makefile.am b/modules/platforms/cpp/odbc/Makefile.am
index ea74c34..90e4dc9 100644
--- a/modules/platforms/cpp/odbc/Makefile.am
+++ b/modules/platforms/cpp/odbc/Makefile.am
@@ -54,8 +54,10 @@ libignite_odbc_la_SOURCES = \
     src/app/parameter.cpp \
     src/app/parameter_set.cpp \
     src/common_types.cpp \
+    src/config/config_tools.cpp \
     src/config/configuration.cpp \
     src/config/connection_info.cpp \
+	src/config/connection_string_parser.cpp \
     src/connection.cpp \
     src/cursor.cpp \
     src/diagnostic/diagnosable_adapter.cpp \

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc/include/ignite/odbc/config/config_tools.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/config/config_tools.h b/modules/platforms/cpp/odbc/include/ignite/odbc/config/config_tools.h
new file mode 100644
index 0000000..5731191
--- /dev/null
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/config/config_tools.h
@@ -0,0 +1,92 @@
+/*
+ * 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_CONFIG_CONFIG_TOOLS
+#define _IGNITE_ODBC_CONFIG_CONFIG_TOOLS
+
+#include <string>
+#include <vector>
+#include <sstream>
+
+#include "ignite/odbc/end_point.h"
+
+namespace ignite
+{
+    namespace odbc
+    {
+        namespace diagnostic
+        {
+            // Forward declaration.
+            class DiagnosticRecordStorage;
+        }
+
+        namespace config
+        {
+            /**
+             * Convert address list to string.
+             *
+             * @param addresses Addresses.
+             * @return Resulting string.
+             */
+            std::string AddressesToString(const std::vector<EndPoint>& addresses);
+
+            /**
+             * Parse address.
+             *
+             * @param value String value to parse.
+             * @param endPoints End ponts list.
+             * @param diag Diagnostics collector.
+             */
+            void ParseAddress(const std::string& value, std::vector<EndPoint>& endPoints,
+                diagnostic::DiagnosticRecordStorage* diag);
+
+            /**
+             * Parse single address.
+             *
+             * @param value String value to parse.
+             * @param endPoint End pont.
+             * @param diag Diagnostics collector.
+             * @return @c true, if parsed successfully, and @c false otherwise.
+             */
+            bool ParseSingleAddress(const std::string& value, EndPoint& endPoint,
+                diagnostic::DiagnosticRecordStorage* diag);
+
+            /**
+             * Parse single network port.
+             *
+             * @param value String value to parse.
+             * @param port Port range begin.
+             * @param range Number of ports in range.
+             * @param diag Diagnostics collector.
+             * @return @c Port value on success and zero on failure.
+             */
+            bool ParsePortRange(const std::string& value, uint16_t& port, uint16_t& range,
+                diagnostic::DiagnosticRecordStorage* diag);
+
+            /**
+             * Parse single network port.
+             *
+             * @param value String value to parse.
+             * @param diag Diagnostics collector.
+             * @return @c Port value on success and zero on failure.
+             */
+            uint16_t ParsePort(const std::string& value, diagnostic::DiagnosticRecordStorage* diag);
+        }
+    }
+}
+
+#endif //_IGNITE_ODBC_CONFIG_CONFIG_TOOLS
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/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 89018f5..079008c 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/config/configuration.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/config/configuration.h
@@ -22,9 +22,10 @@
 #include <string>
 #include <map>
 
-#include <ignite/common/common.h>
-#include <ignite/common/utils.h>
 #include "ignite/odbc/protocol_version.h"
+#include "ignite/odbc/config/settable_value.h"
+#include "ignite/odbc/ssl/ssl_mode.h"
+#include "ignite/odbc/end_point.h"
 
 namespace ignite
 {
@@ -38,67 +39,9 @@ namespace ignite
             class Configuration
             {
             public:
-                /** Map containing connect arguments. */
+                /** Argument map type. */
                 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 schema attribute. */
-                    static const std::string schema;
-
-                    /** 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;
-
-                    /** Connection attribute keyword for distributed joins attribute. */
-                    static const std::string distributedJoins;
-
-                    /** Connection attribute keyword for enforce join order attribute. */
-                    static const std::string enforceJoinOrder;
-
-                    /** Connection attribute keyword for protocol version attribute. */
-                    static const std::string protocolVersion;
-
-                    /** Connection attribute keyword for fetch results page size attribute. */
-                    static const std::string pageSize;
-
-                    /** Connection attribute keyword for replicated only attribute. */
-                    static const std::string replicatedOnly;
-
-                    /** Connection attribute keyword for collocated attribute. */
-                    static const std::string collocated;
-
-                    /** Connection attribute keyword for lazy attribute. */
-                    static const std::string lazy;
-
-                    /** Connection attribute keyword for skipReducerOnUpdate attribute. */
-                    static const std::string skipReducerOnUpdate;
-
-                    /** Connection attribute keyword for sslMode attribute. */
-                    static const std::string sslMode;
-
-                    /** Connection attribute keyword for sslKeyFile attribute. */
-                    static const std::string sslKeyFile;
-
-                    /** Connection attribute keyword for sslCertFile attribute. */
-                    static const std::string sslCertFile;
-
-                    /** Connection attribute keyword for sslCaFile attribute. */
-                    static const std::string sslCaFile;
-                };
-
                 /** Default values for configuration. */
                 struct DefaultValue
                 {
@@ -118,7 +61,7 @@ namespace ignite
                     static const std::string server;
 
                     /** Default value for sslMode attribute. */
-                    static const std::string sslMode;
+                    static const ssl::SslMode::Type sslMode;
 
                     /** Default value for sslKeyFile attribute. */
                     static const std::string sslKeyFile;
@@ -158,18 +101,6 @@ namespace ignite
                 };
 
                 /**
-                 * Connection end point structure.
-                 */
-                struct EndPoint
-                {
-                    /** Remote host. */
-                    std::string host;
-
-                    /** TCP port. */
-                    uint16_t port;
-                };
-
-                /**
                  * Default constructor.
                  */
                 Configuration();
@@ -180,24 +111,6 @@ namespace ignite
                 ~Configuration();
 
                 /**
-                 * Fill configuration data using connection string.
-                 *
-                 * @param str Pointer to string data.
-                 * @param len String length.
-                 */
-                void FillFromConnectString(const char* str, size_t len);
-                
-                /**
-                 * Fill configuration data using connection string.
-                 *
-                 * @param str Connect string.
-                 */
-                void FillFromConnectString(const std::string& str)
-                {
-                    FillFromConnectString(str.data(), str.size());
-                }
-
-                /**
                  * Convert configure to connect string.
                  *
                  * @return Connect string.
@@ -205,22 +118,11 @@ namespace ignite
                 std::string ToConnectString() const;
 
                 /**
-                 * Fill configuration data using config attributes string.
-                 *
-                 * @param attributes Pointer to list of zero-terminated strings.
-                 *     Terminated by two zero bytes.
-                 */
-                void FillFromConfigAttributes(const char* attributes);
-
-                /**
                  * Get server port.
                  *
                  * @return Server port.
                  */
-                uint16_t GetTcpPort() const
-                {
-                    return endPoint.port;
-                }
+                uint16_t GetTcpPort() const;
 
                 /**
                  * Set server port.
@@ -230,44 +132,53 @@ namespace ignite
                 void SetTcpPort(uint16_t port);
 
                 /**
+                 * Check if the value set.
+                 *
+                 * @return @true if the value set.
+                 */
+                bool IsTcpPortSet() const;
+
+                /**
                  * Get DSN.
                  *
                  * @return Data Source Name.
                  */
-                const std::string& GetDsn(const std::string& dflt = DefaultValue::dsn) const
-                {
-                    return GetStringValue(Key::dsn, dflt);
-                }
+                const std::string& GetDsn(const std::string& dflt = DefaultValue::dsn) const;
+
+                /**
+                 * Check if the value set.
+                 *
+                 * @return @true if the value set.
+                 */
+                bool IsDsnSet() const;
 
                 /**
                  * Set DSN.
                  *
                  * @param dsn Data Source Name.
                  */
-                void SetDsn(const std::string& dsn)
-                {
-                    arguments[Key::dsn] = dsn;
-                }
+                void SetDsn(const std::string& dsn);
 
                 /**
                  * Get Driver.
                  *
                  * @return Driver name.
                  */
-                const std::string& GetDriver() const
-                {
-                    return GetStringValue(Key::driver, DefaultValue::driver);
-                }
+                const std::string& GetDriver() const;
+
+                /**
+                 * Set driver.
+                 *
+                 * @param driver Driver.
+                 */
+                void SetDriver(const std::string& driver);
 
                 /**
                  * Get server host.
                  *
                  * @return Server host.
                  */
-                const std::string& GetHost() const
-                {
-                    return endPoint.host;
-                }
+                const std::string& GetHost() const;
 
                 /**
                  * Set server host.
@@ -277,241 +188,263 @@ namespace ignite
                 void SetHost(const std::string& server);
 
                 /**
+                 * Check if the value set.
+                 *
+                 * @return @true if the value set.
+                 */
+                bool IsHostSet() const;
+
+                /**
                  * Get schema.
                  *
                  * @return Schema.
                  */
-                const std::string& GetSchema() const
-                {
-                    return GetStringValue(Key::schema, DefaultValue::schema);
-                }
+                const std::string& GetSchema() const;
 
                 /**
                  * Set schema.
                  *
                  * @param schema Schema name.
                  */
-                void SetSchema(const std::string& schema)
-                {
-                    arguments[Key::schema] = schema;
-                }
+                void SetSchema(const std::string& schema);
 
                 /**
-                 * Get address.
+                 * Check if the value set.
                  *
-                 * @return Address.
+                 * @return @true if the value set.
                  */
-                const std::string& GetAddress() const
-                {
-                    return GetStringValue(Key::address, DefaultValue::address);
-                }
+                bool IsSchemaSet() const;
+
+                /**
+                 * Get addresses.
+                 *
+                 * @return Addresses.
+                 */
+                const std::vector<EndPoint>& GetAddresses() const;
 
                 /**
-                 * Set address.
+                 * Set addresses to connect to.
                  *
-                 * @param address Address.
+                 * @param endPoints Addresses.
                  */
-                void SetAddress(const std::string& address);
+                void SetAddresses(const std::vector<EndPoint>& endPoints);
+
+                /**
+                 * Check if the value set.
+                 *
+                 * @return @true if the value set.
+                 */
+                bool IsAddressesSet() const;
 
                 /**
                  * Get SSL mode.
                  *
                  * @return SSL mode.
                  */
-                const std::string& GetSslMode() const
-                {
-                    return GetStringValue(Key::sslMode, DefaultValue::sslMode);
-                }
+                ssl::SslMode::Type GetSslMode() const;
 
                 /**
                  * Set SSL mode.
                  *
                  * @param sslMode SSL mode.
                  */
-                void SetSslMode(const std::string& sslMode)
-                {
-                    arguments[Key::sslMode] = sslMode;
-                }
+                void SetSslMode(ssl::SslMode::Type sslMode);
+
+                /**
+                 * Check if the value set.
+                 *
+                 * @return @true if the value set.
+                 */
+                bool IsSslModeSet() const;
 
                 /**
                  * Get SSL key file path.
                  *
                  * @return SSL key file path.
                  */
-                const std::string& GetSslKeyFile() const
-                {
-                    return GetStringValue(Key::sslKeyFile, DefaultValue::sslKeyFile);
-                }
+                const std::string& GetSslKeyFile() const;
 
                 /**
                  * Set SSL key file path.
                  *
                  * @param sslKeyFile SSL key file path.
                  */
-                void SetSslKeyFile(const std::string& sslKeyFile)
-                {
-                    arguments[Key::sslKeyFile] = sslKeyFile;
-                }
+                void SetSslKeyFile(const std::string& sslKeyFile);
+
+                /**
+                 * Check if the value set.
+                 *
+                 * @return @true if the value set.
+                 */
+                bool IsSslKeyFileSet() const;
 
                 /**
                  * Get SSL certificate file path.
                  *
                  * @return SSL certificate file path.
                  */
-                const std::string& GetSslCertFile() const
-                {
-                    return GetStringValue(Key::sslCertFile, DefaultValue::sslCertFile);
-                }
+                const std::string& GetSslCertFile() const;
 
                 /**
                  * Set SSL certificate file path.
                  *
                  * @param sslCertFile SSL certificate file path.
                  */
-                void SetSslCertFile(const std::string& sslCertFile)
-                {
-                    arguments[Key::sslCertFile] = sslCertFile;
-                }
+                void SetSslCertFile(const std::string& sslCertFile);
+
+                /**
+                 * Check if the value set.
+                 *
+                 * @return @true if the value set.
+                 */
+                bool IsSslCertFileSet() const;
 
                 /**
                  * Get SSL certificate authority file path.
                  *
                  * @return SSL certificate authority file path.
                  */
-                const std::string& GetSslCaFile() const
-                {
-                    return GetStringValue(Key::sslCaFile, DefaultValue::sslCaFile);
-                }
+                const std::string& GetSslCaFile() const;
 
                 /**
                  * Set SSL certificate authority file path.
                  *
                  * @param sslCaFile SSL certificate authority file path.
                  */
-                void SetSslCaFile(const std::string& sslCaFile)
-                {
-                    arguments[Key::sslCaFile] = sslCaFile;
-                }
+                void SetSslCaFile(const std::string& sslCaFile);
+
+                /**
+                 * Check if the value set.
+                 *
+                 * @return @true if the value set.
+                 */
+                bool IsSslCaFileSet() const;
 
                 /**
                  * Check distributed joins flag.
                  *
                  * @return True if distributed joins are enabled.
                  */
-                bool IsDistributedJoins() const
-                {
-                    return GetBoolValue(Key::distributedJoins, DefaultValue::distributedJoins);
-                }
+                bool IsDistributedJoins() const;
 
                 /**
                  * Set distributed joins.
                  *
                  * @param val Value to set.
                  */
-                void SetDistributedJoins(bool val)
-                {
-                    SetBoolValue(Key::distributedJoins, val);
-                }
+                void SetDistributedJoins(bool val);
+
+                /**
+                 * Check if the value set.
+                 *
+                 * @return @true if the value set.
+                 */
+                bool IsDistributedJoinsSet() const;
 
                 /**
                  * Check enforce join order flag.
                  *
                  * @return True if enforcing of join order is enabled.
                  */
-                bool IsEnforceJoinOrder() const
-                {
-                    return GetBoolValue(Key::enforceJoinOrder, DefaultValue::enforceJoinOrder);
-                }
+                bool IsEnforceJoinOrder() const;
 
                 /**
                  * Set enforce joins.
                  *
                  * @param val Value to set.
                  */
-                void SetEnforceJoinOrder(bool val)
-                {
-                    SetBoolValue(Key::enforceJoinOrder, val);
-                }
+                void SetEnforceJoinOrder(bool val);
+
+                /**
+                 * Check if the value set.
+                 *
+                 * @return @true if the value set.
+                 */
+                bool IsEnforceJoinOrderSet() const;
 
                 /**
                  * Check replicated only flag.
                  *
                  * @return True if replicated only is enabled.
                  */
-                bool IsReplicatedOnly() const
-                {
-                    return GetBoolValue(Key::replicatedOnly, DefaultValue::replicatedOnly);
-                }
+                bool IsReplicatedOnly() const;
 
                 /**
                  * Set replicated only flag.
                  *
                  * @param val Value to set.
                  */
-                void SetReplicatedOnly(bool val)
-                {
-                    SetBoolValue(Key::replicatedOnly, val);
-                }
+                void SetReplicatedOnly(bool val);
+
+                /**
+                 * Check if the value set.
+                 *
+                 * @return @true if the value set.
+                 */
+                bool IsReplicatedOnlySet() const;
 
                 /**
                  * Check collocated flag.
                  *
                  * @return True if collocated is enabled.
                  */
-                bool IsCollocated() const
-                {
-                    return GetBoolValue(Key::collocated, DefaultValue::collocated);
-                }
+                bool IsCollocated() const;
 
                 /**
                  * Set collocated.
                  *
                  * @param val Value to set.
                  */
-                void SetCollocated(bool val)
-                {
-                    SetBoolValue(Key::collocated, val);
-                }
+                void SetCollocated(bool val);
+
+                /**
+                 * Check if the value set.
+                 *
+                 * @return @true if the value set.
+                 */
+                bool IsCollocatedSet() const;
 
                 /**
                  * Check lazy flag.
                  *
                  * @return True if lazy is enabled.
                  */
-                bool IsLazy() const
-                {
-                    return GetBoolValue(Key::lazy, DefaultValue::lazy);
-                }
+                bool IsLazy() const;
 
                 /**
                  * Set lazy.
                  *
                  * @param val Value to set.
                  */
-                void SetLazy(bool val)
-                {
-                    SetBoolValue(Key::lazy, val);
-                }
+                void SetLazy(bool val);
+
+                /**
+                 * Check if the value set.
+                 *
+                 * @return @true if the value set.
+                 */
+                bool IsLazySet() const;
 
                 /**
                  * Check update on server flag.
                  *
                  * @return True if update on server.
                  */
-                bool IsSkipReducerOnUpdate() const
-                {
-                    return GetBoolValue(Key::skipReducerOnUpdate, DefaultValue::skipReducerOnUpdate);
-                }
+                bool IsSkipReducerOnUpdate() const;
 
                 /**
                  * Set update on server.
                  *
                  * @param val Value to set.
                  */
-                void SetSkipReducerOnUpdate(bool val)
-                {
-                    SetBoolValue(Key::skipReducerOnUpdate, val);
-                }
+                void SetSkipReducerOnUpdate(bool val);
+
+                /**
+                 * Check if the value set.
+                 *
+                 * @return @true if the value set.
+                 */
+                bool IsSkipReducerOnUpdateSet() const;
 
                 /**
                  * Get protocol version.
@@ -525,101 +458,137 @@ namespace ignite
                  *
                  * @param version Version to set.
                  */
-                void SetProtocolVersion(const std::string& version)
-                {
-                    arguments[Key::protocolVersion] = version;
-                }
+                void SetProtocolVersion(const ProtocolVersion& version);
 
                 /**
-                 * Get argument map.
+                 * Check if the value set.
                  *
-                 * @return Argument map.
+                 * @return @true if the value set.
                  */
-                const ArgumentMap& GetMap() const
-                {
-                    return arguments;
-                }
+                bool IsProtocolVersionSet() const;
 
                 /**
                  * Get fetch results page size.
                  *
                  * @return Fetch results page size.
                  */
-                int32_t GetPageSize() const
-                {
-                    return static_cast<int32_t>(GetIntValue(Key::pageSize, DefaultValue::pageSize));
-                }
+                int32_t GetPageSize() const;
+
                 /**
                  * Set fetch results page size.
                  *
                  * @param size Fetch results page size.
                  */
-                void SetPageSize(int32_t size)
-                {
-                    arguments[Key::pageSize] = common::LexicalCast<std::string>(size);
-                }
-
-                /**
-                 * 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;
+                void SetPageSize(int32_t size);
 
                 /**
-                 * Get int value from the config.
+                 * Check if the value set.
                  *
-                 * @param key Configuration key.
-                 * @param dflt Default value to be returned if there is no value stored.
-                 * @return Found or default value.
+                 * @return @true if the value set.
                  */
-                int64_t GetIntValue(const std::string& key, int64_t dflt) const;
+                bool IsPageSizeSet() const;
 
                 /**
-                 * Get bool value from the config.
+                 * Get argument map.
                  *
-                 * @param key Configuration key.
-                 * @param dflt Default value to be returned if there is no value stored.
-                 * @return Found or default value.
+                 * @param res Resulting argument map.
                  */
-                bool GetBoolValue(const std::string& key, bool dflt) const;
+                void ToMap(ArgumentMap& res) const;
 
-                /**
-                 * Set bool value to the config.
-                 *
-                 * @param key Configuration key.
-                 * @param val Value to set.
-                 */
-                void SetBoolValue(const std::string& key, bool val);
             private:
                 /**
-                 * Parse connect string into key-value storage.
+                 * Add key and value to the argument map.
                  *
-                 * @param str String to parse.
-                 * @param len String length.
-                 * @param args Parsing result.
+                 * @param map Map.
+                 * @param key Key.
+                 * @param value Value.
                  */
-                static void ParseAttributeList(const char* str, size_t len, char delimeter, ArgumentMap& args);
+                template<typename T>
+                static void AddToMap(ArgumentMap& map, const std::string& key, const SettableValue<T>& value);
 
-                /**
-                 * 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);
+                /** DSN. */
+                SettableValue<std::string> dsn;
+
+                /** Driver name. */
+                SettableValue<std::string> driver;
 
-                /** Arguments. */
-                ArgumentMap arguments;
+                /** Schema. */
+                SettableValue<std::string> schema;
 
-                /** Connection end-point. */
-                EndPoint endPoint;
+                /** Server. Deprecated. */
+                SettableValue<std::string> server;
+
+                /** TCP port. Deprecated. */
+                SettableValue<uint16_t> port;
+
+                /** Request and response page size. */
+                SettableValue<int32_t> pageSize;
+
+                /** Distributed joins flag. */
+                SettableValue<bool> distributedJoins;
+
+                /** Enforce join order flag. */
+                SettableValue<bool> enforceJoinOrder;
+
+                /** Replicated only flag. */
+                SettableValue<bool> replicatedOnly;
+
+                /** Collocated flag. */
+                SettableValue<bool> collocated;
+
+                /** Lazy flag. */
+                SettableValue<bool> lazy;
+
+                /** Skip reducer on update flag. */
+                SettableValue<bool> skipReducerOnUpdate;
+
+                /** Protocol version. */
+                SettableValue<ProtocolVersion> protocolVersion;
+
+                /** Connection end-points. */
+                SettableValue< std::vector<EndPoint> > endPoints;
+
+                /** SSL Mode. */
+                SettableValue<ssl::SslMode::Type> sslMode;
+
+                /** SSL private key file path. */
+                SettableValue<std::string> sslKeyFile;
+
+                /** SSL certificate file path. */
+                SettableValue<std::string> sslCertFile;
+
+                /** SSL certificate authority file path. */
+                SettableValue<std::string> sslCaFile;
             };
-        }
 
+            template<>
+            void Configuration::AddToMap<std::string>(ArgumentMap& map, const std::string& key,
+                const SettableValue<std::string>& value);
+
+            template<>
+            void Configuration::AddToMap<uint16_t>(ArgumentMap& map, const std::string& key,
+                const SettableValue<uint16_t>& value);
+
+            template<>
+            void Configuration::AddToMap<int32_t>(ArgumentMap& map, const std::string& key,
+                const SettableValue<int32_t>& value);
+
+            template<>
+            void Configuration::AddToMap<bool>(ArgumentMap& map, const std::string& key,
+                const SettableValue<bool>& value);
+
+            template<>
+            void Configuration::AddToMap<ProtocolVersion>(ArgumentMap& map, const std::string& key,
+                const SettableValue<ProtocolVersion>& value);
+
+            template<>
+            void Configuration::AddToMap< std::vector<EndPoint> >(ArgumentMap& map, const std::string& key,
+                const SettableValue< std::vector<EndPoint> >& value);
+
+            template<>
+            void Configuration::AddToMap<ssl::SslMode::Type>(ArgumentMap& map, const std::string& key,
+                const SettableValue<ssl::SslMode::Type>& value);
+        }
     }
 }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc/include/ignite/odbc/config/connection_string_parser.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/config/connection_string_parser.h b/modules/platforms/cpp/odbc/include/ignite/odbc/config/connection_string_parser.h
new file mode 100644
index 0000000..ed31dcb
--- /dev/null
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/config/connection_string_parser.h
@@ -0,0 +1,188 @@
+/*
+ * 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_CONFIG_CONNECTION_STRING_PARSER
+#define _IGNITE_ODBC_CONFIG_CONNECTION_STRING_PARSER
+
+#include <string>
+
+#include "ignite/odbc/config/configuration.h"
+#include "ignite/odbc/diagnostic/diagnostic_record_storage.h"
+
+namespace ignite
+{
+    namespace odbc
+    {
+        namespace config
+        {
+            /**
+             * ODBC configuration parser abstraction.
+             */
+            class ConnectionStringParser
+            {
+            public:
+                /** 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 schema attribute. */
+                    static const std::string schema;
+
+                    /** 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;
+
+                    /** Connection attribute keyword for distributed joins attribute. */
+                    static const std::string distributedJoins;
+
+                    /** Connection attribute keyword for enforce join order attribute. */
+                    static const std::string enforceJoinOrder;
+
+                    /** Connection attribute keyword for protocol version attribute. */
+                    static const std::string protocolVersion;
+
+                    /** Connection attribute keyword for fetch results page size attribute. */
+                    static const std::string pageSize;
+
+                    /** Connection attribute keyword for replicated only attribute. */
+                    static const std::string replicatedOnly;
+
+                    /** Connection attribute keyword for collocated attribute. */
+                    static const std::string collocated;
+
+                    /** Connection attribute keyword for lazy attribute. */
+                    static const std::string lazy;
+
+                    /** Connection attribute keyword for skipReducerOnUpdate attribute. */
+                    static const std::string skipReducerOnUpdate;
+
+                    /** Connection attribute keyword for sslMode attribute. */
+                    static const std::string sslMode;
+
+                    /** Connection attribute keyword for sslKeyFile attribute. */
+                    static const std::string sslKeyFile;
+
+                    /** Connection attribute keyword for sslCertFile attribute. */
+                    static const std::string sslCertFile;
+
+                    /** Connection attribute keyword for sslCaFile attribute. */
+                    static const std::string sslCaFile;
+                };
+
+                /**
+                 * Constructor.
+                 *
+                 * @param cfg Configuration.
+                 */
+                ConnectionStringParser(Configuration& cfg);
+
+                /**
+                 * Destructor.
+                 */
+                ~ConnectionStringParser();
+
+                /**
+                 * Parse connect string.
+                 *
+                 * @param str String to parse.
+                 * @param len String length.
+                 * @param delimeter Delimeter.
+                 * @param diag Diagnostics collector.
+                 */
+                void ParseConnectionString(const char* str, size_t len, char delimeter,
+                    diagnostic::DiagnosticRecordStorage* diag);
+
+                /**
+                 * Parse connect string.
+                 *
+                 * @param str String to parse.
+                 * @param diag Diagnostics collector.
+                 */
+                void ParseConnectionString(const std::string& str, diagnostic::DiagnosticRecordStorage* diag);
+
+                /**
+                 * Parse config attributes.
+                 *
+                 * @param str String to parse.
+                 * @param diag Diagnostics collector.
+                 */
+                void ParseConfigAttributes(const char* str, diagnostic::DiagnosticRecordStorage* diag);
+
+            private:
+                /**
+                 * Result of parsing string value to bool.
+                 */
+                struct BoolParseResult
+                {
+                    enum Type
+                    {
+                        AI_FALSE,
+
+                        AI_TRUE,
+
+                        AI_UNRECOGNIZED
+                    };
+                };
+
+                /**
+                 * Handle new attribute pair callback.
+                 *
+                 * @param key Key.
+                 * @param value Value.
+                 * @param diag Diagnostics collector.
+                 */
+                void HandleAttributePair(const std::string& key, const std::string& value,
+                    diagnostic::DiagnosticRecordStorage* diag);
+
+                /**
+                 * Convert string to boolean value.
+                 *
+                 * @param value Value to convert to bool.
+                 * @return Result.
+                 */
+                static BoolParseResult::Type StringToBool(const std::string& value);
+
+                /**
+                 * Convert string to boolean value.
+                 *
+                 * @param msg Error message.
+                 * @param key Key.
+                 * @param value Value.
+                 * @return Resulting error message.
+                 */
+                static std::string MakeErrorMessage(const std::string& msg, const std::string& key,
+                    const std::string& value);
+
+                /** Configuration. */
+                Configuration& cfg;
+            };
+        }
+
+    }
+}
+
+#endif //_IGNITE_ODBC_CONFIG_CONNECTION_STRING_PARSER

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc/include/ignite/odbc/config/settable_value.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/config/settable_value.h b/modules/platforms/cpp/odbc/include/ignite/odbc/config/settable_value.h
new file mode 100644
index 0000000..78354d7
--- /dev/null
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/config/settable_value.h
@@ -0,0 +1,101 @@
+/*
+ * 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_CONFIG_SETTABLE_VALUE
+#define _IGNITE_ODBC_CONFIG_SETTABLE_VALUE
+
+namespace ignite
+{
+    namespace odbc
+    {
+        namespace config
+        {
+            /**
+             * Simple abstraction for value, that have default value but can be
+             * set to a different value.
+             *
+             * @tparam T Type of the value.
+             */
+            template<typename T>
+            class SettableValue
+            {
+            public:
+                /** Type of the value. */
+                typedef T ValueType;
+
+                /**
+                 * Constructor.
+                 *
+                 * @param defaultValue Default value to return when is not set.
+                 */
+                SettableValue(const ValueType& defaultValue) :
+                    val(defaultValue),
+                    set(false)
+                {
+                    // No-op.
+                }
+
+                /**
+                 * Destructor.
+                 */
+                ~SettableValue()
+                {
+                    // No-op.
+                }
+                
+                /**
+                 * Set non-default value.
+                 *
+                 * @param value Value.
+                 * @param dflt Set value as default or not.
+                 */
+                void SetValue(const ValueType& value, bool dflt = false)
+                {
+                    val = value;
+                    set = !dflt;
+                }
+
+                /**
+                 * Get value.
+                 *
+                 * @return Value or default value if not set.
+                 */
+                const ValueType& GetValue() const
+                {
+                    return val;
+                }
+
+                /**
+                 * Check whether value is set to non-default.
+                 */
+                bool IsSet() const
+                {
+                    return set;
+                }
+
+            private:
+                /** Current value. */
+                ValueType val;
+
+                /** Flag showing whether value was set to non-default value. */
+                bool set;
+            };
+        }
+    }
+}
+
+#endif //_IGNITE_ODBC_CONFIG_SETTABLE_VALUE
\ No newline at end of file


[2/3] ignite git commit: IGNITE-7811: Implemented connection failover for ODBC

Posted by is...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/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 025b855..0b1181d 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/connection.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/connection.h
@@ -165,6 +165,8 @@ namespace ignite
             template<typename ReqT, typename RspT>
             bool SyncMessage(const ReqT& req, RspT& rsp, int32_t timeout)
             {
+                EnsureConnected();
+
                 std::vector<int8_t> tempBuffer;
 
                 parser.Encode(req, tempBuffer);
@@ -195,6 +197,8 @@ namespace ignite
             template<typename ReqT, typename RspT>
             void SyncMessage(const ReqT& req, RspT& rsp)
             {
+                EnsureConnected();
+
                 std::vector<int8_t> tempBuffer;
 
                 parser.Encode(req, tempBuffer);
@@ -245,6 +249,39 @@ namespace ignite
             IGNITE_NO_COPY_ASSIGNMENT(Connection);
 
             /**
+             * Synchronously send request message and receive response.
+             * Uses provided timeout. Does not try to restore connection on
+             * fail.
+             *
+             * @param req Request message.
+             * @param rsp Response message.
+             * @param timeout Timeout.
+             * @return @c true on success, @c false on timeout.
+             * @throw OdbcError on error.
+             */
+            template<typename ReqT, typename RspT>
+            bool InternalSyncMessage(const ReqT& req, RspT& rsp, int32_t timeout)
+            {
+                std::vector<int8_t> tempBuffer;
+
+                parser.Encode(req, tempBuffer);
+
+                bool success = Send(tempBuffer.data(), tempBuffer.size(), timeout);
+
+                if (!success)
+                    return false;
+
+                success = Receive(tempBuffer, timeout);
+
+                if (!success)
+                    return false;
+
+                parser.Decode(rsp, tempBuffer);
+
+                return true;
+            }
+
+            /**
              * Establish connection to ODBC server.
              * Internal call.
              *
@@ -260,7 +297,7 @@ namespace ignite
              * @param cfg Configuration.
              * @return Operation result.
              */
-            SqlResult::Type InternalEstablish(const config::Configuration cfg);
+            SqlResult::Type InternalEstablish(const config::Configuration& cfg);
 
             /**
              * Release established connection.
@@ -363,6 +400,28 @@ namespace ignite
             SqlResult::Type MakeRequestHandshake();
 
             /**
+             * Ensure there is a connection to the cluster.
+             *
+             * @throw OdbcError on failure.
+             */
+            void EnsureConnected();
+
+            /**
+             * Try to restore connection to the cluster.
+             *
+             * @return @c true on success and @c false otherwise.
+             */
+            bool TryRestoreConnection();
+
+            /**
+             * Collect all addresses from config.
+             *
+             * @param cfg Configuration.
+             * @param endPoints End points.
+             */
+            static void CollectAddresses(const config::Configuration& cfg, std::vector<EndPoint>& endPoints);
+
+            /**
              * Constructor.
              */
             Connection();

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnosable_adapter.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnosable_adapter.h b/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnosable_adapter.h
index 461bfc9..f1e9164 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnosable_adapter.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnosable_adapter.h
@@ -45,6 +45,18 @@ namespace ignite
             {
             public:
                 /**
+                 * Constructor.
+                 *
+                 * @param connection Pointer to connection. Used to create
+                 *     diagnostic records with connection info.
+                 */
+                DiagnosableAdapter(const Connection* connection = 0) :
+                    connection(connection)
+                {
+                    // No-op.
+                }
+
+                /**
                  * Destructor.
                  */
                 virtual ~DiagnosableAdapter()
@@ -99,20 +111,8 @@ namespace ignite
                 virtual void AddStatusRecord(const OdbcError& err);
 
             protected:
-                /**
-                 * Constructor.
-                 *
-                 * @param connection Pointer to connection. Used to create
-                 *                   diagnostic records with connection info.
-                 */
-                DiagnosableAdapter(const Connection* connection = 0) :
-                    connection(connection)
-                {
-                    // No-op.
-                }
-
                 /** Diagnostic records. */
-                diagnostic::DiagnosticRecordStorage diagnosticRecords;
+                DiagnosticRecordStorage diagnosticRecords;
 
             private:
                 /** Connection. */

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnostic_record_storage.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnostic_record_storage.h b/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnostic_record_storage.h
index 9a816da..c93eee7 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnostic_record_storage.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnostic_record_storage.h
@@ -62,11 +62,19 @@ namespace ignite
                 /**
                  * Set header record values.
                  *
-                 * @param retCode Operation return code.
+                 * @param result Operation return code.
                  */
                 void SetHeaderRecord(SqlResult::Type result);
 
                 /**
+                 * Add new status record.
+                 *
+                 * @param sqlState SQL state.
+                 * @param message Message.
+                 */
+                void AddStatusRecord(SqlState::Type  sqlState, const std::string& message);
+
+                /**
                  * Add status record to diagnostic records.
                  *
                  * @param record Status record.
@@ -169,7 +177,8 @@ namespace ignite
                  * @param buffer Buffer to put data to.
                  * @return Operation result.
                  */
-                SqlResult::Type GetField(int32_t recNum, DiagnosticField::Type field, app::ApplicationDataBuffer& buffer) const;
+                SqlResult::Type GetField(int32_t recNum, DiagnosticField::Type field,
+                    app::ApplicationDataBuffer& buffer) const;
 
             private:
                 IGNITE_NO_COPY_ASSIGNMENT(DiagnosticRecordStorage);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc/include/ignite/odbc/end_point.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/end_point.h b/modules/platforms/cpp/odbc/include/ignite/odbc/end_point.h
new file mode 100644
index 0000000..969b02f
--- /dev/null
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/end_point.h
@@ -0,0 +1,72 @@
+/*
+ * 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_END_POINT
+#define _IGNITE_ODBC_END_POINT
+
+#include <stdint.h>
+#include <string>
+
+namespace ignite
+{
+    namespace odbc
+    {
+        /**
+         * Connection end point structure.
+         */
+        struct EndPoint
+        {
+            /**
+             * Default constructor.
+             */
+            EndPoint() :
+                host(),
+                port(),
+                range()
+            {
+                // No-op.
+            }
+
+            /**
+             * Constructor.
+             *
+             * @param host Host.
+             * @param port Port.
+             * @param range Number of ports after the @c port that should be
+             *    tried if the previous are unavailable.
+             */
+            EndPoint(const std::string& host, uint16_t port, uint16_t range = 0) :
+                host(host),
+                port(port),
+                range(range)
+            {
+                // No-op.
+            }
+
+            /** Remote host. */
+            std::string host;
+
+            /** TCP port. */
+            uint16_t port;
+
+            /** Number of ports after the port that should be tried if the previous are unavailable. */
+            uint16_t range;
+        };
+    }
+}
+
+#endif //_IGNITE_ODBC_END_POINT
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_mode.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_mode.h b/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_mode.h
index 20472c3..0f2f2eb 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_mode.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_mode.h
@@ -31,7 +31,7 @@ namespace ignite
             /** SSL Mode enum. */
             struct SslMode
             {
-                enum T
+                enum Type
                 {
                     DISABLE = 0,
 
@@ -42,11 +42,20 @@ namespace ignite
 
                 /**
                  * Convert mode from string. 
+                 *
                  * @param val String value.
                  * @param dflt Default value to return on error.
                  * @return Corresponding enum value.
                  */
-                static T FromString(const std::string& val, T dflt = UNKNOWN);
+                static Type FromString(const std::string& val, Type dflt = UNKNOWN);
+
+                /**
+                 * Convert mode to string. 
+                 *
+                 * @param val Value to convert.
+                 * @return String value.
+                 */
+                static std::string ToString(Type val);
             };
         }
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc/include/ignite/odbc/utility.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/utility.h b/modules/platforms/cpp/odbc/include/ignite/odbc/utility.h
index 7ff5b23..d58479c 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/utility.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/utility.h
@@ -34,6 +34,7 @@
 
 #include "ignite/impl/binary/binary_reader_impl.h"
 #include "ignite/impl/binary/binary_writer_impl.h"
+#include <iterator>
 
 namespace ignite
 {
@@ -98,7 +99,7 @@ namespace ignite
 
             res.reserve(skipped_trailing - skipped_leading);
 
-            std::copy(skipped_leading, skipped_trailing, std::back_insert_iterator<std::string>(res));
+            std::copy(skipped_leading, skipped_trailing, std::back_inserter(res));
 
             return res;
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc/os/win/src/system/ui/dsn_configuration_window.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/os/win/src/system/ui/dsn_configuration_window.cpp b/modules/platforms/cpp/odbc/os/win/src/system/ui/dsn_configuration_window.cpp
index 0e742be..32bf61c 100644
--- a/modules/platforms/cpp/odbc/os/win/src/system/ui/dsn_configuration_window.cpp
+++ b/modules/platforms/cpp/odbc/os/win/src/system/ui/dsn_configuration_window.cpp
@@ -22,6 +22,8 @@
 #include "ignite/odbc/ssl/ssl_mode.h"
 
 #include "ignite/odbc/system/ui/dsn_configuration_window.h"
+#include "ignite/odbc/config/config_tools.h"
+#include "ignite/odbc/diagnostic/diagnosable_adapter.h"
 
 namespace ignite
 {
@@ -124,7 +126,9 @@ namespace ignite
 
                     rowPos += INTERVAL + ROW_HEIGHT;
 
-                    val = config.GetAddress().c_str();
+                    std::string addr = config::AddressesToString(config.GetAddresses());
+
+                    val = addr.c_str();
                     addressLabel = CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT,
                         "Address:", ChildId::ADDRESS_LABEL);
                     addressEdit = CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, val, ChildId::ADDRESS_EDIT);
@@ -183,8 +187,10 @@ namespace ignite
 
                     int rowPos = posY + 2 * INTERVAL;
 
-                    const char* val = config.GetSslMode().c_str();
-                    SslMode::T sslMode = SslMode::FromString(val, SslMode::DISABLE);
+                    SslMode::Type sslMode = config.GetSslMode();
+                    std::string sslModeStr = SslMode::ToString(sslMode);
+
+                    const char* val = sslModeStr.c_str();
 
                     sslModeLabel = CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT, "SSL Mode:", ChildId::SSL_MODE_LABEL);
                     sslModeComboBox = CreateComboBox(editPosX, rowPos, editSizeX, ROW_HEIGHT, "", ChildId::SSL_MODE_COMBO_BOX);
@@ -385,7 +391,7 @@ namespace ignite
                                     std::string sslModeStr;
                                     sslModeComboBox->GetText(sslModeStr);
 
-                                    SslMode::T sslMode = SslMode::FromString(sslModeStr, SslMode::DISABLE);
+                                    SslMode::Type sslMode = SslMode::FromString(sslModeStr, SslMode::DISABLE);
 
                                     sslKeyFileEdit->SetEnabled(sslMode != SslMode::DISABLE);
                                     sslCertFileEdit->SetEnabled(sslMode != SslMode::DISABLE);
@@ -424,57 +430,76 @@ namespace ignite
 
                 void DsnConfigurationWindow::RetrieveConnectionParameters(config::Configuration& cfg) const
                 {
-                    std::string dsn;
-                    std::string address;
-                    std::string schema;
-                    std::string version;
-
-                    nameEdit->GetText(dsn);
-                    addressEdit->GetText(address);
-                    schemaEdit->GetText(schema);
-                    protocolVersionComboBox->GetText(version);
-
-                    common::StripSurroundingWhitespaces(address);
-                    common::StripSurroundingWhitespaces(dsn);
+                    std::string dsnStr;
+                    std::string addressStr;
+                    std::string schemaStr;
+                    std::string versionStr;
+
+                    nameEdit->GetText(dsnStr);
+                    addressEdit->GetText(addressStr);
+                    schemaEdit->GetText(schemaStr);
+                    protocolVersionComboBox->GetText(versionStr);
+
+                    common::StripSurroundingWhitespaces(addressStr);
+                    common::StripSurroundingWhitespaces(dsnStr);
                     // Stripping of whitespaces off the schema skipped intentionally
 
-                    LOG_MSG("Retriving arguments:");
-                    LOG_MSG("DSN:                " << dsn);
-                    LOG_MSG("Address:            " << address);
-                    LOG_MSG("Schema:             " << schema);
-                    LOG_MSG("Protocol version:   " << version);
+                    LOG_MSG("Retrieving arguments:");
+                    LOG_MSG("DSN:                " << dsnStr);
+                    LOG_MSG("Address:            " << addressStr);
+                    LOG_MSG("Schema:             " << schemaStr);
+                    LOG_MSG("Protocol version:   " << versionStr);
 
-                    if (dsn.empty())
+                    if (dsnStr.empty())
                         throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, "DSN name can not be empty.");
 
-                    cfg.SetDsn(dsn);
-                    cfg.SetAddress(address);
-                    cfg.SetSchema(schema);
+                    diagnostic::DiagnosticRecordStorage diag;
+
+                    std::vector<EndPoint> addresses;
+
+                    config::ParseAddress(addressStr, addresses, &diag);
+
+                    if (diag.GetStatusRecordsNumber() > 0)
+                    {
+                        throw IgniteError(IgniteError::IGNITE_ERR_GENERIC,
+                            diag.GetStatusRecord(1).GetMessageText().c_str());
+                    }
+
+                    ProtocolVersion version = ProtocolVersion::FromString(versionStr);
+
+                    if (!version.IsSupported())
+                        throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, "Protocol version is not supported.");
+
+                    cfg.SetDsn(dsnStr);
+                    cfg.SetAddresses(addresses);
+                    cfg.SetSchema(schemaStr);
                     cfg.SetProtocolVersion(version);
                 }
 
                 void DsnConfigurationWindow::RetrieveSslParameters(config::Configuration& cfg) const
                 {
-                    std::string sslMode;
-                    std::string sslKey;
-                    std::string sslCert;
-                    std::string sslCa;
-
-                    sslModeComboBox->GetText(sslMode);
-                    sslKeyFileEdit->GetText(sslKey);
-                    sslCertFileEdit->GetText(sslCert);
-                    sslCaFileEdit->GetText(sslCa);
-
-                    LOG_MSG("Retriving arguments:");
-                    LOG_MSG("SSL Mode:           " << sslMode);
-                    LOG_MSG("SSL Key:            " << sslKey);
-                    LOG_MSG("SSL Certificate:    " << sslCert);
-                    LOG_MSG("SSL CA:             " << sslCa);
+                    std::string sslModeStr;
+                    std::string sslKeyStr;
+                    std::string sslCertStr;
+                    std::string sslCaStr;
+
+                    sslModeComboBox->GetText(sslModeStr);
+                    sslKeyFileEdit->GetText(sslKeyStr);
+                    sslCertFileEdit->GetText(sslCertStr);
+                    sslCaFileEdit->GetText(sslCaStr);
+
+                    LOG_MSG("Retrieving arguments:");
+                    LOG_MSG("SSL Mode:           " << sslModeStr);
+                    LOG_MSG("SSL Key:            " << sslKeyStr);
+                    LOG_MSG("SSL Certificate:    " << sslCertStr);
+                    LOG_MSG("SSL CA:             " << sslCaStr);
+
+                    ssl::SslMode::Type sslMode = ssl::SslMode::FromString(sslModeStr, ssl::SslMode::DISABLE);
 
                     cfg.SetSslMode(sslMode);
-                    cfg.SetSslKeyFile(sslKey);
-                    cfg.SetSslCertFile(sslCert);
-                    cfg.SetSslCaFile(sslCa);
+                    cfg.SetSslKeyFile(sslKeyStr);
+                    cfg.SetSslCertFile(sslCertStr);
+                    cfg.SetSslCaFile(sslCaStr);
                 }
 
                 void DsnConfigurationWindow::RetrieveAdditionalParameters(config::Configuration& cfg) const
@@ -502,14 +527,14 @@ namespace ignite
                     lazy = lazyCheckBox->IsChecked();
                     skipReducerOnUpdate = skipReducerOnUpdateCheckBox->IsChecked();
 
-                    LOG_MSG("Retriving arguments:");
-                    LOG_MSG("Page size:                 " << pageSize);
-                    LOG_MSG("Distributed Joins:         " << (distributedJoins ? "true" : "false"));
-                    LOG_MSG("Enforce Join Order:        " << (enforceJoinOrder ? "true" : "false"));
-                    LOG_MSG("Replicated only:           " << (replicatedOnly ? "true" : "false"));
-                    LOG_MSG("Collocated:                " << (collocated ? "true" : "false"));
-                    LOG_MSG("Lazy:                      " << (lazy ? "true" : "false"));
-                    LOG_MSG("Skip reducer on update:    " << (skipReducerOnUpdate ? "true" : "false"));
+                    LOG_MSG("Retrieving arguments:");
+                    LOG_MSG("Page size:              " << pageSize);
+                    LOG_MSG("Distributed Joins:      " << (distributedJoins ? "true" : "false"));
+                    LOG_MSG("Enforce Join Order:     " << (enforceJoinOrder ? "true" : "false"));
+                    LOG_MSG("Replicated only:        " << (replicatedOnly ? "true" : "false"));
+                    LOG_MSG("Collocated:             " << (collocated ? "true" : "false"));
+                    LOG_MSG("Lazy:                   " << (lazy ? "true" : "false"));
+                    LOG_MSG("Skip reducer on update: " << (skipReducerOnUpdate ? "true" : "false"));
 
                     cfg.SetPageSize(pageSize);
                     cfg.SetDistributedJoins(distributedJoins);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc/os/win/src/system_dsn.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/os/win/src/system_dsn.cpp b/modules/platforms/cpp/odbc/os/win/src/system_dsn.cpp
index 3402aca..733d0cd 100644
--- a/modules/platforms/cpp/odbc/os/win/src/system_dsn.cpp
+++ b/modules/platforms/cpp/odbc/os/win/src/system_dsn.cpp
@@ -22,6 +22,9 @@
 #include "ignite/odbc/dsn_config.h"
 #include "ignite/odbc/system/ui/window.h"
 #include "ignite/odbc/system/ui/dsn_configuration_window.h"
+#include "ignite/odbc/config/connection_string_parser.h"
+#include "ignite/odbc/diagnostic/diagnosable_adapter.h"
+#include "ignite/odbc/odbc_error.h"
 
 using ignite::odbc::config::Configuration;
 
@@ -89,21 +92,18 @@ bool RegisterDsn(const Configuration& config, LPCSTR driver)
         if (!SQLWriteDSNToIni(dsn, driver))
             ignite::odbc::ThrowLastSetupError();
 
-        const ArgMap& map = config.GetMap();
+        ArgMap map;
+        
+        config.ToMap(map);
 
-        std::set<std::string> ignore;
-
-        ignore.insert(Configuration::Key::dsn);
-        ignore.insert(Configuration::Key::driver);
+        map.erase(ConnectionStringParser::Key::dsn);
+        map.erase(ConnectionStringParser::Key::driver);
 
         for (ArgMap::const_iterator it = map.begin(); it != map.end(); ++it)
         {
             const std::string& key = it->first;
             const std::string& value = it->second;
 
-            if (ignore.find(key) != ignore.end())
-                continue;
-
             ignite::odbc::WriteDsnString(dsn, key.c_str(), value.c_str());
         }
 
@@ -154,14 +154,16 @@ BOOL INSTAPI ConfigDSN(HWND hwndParent, WORD req, LPCSTR driver, LPCSTR attribut
 
     LOG_MSG("Attributes: " << attributes);
 
-    config.FillFromConfigAttributes(attributes);
+    config::ConnectionStringParser parser(config);
+
+    diagnostic::DiagnosticRecordStorage diag;
+
+    parser.ParseConfigAttributes(attributes, &diag);
 
     if (!SQLValidDSN(config.GetDsn().c_str()))
         return FALSE;
 
     LOG_MSG("Driver: " << driver);
-    LOG_MSG("Attributes: " << attributes);
-
     LOG_MSG("DSN: " << config.GetDsn());
 
     switch (req)

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc/project/vs/odbc.vcxproj
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/project/vs/odbc.vcxproj b/modules/platforms/cpp/odbc/project/vs/odbc.vcxproj
index 239a30f..4f7c16e 100644
--- a/modules/platforms/cpp/odbc/project/vs/odbc.vcxproj
+++ b/modules/platforms/cpp/odbc/project/vs/odbc.vcxproj
@@ -172,6 +172,8 @@
     <ClCompile Include="..\..\src\column.cpp" />
     <ClCompile Include="..\..\src\common_types.cpp" />
     <ClCompile Include="..\..\src\config\configuration.cpp" />
+    <ClCompile Include="..\..\src\config\config_tools.cpp" />
+    <ClCompile Include="..\..\src\config\connection_string_parser.cpp" />
     <ClCompile Include="..\..\src\config\connection_info.cpp" />
     <ClCompile Include="..\..\src\connection.cpp" />
     <ClCompile Include="..\..\src\cursor.cpp" />
@@ -215,7 +217,10 @@
     <ClInclude Include="..\..\include\ignite\odbc\column.h" />
     <ClInclude Include="..\..\include\ignite\odbc\common_types.h" />
     <ClInclude Include="..\..\include\ignite\odbc\config\configuration.h" />
+    <ClInclude Include="..\..\include\ignite\odbc\config\connection_string_parser.h" />
     <ClInclude Include="..\..\include\ignite\odbc\config\connection_info.h" />
+    <ClInclude Include="..\..\include\ignite\odbc\config\config_tools.h" />
+    <ClInclude Include="..\..\include\ignite\odbc\config\settable_value.h" />
     <ClInclude Include="..\..\include\ignite\odbc\connection.h" />
     <ClInclude Include="..\..\include\ignite\odbc\cursor.h" />
     <ClInclude Include="..\..\include\ignite\odbc\diagnostic\diagnosable.h" />
@@ -223,6 +228,7 @@
     <ClInclude Include="..\..\include\ignite\odbc\diagnostic\diagnostic_record.h" />
     <ClInclude Include="..\..\include\ignite\odbc\diagnostic\diagnostic_record_storage.h" />
     <ClInclude Include="..\..\include\ignite\odbc\dsn_config.h" />
+    <ClInclude Include="..\..\include\ignite\odbc\end_point.h" />
     <ClInclude Include="..\..\include\ignite\odbc\environment.h" />
     <ClInclude Include="..\..\include\ignite\odbc\message.h" />
     <ClInclude Include="..\..\include\ignite\odbc\meta\column_meta.h" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc/project/vs/odbc.vcxproj.filters
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/project/vs/odbc.vcxproj.filters b/modules/platforms/cpp/odbc/project/vs/odbc.vcxproj.filters
index b203b21..b1956aa 100644
--- a/modules/platforms/cpp/odbc/project/vs/odbc.vcxproj.filters
+++ b/modules/platforms/cpp/odbc/project/vs/odbc.vcxproj.filters
@@ -160,6 +160,12 @@
     <ClCompile Include="..\..\src\ssl\ssl_gateway.cpp">
       <Filter>Code\ssl</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\config\connection_string_parser.cpp">
+      <Filter>Code\config</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\config\config_tools.cpp">
+      <Filter>Code\config</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <None Include="module.def">
@@ -311,5 +317,17 @@
     <ClInclude Include="..\..\include\ignite\odbc\ssl\ssl_bindings.h">
       <Filter>Code\ssl</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\ignite\odbc\config\connection_string_parser.h">
+      <Filter>Code\config</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\ignite\odbc\config\settable_value.h">
+      <Filter>Code\config</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\ignite\odbc\config\config_tools.h">
+      <Filter>Code\config</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\ignite\odbc\end_point.h">
+      <Filter>Code</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc/src/config/config_tools.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/config/config_tools.cpp b/modules/platforms/cpp/odbc/src/config/config_tools.cpp
new file mode 100644
index 0000000..f0d956f
--- /dev/null
+++ b/modules/platforms/cpp/odbc/src/config/config_tools.cpp
@@ -0,0 +1,250 @@
+/*
+ * 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 <cctype>
+#include <algorithm>
+
+#include "ignite/odbc/utility.h"
+#include "ignite/odbc/config/config_tools.h"
+#include "ignite/odbc/config/configuration.h"
+
+namespace ignite
+{
+    namespace odbc
+    {
+        namespace config
+        {
+            std::string AddressesToString(const std::vector<EndPoint>& addresses)
+            {
+                std::stringstream stream;
+
+                std::vector<EndPoint>::const_iterator it = addresses.begin();
+
+                if (it != addresses.end())
+                {
+                    stream << it->host << ':' << it->port;
+                    ++it;
+                }
+
+                for (; it != addresses.end(); ++it)
+                {
+                    stream << ',' << it->host << ':' << it->port;
+                }
+
+                return stream.str();
+            }
+
+            void ParseAddress(const std::string& value, std::vector<EndPoint>& endPoints,
+                diagnostic::DiagnosticRecordStorage* diag)
+            {
+                size_t addrNum = std::count(value.begin(), value.end(), ',') + 1;
+
+                endPoints.reserve(endPoints.size() + addrNum);
+
+                std::string parsedAddr(value);
+
+                while (!parsedAddr.empty())
+                {
+                    size_t addrBeginPos = parsedAddr.rfind(',');
+
+                    if (addrBeginPos == std::string::npos)
+                        addrBeginPos = 0;
+                    else
+                        ++addrBeginPos;
+
+                    const char* addrBegin = parsedAddr.data() + addrBeginPos;
+                    const char* addrEnd = parsedAddr.data() + parsedAddr.size();
+
+                    std::string addr = utility::RemoveSurroundingSpaces(addrBegin, addrEnd);
+
+                    if (!addr.empty())
+                    {
+                        EndPoint endPoint;
+
+                        bool success = ParseSingleAddress(addr, endPoint, diag);
+
+                        if (success)
+                            endPoints.push_back(endPoint);
+                    }
+
+                    if (!addrBeginPos)
+                        break;
+
+                    parsedAddr.erase(addrBeginPos - 1);
+                }
+            }
+
+            bool ParseSingleAddress(const std::string& value, EndPoint& endPoint,
+                diagnostic::DiagnosticRecordStorage* diag)
+            {
+                int64_t colonNum = std::count(value.begin(), value.end(), ':');
+
+                if (colonNum == 0)
+                {
+                    endPoint.host = value;
+                    endPoint.port = Configuration::DefaultValue::port;
+
+                    return true;
+                }
+
+                if (colonNum != 1)
+                {
+                    std::stringstream stream;
+
+                    stream << "Unexpected number of ':' characters in the following address: '"
+                        << value << "'. Ignoring address.";
+
+                    if (diag)
+                        diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED, stream.str());
+
+                    return false;
+                }
+
+                size_t colonPos = value.find(':');
+
+                endPoint.host = value.substr(0, colonPos);
+
+                if (colonPos == value.size() - 1)
+                {
+                    std::stringstream stream;
+
+                    stream << "Port is missing in the following address: '" << value << "'. Ignoring address.";
+
+                    if (diag)
+                        diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED, stream.str());
+
+                    return false;
+                }
+
+                std::string portRange = value.substr(colonPos + 1);
+
+                if (!ParsePortRange(portRange, endPoint.port, endPoint.range, diag))
+                    return false;
+
+                return true;
+            }
+
+            bool ParsePortRange(const std::string& value, uint16_t& port, uint16_t& range,
+                diagnostic::DiagnosticRecordStorage* diag)
+            {
+                size_t sepPos = value.find('.');
+
+                if (sepPos == value.npos)
+                {
+                    range = 0;
+                    port = ParsePort(value, diag);
+
+                    if (!port)
+                        return false;
+
+                    return true;
+                }
+
+                if (sepPos + 2 > value.size() || value[sepPos + 1] != '.')
+                {
+                    std::stringstream stream;
+
+                    stream << "Unexpected number of '.' characters in the following address: '"
+                        << value << "'. Ignoring address.";
+
+                    if (diag)
+                        diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED, stream.str());
+
+                    return false;
+                }
+
+                uint16_t rangeBegin = ParsePort(value.substr(0, sepPos), diag);
+
+                if (!rangeBegin)
+                    return false;
+
+                uint16_t rangeEnd = ParsePort(value.substr(sepPos + 2), diag);
+
+                if (!rangeEnd)
+                    return false;
+
+                if (rangeEnd < rangeBegin)
+                {
+                    std::stringstream stream;
+
+                    stream << "Port range end is less than port range begin in the following address: '"
+                        << value << "'. Ignoring address.";
+
+                    if (diag)
+                        diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED, stream.str());
+
+                    return false;
+                }
+
+                port = rangeBegin;
+                range = rangeEnd - rangeBegin;
+
+                return true;
+            }
+
+            uint16_t ParsePort(const std::string& value, diagnostic::DiagnosticRecordStorage* diag)
+            {
+                std::string port = utility::RemoveSurroundingSpaces(value.begin(), value.end());
+
+                if (!common::AllOf(port.begin(), port.end(), &isdigit))
+                {
+                    std::stringstream stream;
+
+                    stream << "Unexpected port characters: '" << port << "'. Ignoring address.";
+
+                    if (diag)
+                        diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED, stream.str());
+
+                    return 0;
+                }
+
+                if (port.size() >= sizeof("65535"))
+                {
+                    std::stringstream stream;
+
+                    stream << "Port value is too large: '" << port << "'. Ignoring address.";
+
+                    if (diag)
+                        diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED, stream.str());
+
+                    return 0;
+                }
+
+                int32_t intPort = 0;
+                std::stringstream conv;
+
+                conv << port;
+                conv >> intPort;
+
+                if (intPort <= 0 || intPort > 0xFFFF)
+                {
+                    std::stringstream stream;
+
+                    stream << "Port value is out of range: '" << port << "'. Ignoring address.";
+
+                    if (diag)
+                        diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED, stream.str());
+
+                    return 0;
+                }
+
+                return static_cast<uint16_t>(intPort);
+            }
+        }
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/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 769e167..8f6bf18 100644
--- a/modules/platforms/cpp/odbc/src/config/configuration.cpp
+++ b/modules/platforms/cpp/odbc/src/config/configuration.cpp
@@ -17,14 +17,12 @@
 
 #include <string>
 #include <sstream>
-#include <algorithm>
 #include <iterator>
 
-#include "ignite/common/common.h"
-#include "ignite/common/utils.h"
-
 #include "ignite/odbc/utility.h"
 #include "ignite/odbc/config/configuration.h"
+#include "ignite/odbc/config/connection_string_parser.h"
+#include "ignite/odbc/config/config_tools.h"
 
 namespace ignite
 {
@@ -32,51 +30,50 @@ namespace ignite
     {
         namespace config
         {
-            const std::string Configuration::Key::dsn                    = "dsn";
-            const std::string Configuration::Key::driver                 = "driver";
-            const std::string Configuration::Key::schema                 = "schema";
-            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::Key::distributedJoins       = "distributed_joins";
-            const std::string Configuration::Key::enforceJoinOrder       = "enforce_join_order";
-            const std::string Configuration::Key::protocolVersion        = "protocol_version";
-            const std::string Configuration::Key::pageSize               = "page_size";
-            const std::string Configuration::Key::replicatedOnly         = "replicated_only";
-            const std::string Configuration::Key::collocated             = "collocated";
-            const std::string Configuration::Key::lazy                   = "lazy";
-            const std::string Configuration::Key::skipReducerOnUpdate    = "skip_reducer_on_update";
-            const std::string Configuration::Key::sslMode                = "ssl_mode";
-            const std::string Configuration::Key::sslKeyFile             = "ssl_key_file";
-            const std::string Configuration::Key::sslCertFile            = "ssl_cert_file";
-            const std::string Configuration::Key::sslCaFile              = "ssl_ca_file";
-
-            const std::string Configuration::DefaultValue::dsn           = "Apache Ignite DSN";
-            const std::string Configuration::DefaultValue::driver        = "Apache Ignite";
-            const std::string Configuration::DefaultValue::schema        = "PUBLIC";
-            const std::string Configuration::DefaultValue::address       = "";
-            const std::string Configuration::DefaultValue::server        = "";
-            const std::string Configuration::DefaultValue::sslMode       = "disable";
-            const std::string Configuration::DefaultValue::sslKeyFile    = "";
-            const std::string Configuration::DefaultValue::sslCertFile   = "";
-            const std::string Configuration::DefaultValue::sslCaFile     = "";
-
-            const uint16_t Configuration::DefaultValue::port    = 10800;
+            const std::string Configuration::DefaultValue::dsn = "Apache Ignite DSN";
+            const std::string Configuration::DefaultValue::driver = "Apache Ignite";
+            const std::string Configuration::DefaultValue::schema = "PUBLIC";
+            const std::string Configuration::DefaultValue::address = "";
+            const std::string Configuration::DefaultValue::server = "";
+
+            const uint16_t Configuration::DefaultValue::port = 10800;
             const int32_t Configuration::DefaultValue::pageSize = 1024;
 
-            const bool Configuration::DefaultValue::distributedJoins      = false;
-            const bool Configuration::DefaultValue::enforceJoinOrder      = false;
-            const bool Configuration::DefaultValue::replicatedOnly        = false;
-            const bool Configuration::DefaultValue::collocated            = false;
-            const bool Configuration::DefaultValue::lazy                  = false;
-            const bool Configuration::DefaultValue::skipReducerOnUpdate   = false;
+            const bool Configuration::DefaultValue::distributedJoins = false;
+            const bool Configuration::DefaultValue::enforceJoinOrder = false;
+            const bool Configuration::DefaultValue::replicatedOnly = false;
+            const bool Configuration::DefaultValue::collocated = false;
+            const bool Configuration::DefaultValue::lazy = false;
+            const bool Configuration::DefaultValue::skipReducerOnUpdate = false;
 
             const ProtocolVersion& Configuration::DefaultValue::protocolVersion = ProtocolVersion::GetCurrent();
 
+            const ssl::SslMode::Type Configuration::DefaultValue::sslMode = ssl::SslMode::DISABLE;
+            const std::string Configuration::DefaultValue::sslKeyFile = "";
+            const std::string Configuration::DefaultValue::sslCertFile = "";
+            const std::string Configuration::DefaultValue::sslCaFile = "";
+
             Configuration::Configuration() :
-                arguments()
+                dsn(DefaultValue::dsn),
+                driver(DefaultValue::driver),
+                schema(DefaultValue::schema),
+                server(DefaultValue::server),
+                port(DefaultValue::port),
+                pageSize(DefaultValue::pageSize),
+                distributedJoins(DefaultValue::distributedJoins),
+                enforceJoinOrder(DefaultValue::enforceJoinOrder),
+                replicatedOnly(DefaultValue::replicatedOnly),
+                collocated(DefaultValue::collocated),
+                lazy(DefaultValue::lazy),
+                skipReducerOnUpdate(DefaultValue::skipReducerOnUpdate),
+                protocolVersion(DefaultValue::protocolVersion),
+                endPoints(std::vector<EndPoint>()),
+                sslMode(DefaultValue::sslMode),
+                sslKeyFile(DefaultValue::sslKeyFile),
+                sslCertFile(DefaultValue::sslCertFile),
+                sslCaFile(DefaultValue::sslCaFile)
             {
-                ParseAddress(DefaultValue::address, endPoint);
+                // No-op.
             }
 
             Configuration::~Configuration()
@@ -84,37 +81,12 @@ namespace ignite
                 // No-op.
             }
 
-            void Configuration::FillFromConnectString(const char* str, size_t len)
+            std::string Configuration::ToConnectString() const
             {
-                // Initializing map.
-                arguments.clear();
+                ArgumentMap arguments;
 
-                // Initializing DSN to empty string.
-                arguments[Key::dsn].clear();
-
-                // Ignoring terminating zero byte if present.
-                // Some Driver Managers pass zero-terminated connection string
-                // while others don't.
-                if (len && !str[len - 1])
-                    --len;
-
-                ParseAttributeList(str, len, ';', arguments);
-
-                ArgumentMap::const_iterator it = arguments.find(Key::address);
-                if (it != arguments.end())
-                {
-                    // Parsing address.
-                    ParseAddress(it->second, endPoint);
-                }
-                else
-                {
-                    endPoint.host = GetStringValue(Key::server, DefaultValue::server);
-                    endPoint.port = static_cast<uint16_t>(GetIntValue(Key::port, DefaultValue::port));
-                }
-            }
+                ToMap(arguments);
 
-            std::string Configuration::ToConnectString() const
-            {
                 std::stringstream connect_string_buffer;
 
                 for (ArgumentMap::const_iterator it = arguments.begin(); it != arguments.end(); ++it)
@@ -134,209 +106,348 @@ namespace ignite
                 return connect_string_buffer.str();
             }
 
-            void Configuration::FillFromConfigAttributes(const char* attributes)
+            uint16_t Configuration::GetTcpPort() const
+            {
+                return port.GetValue();
+            }
+
+            void Configuration::SetTcpPort(uint16_t port)
             {
-                // Initializing map.
-                arguments.clear();
+                this->port.SetValue(port);
+            }
 
-                size_t len = 0;
+            bool Configuration::IsTcpPortSet() const
+            {
+                return port.IsSet();
+            }
 
-                // Getting list length. List is terminated by two '\0'.
-                while (attributes[len] || attributes[len + 1])
-                    ++len;
+            const std::string& Configuration::GetDsn(const std::string& dflt) const
+            {
+                if (!dsn.IsSet())
+                    return dflt;
 
-                ++len;
+                return dsn.GetValue();
+            }
 
-                ParseAttributeList(attributes, len, '\0', arguments);
+            bool Configuration::IsDsnSet() const
+            {
+                return dsn.IsSet();
+            }
 
-                ArgumentMap::const_iterator it = arguments.find(Key::address);
-                if (it != arguments.end())
-                {
-                    // Parsing address.
-                    ParseAddress(it->second, endPoint);
-                }
-                else
-                {
-                    endPoint.host = GetStringValue(Key::server, DefaultValue::server);
-                    endPoint.port = static_cast<uint16_t>(GetIntValue(Key::port, DefaultValue::port));
-                }
+            void Configuration::SetDsn(const std::string& dsn)
+            {
+                this->dsn.SetValue(dsn);
             }
 
-            void Configuration::SetTcpPort(uint16_t port)
+            const std::string& Configuration::GetDriver() const
             {
-                arguments[Key::port] = common::LexicalCast<std::string>(port);
+                return driver.GetValue();
+            }
 
-                ArgumentMap::const_iterator it = arguments.find(Key::address);
+            void Configuration::SetDriver(const std::string& driver)
+            {
+                this->driver.SetValue(driver);
+            }
 
-                if (it == arguments.end())
-                    endPoint.port = port;
+            const std::string& Configuration::GetHost() const
+            {
+                return server.GetValue();
             }
 
             void Configuration::SetHost(const std::string& server)
             {
-                arguments[Key::server] = server;
+                this->server.SetValue(server);
+            }
 
-                ArgumentMap::const_iterator it = arguments.find(Key::address);
+            bool Configuration::IsHostSet() const
+            {
+                return server.IsSet();
+            }
 
-                if (it == arguments.end())
-                    endPoint.host = server;
+            const std::string& Configuration::GetSchema() const
+            {
+                return schema.GetValue();
             }
 
-            void Configuration::SetAddress(const std::string& address)
+            void Configuration::SetSchema(const std::string& schema)
             {
-                arguments[Key::address] = address;
+                this->schema.SetValue(schema);
+            }
 
-                ParseAddress(address, endPoint);
+            bool Configuration::IsSchemaSet() const
+            {
+                return schema.IsSet();
             }
 
-            ProtocolVersion Configuration::GetProtocolVersion() const
+            const std::vector<EndPoint>& Configuration::GetAddresses() const
             {
-                ArgumentMap::const_iterator it = arguments.find(Key::protocolVersion);
+                return endPoints.GetValue();
+            }
 
-                if (it != arguments.end())
-                    return ProtocolVersion::FromString(it->second);
+            void Configuration::SetAddresses(const std::vector<EndPoint>& endPoints)
+            {
+                this->endPoints.SetValue(endPoints);
+            }
 
-                return DefaultValue::protocolVersion;
+            bool Configuration::IsAddressesSet() const
+            {
+                return endPoints.IsSet();
             }
 
-            const std::string& Configuration::GetStringValue(const std::string& key, const std::string& dflt) const
+            ssl::SslMode::Type Configuration::GetSslMode() const
             {
-                ArgumentMap::const_iterator it = arguments.find(common::ToLower(key));
+                return sslMode.GetValue();
+            }
 
-                if (it != arguments.end())
-                    return it->second;
+            void Configuration::SetSslMode(ssl::SslMode::Type sslMode)
+            {
+                this->sslMode.SetValue(sslMode);
+            }
 
-                return dflt;
+            bool Configuration::IsSslModeSet() const
+            {
+                return sslMode.IsSet();
             }
 
-            int64_t Configuration::GetIntValue(const std::string& key, int64_t dflt) const
+            const std::string& Configuration::GetSslKeyFile() const
             {
-                ArgumentMap::const_iterator it = arguments.find(common::ToLower(key));
+                return sslKeyFile.GetValue();
+            }
 
-                if (it != arguments.end())
-                {
-                    const std::string& val = it->second;
+            void Configuration::SetSslKeyFile(const std::string& sslKeyFile)
+            {
+                this->sslKeyFile.SetValue(sslKeyFile);
+            }
 
-                    if (!common::AllOf(val.begin(), val.end(), isdigit))
-                        IGNITE_ERROR_FORMATTED_1(IgniteError::IGNITE_ERR_GENERIC,
-                            "Invalid argument value: Integer value is expected.", "key", key);
+            bool Configuration::IsSslKeyFileSet() const
+            {
+                return sslKeyFile.IsSet();
+            }
 
-                    return common::LexicalCast<int64_t>(val);
-                }
+            const std::string& Configuration::GetSslCertFile() const
+            {
+                return sslCertFile.GetValue();
+            }
 
-                return dflt;
+            void Configuration::SetSslCertFile(const std::string& sslCertFile)
+            {
+                this->sslCertFile.SetValue(sslCertFile);
             }
 
-            bool Configuration::GetBoolValue(const std::string& key, bool dflt) const
+            bool Configuration::IsSslCertFileSet() const
             {
-                ArgumentMap::const_iterator it = arguments.find(common::ToLower(key));
+                return sslCertFile.IsSet();
+            }
 
-                if (it != arguments.end())
-                {
-                    std::string lowercaseVal = common::ToLower(it->second);
+            const std::string& Configuration::GetSslCaFile() const
+            {
+                return sslCaFile.GetValue();
+            }
+
+            void Configuration::SetSslCaFile(const std::string& sslCaFile)
+            {
+                this->sslCaFile.SetValue(sslCaFile);
+            }
 
-                    if (lowercaseVal != "true" && lowercaseVal != "false")
-                        IGNITE_ERROR_FORMATTED_1(IgniteError::IGNITE_ERR_GENERIC,
-                            "Invalid argument value: Boolean value is expected (true or false).", "key", key);
+            bool Configuration::IsSslCaFileSet() const
+            {
+                return sslCaFile.IsSet();
+            }
 
-                    return lowercaseVal == "true";
-                }
+            bool Configuration::IsDistributedJoins() const
+            {
+                return distributedJoins.GetValue();
+            }
 
-                return dflt;
+            void Configuration::SetDistributedJoins(bool val)
+            {
+                this->distributedJoins.SetValue(val);
             }
 
-            void Configuration::SetBoolValue(const std::string& key, bool val)
+            bool Configuration::IsDistributedJoinsSet() const
             {
-                arguments[key] = val ? "true" : "false";
+                return distributedJoins.IsSet();
             }
 
-            void Configuration::ParseAttributeList(const char * str, size_t len, char delimeter, ArgumentMap & args)
+            bool Configuration::IsEnforceJoinOrder() const
             {
-                std::string connect_str(str, len);
+                return enforceJoinOrder.GetValue();
+            }
 
-                while (!connect_str.empty())
-                {
-                    size_t attr_begin = connect_str.rfind(delimeter);
+            void Configuration::SetEnforceJoinOrder(bool val)
+            {
+                this->enforceJoinOrder.SetValue(val);
+            }
 
-                    if (attr_begin == std::string::npos)
-                        attr_begin = 0;
-                    else
-                        ++attr_begin;
+            bool Configuration::IsEnforceJoinOrderSet() const
+            {
+                return enforceJoinOrder.IsSet();
+            }
 
-                    size_t attr_eq_pos = connect_str.rfind('=');
+            bool Configuration::IsReplicatedOnly() const
+            {
+                return replicatedOnly.GetValue();
+            }
 
-                    if (attr_eq_pos == std::string::npos)
-                        attr_eq_pos = 0;
+            void Configuration::SetReplicatedOnly(bool val)
+            {
+                this->replicatedOnly.SetValue(val);
+            }
 
-                    if (attr_begin < attr_eq_pos)
-                    {
-                        const char* key_begin = connect_str.data() + attr_begin;
-                        const char* key_end = connect_str.data() + attr_eq_pos;
+            bool Configuration::IsReplicatedOnlySet() const
+            {
+                return replicatedOnly.IsSet();
+            }
 
-                        const char* value_begin = connect_str.data() + attr_eq_pos + 1;
-                        const char* value_end = connect_str.data() + connect_str.size();
+            bool Configuration::IsCollocated() const
+            {
+                return collocated.GetValue();
+            }
 
-                        std::string key = utility::RemoveSurroundingSpaces(key_begin, key_end);
-                        std::string value = utility::RemoveSurroundingSpaces(value_begin, value_end);
+            void Configuration::SetCollocated(bool val)
+            {
+                this->collocated.SetValue(val);
+            }
 
-                        utility::IntoLower(key);
+            bool Configuration::IsCollocatedSet() const
+            {
+                return collocated.IsSet();
+            }
 
-                        if (value[0] == '{' && value[value.size() - 1] == '}')
-                            value = value.substr(1, value.size() - 2);
+            bool Configuration::IsLazy() const
+            {
+                return lazy.GetValue();
+            }
 
-                        args[key] = value;
-                    }
+            void Configuration::SetLazy(bool val)
+            {
+                this->lazy.SetValue(val);
+            }
 
-                    if (!attr_begin)
-                        break;
+            bool Configuration::IsLazySet() const
+            {
+                return lazy.IsSet();
+            }
 
-                    connect_str.erase(attr_begin - 1);
-                }
+            bool Configuration::IsSkipReducerOnUpdate() const
+            {
+                return skipReducerOnUpdate.GetValue();
             }
 
-            void Configuration::ParseAddress(const std::string& address, EndPoint& res)
+            void Configuration::SetSkipReducerOnUpdate(bool val)
             {
-                int64_t colonNum = std::count(address.begin(), address.end(), ':');
+                this->skipReducerOnUpdate.SetValue(val);
+            }
 
-                if (colonNum == 0)
-                {
-                    res.host = address;
-                    res.port = DefaultValue::port;
-                }
-                else if (colonNum == 1)
-                {
-                    size_t pos = address.find(':');
+            bool Configuration::IsSkipReducerOnUpdateSet() const
+            {
+                return skipReducerOnUpdate.IsSet();
+            }
 
-                    if (pos == address.size() - 1)
-                        throw IgniteError(IgniteError::IGNITE_ERR_GENERIC,
-                            "Invalid address format: no port after colon");
+            ProtocolVersion Configuration::GetProtocolVersion() const
+            {
+                return protocolVersion.GetValue();
+            }
 
-                    res.host = address.substr(0, pos);
+            void Configuration::SetProtocolVersion(const ProtocolVersion& version)
+            {
+                this->protocolVersion.SetValue(version);
+            }
 
-                    std::string port = address.substr(pos + 1);
+            bool Configuration::IsProtocolVersionSet() const
+            {
+                return protocolVersion.IsSet();
+            }
 
-                    if (!common::AllOf(port.begin(), port.end(), isdigit))
-                        throw IgniteError(IgniteError::IGNITE_ERR_GENERIC,
-                            "Invalid address format: port can only contain digits");
+            void Configuration::SetPageSize(int32_t size)
+            {
+                this->pageSize.SetValue(size);
+            }
 
-                    int32_t intPort = common::LexicalCast<int32_t>(port);
+            bool Configuration::IsPageSizeSet() const
+            {
+                return pageSize.IsSet();
+            }
 
-                    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");
-                    }
+            int32_t Configuration::GetPageSize() const
+            {
+                return pageSize.GetValue();
+            }
 
-                    if (intPort == 0)
-                        throw IgniteError(IgniteError::IGNITE_ERR_GENERIC,
-                            "Invalid address format: Port value can not be zero");
+            void Configuration::ToMap(ArgumentMap& res) const
+            {
+                AddToMap(res, ConnectionStringParser::Key::dsn, dsn);
+                AddToMap(res, ConnectionStringParser::Key::driver, driver);
+                AddToMap(res, ConnectionStringParser::Key::schema, schema);
+                AddToMap(res, ConnectionStringParser::Key::address, endPoints);
+                AddToMap(res, ConnectionStringParser::Key::server, server);
+                AddToMap(res, ConnectionStringParser::Key::port, port);
+                AddToMap(res, ConnectionStringParser::Key::distributedJoins, distributedJoins);
+                AddToMap(res, ConnectionStringParser::Key::enforceJoinOrder, enforceJoinOrder);
+                AddToMap(res, ConnectionStringParser::Key::protocolVersion, protocolVersion);
+                AddToMap(res, ConnectionStringParser::Key::pageSize, pageSize);
+                AddToMap(res, ConnectionStringParser::Key::replicatedOnly, replicatedOnly);
+                AddToMap(res, ConnectionStringParser::Key::collocated, collocated);
+                AddToMap(res, ConnectionStringParser::Key::lazy, lazy);
+                AddToMap(res, ConnectionStringParser::Key::skipReducerOnUpdate, skipReducerOnUpdate);
+                AddToMap(res, ConnectionStringParser::Key::sslMode, sslMode);
+                AddToMap(res, ConnectionStringParser::Key::sslKeyFile, sslKeyFile);
+                AddToMap(res, ConnectionStringParser::Key::sslCertFile, sslCertFile);
+                AddToMap(res, ConnectionStringParser::Key::sslCaFile, sslCaFile);
+            }
 
-                    res.port = static_cast<uint16_t>(intPort);
-                }
-                else
-                    throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, 
-                        "Invalid address format: too many colons");
+            template<>
+            void Configuration::AddToMap(ArgumentMap& map, const std::string& key, const SettableValue<uint16_t>& value)
+            {
+                if (value.IsSet())
+                    map[key] = common::LexicalCast<std::string>(value.GetValue());
+            }
+
+            template<>
+            void Configuration::AddToMap(ArgumentMap& map, const std::string& key, const SettableValue<int32_t>& value)
+            {
+                if (value.IsSet())
+                    map[key] = common::LexicalCast<std::string>(value.GetValue());
+            }
+
+            template<>
+            void Configuration::AddToMap(ArgumentMap& map, const std::string& key,
+                const SettableValue<std::string>& value)
+            {
+                if (value.IsSet())
+                    map[key] = value.GetValue();
+            }
+
+            template<>
+            void Configuration::AddToMap(ArgumentMap& map, const std::string& key,
+                const SettableValue<bool>& value)
+            {
+                if (value.IsSet())
+                    map[key] = value.GetValue() ? "true" : "false";
+            }
+
+            template<>
+            void Configuration::AddToMap(ArgumentMap& map, const std::string& key,
+                const SettableValue<ProtocolVersion>& value)
+            {
+                if (value.IsSet())
+                    map[key] = value.GetValue().ToString();
+            }
+
+            template<>
+            void Configuration::AddToMap(ArgumentMap& map, const std::string& key,
+                const SettableValue< std::vector<EndPoint> >& value)
+            {
+                if (value.IsSet())
+                    map[key] = AddressesToString(value.GetValue());
+            }
+
+            template<>
+            void Configuration::AddToMap(ArgumentMap& map, const std::string& key,
+                const SettableValue<ssl::SslMode::Type>& value)
+            {
+                if (value.IsSet())
+                    map[key] = ssl::SslMode::ToString(value.GetValue());
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/6ddc6d70/modules/platforms/cpp/odbc/src/config/connection_string_parser.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/config/connection_string_parser.cpp b/modules/platforms/cpp/odbc/src/config/connection_string_parser.cpp
new file mode 100644
index 0000000..cda23c8
--- /dev/null
+++ b/modules/platforms/cpp/odbc/src/config/connection_string_parser.cpp
@@ -0,0 +1,452 @@
+/*
+ * 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 <vector>
+
+#include "ignite/common/utils.h"
+
+#include "ignite/odbc/utility.h"
+#include "ignite/odbc/odbc_error.h"
+#include "ignite/odbc/ssl/ssl_mode.h"
+#include "ignite/odbc/config/connection_string_parser.h"
+#include "ignite/odbc/config/config_tools.h"
+
+namespace ignite
+{
+    namespace odbc
+    {
+        namespace config
+        {
+            const std::string ConnectionStringParser::Key::dsn                    = "dsn";
+            const std::string ConnectionStringParser::Key::driver                 = "driver";
+            const std::string ConnectionStringParser::Key::schema                 = "schema";
+            const std::string ConnectionStringParser::Key::address                = "address";
+            const std::string ConnectionStringParser::Key::server                 = "server";
+            const std::string ConnectionStringParser::Key::port                   = "port";
+            const std::string ConnectionStringParser::Key::distributedJoins       = "distributed_joins";
+            const std::string ConnectionStringParser::Key::enforceJoinOrder       = "enforce_join_order";
+            const std::string ConnectionStringParser::Key::protocolVersion        = "protocol_version";
+            const std::string ConnectionStringParser::Key::pageSize               = "page_size";
+            const std::string ConnectionStringParser::Key::replicatedOnly         = "replicated_only";
+            const std::string ConnectionStringParser::Key::collocated             = "collocated";
+            const std::string ConnectionStringParser::Key::lazy                   = "lazy";
+            const std::string ConnectionStringParser::Key::skipReducerOnUpdate    = "skip_reducer_on_update";
+            const std::string ConnectionStringParser::Key::sslMode                = "ssl_mode";
+            const std::string ConnectionStringParser::Key::sslKeyFile             = "ssl_key_file";
+            const std::string ConnectionStringParser::Key::sslCertFile            = "ssl_cert_file";
+            const std::string ConnectionStringParser::Key::sslCaFile              = "ssl_ca_file";
+
+            ConnectionStringParser::ConnectionStringParser(Configuration& cfg):
+                cfg(cfg)
+            {
+                // No-op.
+            }
+
+            ConnectionStringParser::~ConnectionStringParser()
+            {
+                // No-op.
+            }
+
+            void ConnectionStringParser::ParseConnectionString(const char* str, size_t len, char delimeter,
+                diagnostic::DiagnosticRecordStorage* diag)
+            {
+                std::string connect_str(str, len);
+
+                while (connect_str.rbegin() != connect_str.rend() && *connect_str.rbegin() == 0)
+                    connect_str.erase(connect_str.size() - 1);
+
+                while (!connect_str.empty())
+                {
+                    size_t attr_begin = connect_str.rfind(delimeter);
+
+                    if (attr_begin == std::string::npos)
+                        attr_begin = 0;
+                    else
+                        ++attr_begin;
+
+                    size_t attr_eq_pos = connect_str.rfind('=');
+
+                    if (attr_eq_pos == std::string::npos)
+                        attr_eq_pos = 0;
+
+                    if (attr_begin < attr_eq_pos)
+                    {
+                        const char* key_begin = connect_str.data() + attr_begin;
+                        const char* key_end = connect_str.data() + attr_eq_pos;
+
+                        const char* value_begin = connect_str.data() + attr_eq_pos + 1;
+                        const char* value_end = connect_str.data() + connect_str.size();
+
+                        std::string key = utility::RemoveSurroundingSpaces(key_begin, key_end);
+                        std::string value = utility::RemoveSurroundingSpaces(value_begin, value_end);
+
+                        if (value[0] == '{' && value[value.size() - 1] == '}')
+                            value = value.substr(1, value.size() - 2);
+
+                        HandleAttributePair(key, value, diag);
+                    }
+
+                    if (!attr_begin)
+                        break;
+
+                    connect_str.erase(attr_begin - 1);
+                }
+            }
+
+            void ConnectionStringParser::ParseConnectionString(const std::string& str,
+                diagnostic::DiagnosticRecordStorage* diag)
+            {
+                ParseConnectionString(str.data(), str.size(), ';', diag);
+            }
+
+            void ConnectionStringParser::ParseConfigAttributes(const char* str,
+                diagnostic::DiagnosticRecordStorage* diag)
+            {
+                size_t len = 0;
+
+                // Getting list length. List is terminated by two '\0'.
+                while (str[len] || str[len + 1])
+                    ++len;
+
+                ++len;
+
+                ParseConnectionString(str, len, '\0', diag);
+            }
+
+            void ConnectionStringParser::HandleAttributePair(const std::string &key, const std::string &value,
+                diagnostic::DiagnosticRecordStorage* diag)
+            {
+                std::string lKey = common::ToLower(key);
+
+                if (lKey == Key::dsn)
+                {
+                    cfg.SetDsn(value);
+                }
+                else if (lKey == Key::schema)
+                {
+                    cfg.SetSchema(value);
+                }
+                else if (lKey == Key::address)
+                {
+                    std::vector<EndPoint> endPoints;
+
+                    ParseAddress(value, endPoints, diag);
+
+                    cfg.SetAddresses(endPoints);
+                }
+                else if (lKey == Key::server)
+                {
+                    cfg.SetHost(value);
+                }
+                else if (lKey == Key::port)
+                {
+                    if (value.empty())
+                    {
+                        if (diag)
+                        {
+                            diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED,
+                                MakeErrorMessage("Port attribute value is empty. Using default value.", key, value));
+                        }
+
+                        return;
+                    }
+
+                    if (!common::AllOf(value.begin(), value.end(), isdigit))
+                    {
+                        if (diag)
+                        {
+                            diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED,
+                                MakeErrorMessage("Port attribute value contains unexpected characters."
+                                    " Using default value.", key, value));
+                        }
+
+                        return;
+                    }
+
+                    if (value.size() >= sizeof("65535"))
+                    {
+                        if (diag)
+                        {
+                            diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED,
+                                MakeErrorMessage("Port attribute value is too large. Using default value.", key, value));
+                        }
+
+                        return;
+                    }
+
+                    int32_t numValue = 0;
+                    std::stringstream conv;
+
+                    conv << value;
+                    conv >> numValue;
+
+                    if (numValue <= 0 || numValue > 0xFFFF)
+                    {
+                        if (diag)
+                        {
+                            diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED,
+                                MakeErrorMessage("Port attribute value is out of range. "
+                                    "Using default value.", key, value));
+                        }
+
+                        return;
+                    }
+
+                    cfg.SetTcpPort(static_cast<uint16_t>(numValue));
+                }
+                else if (lKey == Key::distributedJoins)
+                {
+                    BoolParseResult::Type res = StringToBool(value);
+
+                    if (res == BoolParseResult::AI_UNRECOGNIZED)
+                    {
+                        if (diag)
+                        {
+                            diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED,
+                                MakeErrorMessage("Unrecognized bool value. Using default value.", key, value));
+                        }
+
+                        return;
+                    }
+
+                    cfg.SetDistributedJoins(res == BoolParseResult::AI_TRUE);
+                }
+                else if (lKey == Key::enforceJoinOrder)
+                {
+                    BoolParseResult::Type res = StringToBool(value);
+
+                    if (res == BoolParseResult::AI_UNRECOGNIZED)
+                    {
+                        if (diag)
+                        {
+                            diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED,
+                                MakeErrorMessage("Unrecognized bool value. Using default value.", key, value));
+                        }
+
+                        return;
+                    }
+
+                    cfg.SetEnforceJoinOrder(res == BoolParseResult::AI_TRUE);
+                }
+                else if (lKey == Key::protocolVersion)
+                {
+                    try
+                    {
+                        ProtocolVersion version = ProtocolVersion::FromString(value);
+
+                        if (!version.IsSupported())
+                        {
+                            if (diag)
+                            {
+                                diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED,
+                                    "Specified version is not supported. Default value used.");
+                            }
+
+                            return;
+                        }
+
+                        cfg.SetProtocolVersion(version);
+                    }
+                    catch (IgniteError& err)
+                    {
+                        if (diag)
+                            diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED, err.GetText());
+                    }
+                }
+                else if (lKey == Key::pageSize)
+                {
+                    if (!common::AllOf(value.begin(), value.end(), isdigit))
+                    {
+                        if (diag)
+                        {
+                            diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED,
+                                MakeErrorMessage("Page size attribute value contains unexpected characters."
+                                    " Using default value.", key, value));
+                        }
+
+                        return;
+                    }
+
+                    if (value.size() >= sizeof("4294967295"))
+                    {
+                        if (diag)
+                        {
+                            diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED,
+                                MakeErrorMessage("Page size attribute value is too large."
+                                    " Using default value.", key, value));
+                        }
+
+                        return;
+                    }
+
+                    int64_t numValue = 0;
+                    std::stringstream conv;
+
+                    conv << value;
+                    conv >> numValue;
+
+                    if (numValue <= 0 || numValue > 0xFFFFFFFFLL)
+                    {
+                        if (diag)
+                        {
+                            diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED,
+                                MakeErrorMessage("Page size attribute value is out of range."
+                                    " Using default value.", key, value));
+                        }
+
+                        return;
+                    }
+
+                    cfg.SetPageSize(static_cast<int32_t>(numValue));
+                }
+                else if (lKey == Key::replicatedOnly)
+                {
+                    BoolParseResult::Type res = StringToBool(value);
+
+                    if (res == BoolParseResult::AI_UNRECOGNIZED)
+                    {
+                        if (diag)
+                        {
+                            diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED,
+                                MakeErrorMessage("Unrecognized bool value. Using default value.", key, value));
+                        }
+
+                        return;
+                    }
+
+                    cfg.SetReplicatedOnly(res == BoolParseResult::AI_TRUE);
+                }
+                else if (lKey == Key::collocated)
+                {
+                    BoolParseResult::Type res = StringToBool(value);
+
+                    if (res == BoolParseResult::AI_UNRECOGNIZED)
+                    {
+                        if (diag)
+                        {
+                            diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED,
+                                MakeErrorMessage("Unrecognized bool value. Using default value.", key, value));
+                        }
+
+                        return;
+                    }
+
+                    cfg.SetCollocated(res == BoolParseResult::AI_TRUE);
+                }
+                else if (lKey == Key::lazy)
+                {
+                    BoolParseResult::Type res = StringToBool(value);
+
+                    if (res == BoolParseResult::AI_UNRECOGNIZED)
+                    {
+                        if (diag)
+                        {
+                            diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED,
+                                MakeErrorMessage("Unrecognized bool value. Defaulting to 'false'.", key, value));
+                        }
+
+                        return;
+                    }
+
+                    cfg.SetLazy(res == BoolParseResult::AI_TRUE);
+                }
+                else if (lKey == Key::skipReducerOnUpdate)
+                {
+                    BoolParseResult::Type res = StringToBool(value);
+
+                    if (res == BoolParseResult::AI_UNRECOGNIZED)
+                    {
+                        if (diag)
+                        {
+                            diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED,
+                                MakeErrorMessage("Unrecognized bool value. Defaulting to 'false'.", key, value));
+                        }
+
+                        return;
+                    }
+
+                    cfg.SetSkipReducerOnUpdate(res == BoolParseResult::AI_TRUE);
+                }
+                else if (lKey == Key::sslMode)
+                {
+                    ssl::SslMode::Type mode = ssl::SslMode::FromString(value);
+
+                    if (mode == ssl::SslMode::UNKNOWN)
+                    {
+                        if (diag)
+                        {
+                            diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED,
+                                "Specified SSL mode is not supported. Default value used ('disable').");
+                        }
+
+                        return;
+                    }
+
+                    cfg.SetSslMode(mode);
+                }
+                else if (lKey == Key::sslKeyFile)
+                {
+                    cfg.SetSslKeyFile(value);
+                }
+                else if (lKey == Key::sslCertFile)
+                {
+                    cfg.SetSslCertFile(value);
+                }
+                else if (lKey == Key::sslCaFile)
+                {
+                    cfg.SetSslCaFile(value);
+                }
+                else if (lKey == Key::driver)
+                {
+                    cfg.SetDriver(value);
+                }
+                else if (diag)
+                {
+                    std::stringstream stream;
+
+                    stream << "Unknown attribute: '" << key << "'. Ignoring.";
+
+                    diag->AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED, stream.str());
+                }
+            }
+
+            ConnectionStringParser::BoolParseResult::Type ConnectionStringParser::StringToBool(const std::string& value)
+            {
+                std::string lower = common::ToLower(value);
+
+                if (lower == "true")
+                    return BoolParseResult::AI_TRUE;
+
+                if (lower == "false")
+                    return BoolParseResult::AI_FALSE;
+
+                return BoolParseResult::AI_UNRECOGNIZED;
+            }
+
+            std::string ConnectionStringParser::MakeErrorMessage(const std::string& msg, const std::string& key,
+                const std::string& value)
+            {
+                std::stringstream stream;
+
+                stream << msg << " [key='" << key << "', value='" << value << "']";
+
+                return stream.str();
+            }
+        }
+    }
+}
+