You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2018/10/15 07:47:34 UTC

ignite git commit: IGNITE-9620: MVCC: throw specific SQLSTATE code (40001) in case of write conflict. This closes #4952.

Repository: ignite
Updated Branches:
  refs/heads/master 11716dedc -> 3ebc740f1


IGNITE-9620: MVCC: throw specific SQLSTATE code (40001) in case of write conflict. This closes #4952.


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

Branch: refs/heads/master
Commit: 3ebc740f11464df42f2b8e5e1d7adcda458f7b05
Parents: 11716de
Author: devozerov <vo...@gridgain.com>
Authored: Mon Oct 15 10:47:26 2018 +0300
Committer: devozerov <vo...@gridgain.com>
Committed: Mon Oct 15 10:47:26 2018 +0300

----------------------------------------------------------------------
 .../jdbc/JdbcVersionMismatchSelfTest.java       | 171 +++++++++++++
 .../suite/IgniteJdbcDriverMvccTestSuite.java    |   4 +-
 ...ThinTransactionsAbstractComplexSelfTest.java |   4 +-
 .../internal/jdbc/thin/JdbcThinConnection.java  |   2 +-
 .../processors/cache/GridCacheMapEntry.java     |  21 +-
 .../cache/query/IgniteQueryErrorCode.java       |   6 +
 .../internal/processors/odbc/SqlStateCode.java  |   3 +
 .../processors/query/h2/IgniteH2Indexing.java   |   6 +-
 .../cache/mvcc/CacheMvccSizeTest.java           |   4 +-
 .../cache/mvcc/CacheMvccSqlLockTimeoutTest.java |   2 +-
 .../mvcc/CacheMvccSqlTxQueriesAbstractTest.java |   2 +-
 ...MvccSqlTxQueriesWithReducerAbstractTest.java |   2 +-
 .../cpp/odbc-test/include/odbc_test_suite.h     |  11 +-
 .../cpp/odbc-test/include/test_utils.h          |  59 +++++
 .../cpp/odbc-test/src/odbc_test_suite.cpp       |  28 +++
 .../platforms/cpp/odbc-test/src/test_utils.cpp  |  15 ++
 .../cpp/odbc-test/src/transaction_test.cpp      | 244 +++++++++++++------
 .../cpp/odbc/include/ignite/odbc/common_types.h |  14 +-
 modules/platforms/cpp/odbc/src/common_types.cpp |   8 +-
 .../odbc/src/diagnostic/diagnostic_record.cpp   |  12 +
 .../mvcc/MvccUpdateContentionBenchmark.java     |   4 +-
 21 files changed, 532 insertions(+), 90 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/3ebc740f/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcVersionMismatchSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcVersionMismatchSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcVersionMismatchSelfTest.java
new file mode 100644
index 0000000..19e18a2
--- /dev/null
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcVersionMismatchSelfTest.java
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.jdbc;
+
+import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
+import org.apache.ignite.internal.processors.odbc.SqlStateCode;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * JDBC version mismatch test.
+ */
+public class JdbcVersionMismatchSelfTest extends GridCommonAbstractTest {
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        startGrid();
+
+        try (Connection conn = connect()) {
+            executeUpdate(conn,
+                "CREATE TABLE test (a INT PRIMARY KEY, b INT, c VARCHAR) WITH \"atomicity=TRANSACTIONAL_SNAPSHOT, cache_name=TEST\"");
+
+            executeUpdate(conn, "INSERT INTO test VALUES (1, 1, 'test_1')");
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testVersionMismatchJdbc() throws Exception {
+        try (Connection conn1 = connect(); Connection conn2 = connect()) {
+            conn1.setAutoCommit(false);
+            conn2.setAutoCommit(false);
+
+            // Start first transaction and observe some values.
+            assertEquals(1, executeQuery(conn1, "SELECT * FROM test").size());
+
+            // Change values while first transaction is still in progress.
+            executeUpdate(conn2, "INSERT INTO test VALUES (2, 2, 'test_2')");
+            executeUpdate(conn2, "COMMIT");
+            assertEquals(2, executeQuery(conn2, "SELECT * FROM test").size());
+
+            // Force version mismatch.
+            try {
+                executeUpdate(conn1, "INSERT INTO test VALUES (2, 2, 'test_2')");
+
+                fail();
+            }
+            catch (SQLException e) {
+                assertEquals(SqlStateCode.SERIALIZATION_FAILURE, e.getSQLState());
+                assertEquals(IgniteQueryErrorCode.TRANSACTION_SERIALIZATION_ERROR, e.getErrorCode());
+
+                assertNotNull(e.getMessage());
+                assertTrue(e.getMessage().contains("Cannot serialize transaction due to write conflict"));
+            }
+
+            // Subsequent call should cause exception due to TX being rolled back.
+            try {
+                executeQuery(conn1, "SELECT * FROM test").size();
+
+                fail();
+            }
+            catch (SQLException e) {
+                assertEquals(SqlStateCode.TRANSACTION_STATE_EXCEPTION, e.getSQLState());
+                assertEquals(IgniteQueryErrorCode.TRANSACTION_COMPLETED, e.getErrorCode());
+
+                assertNotNull(e.getMessage());
+                assertTrue(e.getMessage().contains("Transaction is already completed"));
+            }
+
+            // Commit should fail.
+            try {
+                conn1.commit();
+
+                fail();
+            }
+            catch (SQLException e) {
+                // Cannot pass proper error codes for now
+                assertEquals(SqlStateCode.INTERNAL_ERROR, e.getSQLState());
+                assertEquals(IgniteQueryErrorCode.UNKNOWN, e.getErrorCode());
+
+                assertNotNull(e.getMessage());
+                assertTrue(e.getMessage().contains("Failed to finish transaction because it has been rolled back"));
+            }
+
+            // Rollback should work.
+            conn1.rollback();
+
+            // Subsequent calls should work fine.
+            assertEquals(2, executeQuery(conn2, "SELECT * FROM test").size());
+        }
+    }
+
+    /**
+     * Establish JDBC connection.
+     *
+     * @return Connection.
+     * @throws Exception If failed.
+     */
+    private Connection connect() throws Exception {
+        return DriverManager.getConnection("jdbc:ignite:thin://127.0.0.1:10800");
+    }
+
+    /**
+     * Execute update statement.
+     *
+     * @param conn Connection.
+     * @param sql SQL.
+     * @throws Exception If failed.
+     */
+    private static void executeUpdate(Connection conn, String sql) throws Exception {
+        try (Statement stmt = conn.createStatement()) {
+            stmt.executeUpdate(sql);
+        }
+    }
+
+    /**
+     * Execute query.
+     *
+     * @param conn Connection.
+     * @param sql SQL.
+     * @return Result.
+     * @throws Exception If failed.
+     */
+    private static List<List<Object>> executeQuery(Connection conn, String sql) throws Exception {
+        List<List<Object>> rows = new ArrayList<>();
+
+        try (Statement stmt = conn.createStatement()) {
+            try (ResultSet rs = stmt.executeQuery(sql)) {
+                int colCnt = rs.getMetaData().getColumnCount();
+
+                while (rs.next()) {
+                    List<Object> row = new ArrayList<>(colCnt);
+
+                    for (int i = 0; i < colCnt; i++)
+                        row.add(rs.getObject(i + 1));
+
+                    rows.add(row);
+                }
+            }
+        }
+
+        return rows;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/3ebc740f/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverMvccTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverMvccTestSuite.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverMvccTestSuite.java
index 6d8933d..606c32d 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverMvccTestSuite.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverMvccTestSuite.java
@@ -18,12 +18,13 @@
 package org.apache.ignite.jdbc.suite;
 
 import junit.framework.TestSuite;
+import org.apache.ignite.jdbc.JdbcVersionMismatchSelfTest;
 import org.apache.ignite.jdbc.thin.JdbcThinConnectionMvccEnabledSelfTest;
 import org.apache.ignite.jdbc.thin.JdbcThinTransactionsClientAutoCommitComplexSelfTest;
 import org.apache.ignite.jdbc.thin.JdbcThinTransactionsClientNoAutoCommitComplexSelfTest;
-import org.apache.ignite.jdbc.thin.JdbcThinTransactionsWithMvccEnabledSelfTest;
 import org.apache.ignite.jdbc.thin.JdbcThinTransactionsServerAutoCommitComplexSelfTest;
 import org.apache.ignite.jdbc.thin.JdbcThinTransactionsServerNoAutoCommitComplexSelfTest;
+import org.apache.ignite.jdbc.thin.JdbcThinTransactionsWithMvccEnabledSelfTest;
 
 public class IgniteJdbcDriverMvccTestSuite extends TestSuite {
     /**
@@ -34,6 +35,7 @@ public class IgniteJdbcDriverMvccTestSuite extends TestSuite {
         TestSuite suite = new TestSuite("Ignite JDBC Driver Test Suite");
 
         suite.addTest(new TestSuite(JdbcThinConnectionMvccEnabledSelfTest.class));
+        suite.addTest(new TestSuite(JdbcVersionMismatchSelfTest.class));
         
         // Transactions
         suite.addTest(new TestSuite(JdbcThinTransactionsWithMvccEnabledSelfTest.class));

http://git-wip-us.apache.org/repos/asf/ignite/blob/3ebc740f/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinTransactionsAbstractComplexSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinTransactionsAbstractComplexSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinTransactionsAbstractComplexSelfTest.java
index 68ed36b..a175568 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinTransactionsAbstractComplexSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinTransactionsAbstractComplexSelfTest.java
@@ -755,11 +755,11 @@ public abstract class JdbcThinTransactionsAbstractComplexSelfTest extends JdbcTh
 
                     return null;
                 }
-            }, IgniteCheckedException.class, "Mvcc version mismatch.");
+            }, IgniteCheckedException.class, "Cannot serialize transaction due to write conflict");
 
             assertTrue(X.hasCause(ex, SQLException.class));
 
-            assertTrue(X.getCause(ex).getMessage().contains("Mvcc version mismatch."));
+            assertTrue(X.getCause(ex).getMessage().contains("Cannot serialize transaction due to write conflict"));
         }
         else
             readFut.get();

http://git-wip-us.apache.org/repos/asf/ignite/blob/3ebc740f/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinConnection.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinConnection.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinConnection.java
index 323a410..d92948c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinConnection.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinConnection.java
@@ -747,7 +747,7 @@ public class JdbcThinConnection implements Connection {
             JdbcResponse res = cliIo.sendRequest(req);
 
             if (res.status() != ClientListenerResponse.STATUS_SUCCESS)
-                throw new SQLException(res.error(), IgniteQueryErrorCode.codeToSqlState(res.status()));
+                throw new SQLException(res.error(), IgniteQueryErrorCode.codeToSqlState(res.status()), res.status());
 
             return (R)res.response();
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/3ebc740f/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
index 1a04bd2..d417bd4 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
@@ -118,6 +118,7 @@ import static org.apache.ignite.internal.processors.cache.GridCacheUpdateAtomicR
 import static org.apache.ignite.internal.processors.cache.persistence.CacheDataRowAdapter.RowData.NO_KEY;
 import static org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode.CONCURRENT_UPDATE;
 import static org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode.DUPLICATE_KEY;
+import static org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode.TRANSACTION_SERIALIZATION_ERROR;
 import static org.apache.ignite.internal.processors.dr.GridDrType.DR_BACKUP;
 import static org.apache.ignite.internal.processors.dr.GridDrType.DR_NONE;
 import static org.apache.ignite.internal.processors.dr.GridDrType.DR_PRIMARY;
@@ -1111,7 +1112,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
             assert res.resultType() != ResultType.PREV_NOT_NULL || op != CREATE || tx.local();
 
             if (res.resultType() == ResultType.VERSION_MISMATCH)
-                throw new IgniteSQLException("Mvcc version mismatch.", CONCURRENT_UPDATE);
+                throw serializationError();
             else if (res.resultType() == ResultType.FILTERED) {
                 GridCacheUpdateTxResult updRes = new GridCacheUpdateTxResult(invoke);
 
@@ -1261,7 +1262,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
             assert res != null;
 
             if (res.resultType() == ResultType.VERSION_MISMATCH)
-                throw new IgniteSQLException("Mvcc version mismatch.", CONCURRENT_UPDATE);
+                throw serializationError();
             else if (res.resultType() == ResultType.PREV_NULL || res.resultType() == ResultType.FILTERED)
                 return new GridCacheUpdateTxResult(false);
             else if (res.resultType() == ResultType.LOCKED) {
@@ -1358,7 +1359,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
             assert res != null;
 
             if (res.resultType() == ResultType.VERSION_MISMATCH)
-                throw new IgniteSQLException("Mvcc version mismatch.", CONCURRENT_UPDATE);
+                throw serializationError();
             else if (res.resultType() == ResultType.LOCKED) {
                 unlockEntry();
 
@@ -5069,7 +5070,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
                 assert res != null;
 
                 if (res.resultType() == ResultType.VERSION_MISMATCH) {
-                    resFut.onDone(new IgniteSQLException("Mvcc version mismatch.", CONCURRENT_UPDATE));
+                    resFut.onDone(serializationError());
 
                     return;
                 }
@@ -5212,7 +5213,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
                 assert res != null;
 
                 if (res.resultType() == ResultType.VERSION_MISMATCH) {
-                    resFut.onDone(new IgniteSQLException("Mvcc version mismatch.", CONCURRENT_UPDATE));
+                    resFut.onDone(serializationError());
 
                     return;
                 }
@@ -5382,7 +5383,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
                 assert res != null;
 
                 if (res.resultType() == ResultType.VERSION_MISMATCH) {
-                    resFut.onDone(new IgniteSQLException("Mvcc version mismatch.", CONCURRENT_UPDATE));
+                    resFut.onDone(serializationError());
 
                     return;
                 }
@@ -6654,4 +6655,12 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
 
         return new GridCacheUpdateTxResult(true, logPtr);
     }
+
+    /**
+     * @return Common serialization error.
+     */
+    @SuppressWarnings("UnnecessaryReturnStatement")
+    private static IgniteSQLException serializationError() {
+        return new IgniteSQLException("Cannot serialize transaction due to write conflict (transaction is marked for rollback)", TRANSACTION_SERIALIZATION_ERROR);
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/3ebc740f/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java
index 5dab5fd..f1a2355 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java
@@ -120,6 +120,9 @@ public final class IgniteQueryErrorCode {
     /** Transaction is already completed. */
     public final static int TRANSACTION_COMPLETED = 5004;
 
+    /** Transaction serialization error. */
+    public final static int TRANSACTION_SERIALIZATION_ERROR = 5005;
+
     /** */
     private IgniteQueryErrorCode() {
         // No-op.
@@ -179,6 +182,9 @@ public final class IgniteQueryErrorCode {
             case TRANSACTION_COMPLETED:
                 return SqlStateCode.TRANSACTION_STATE_EXCEPTION;
 
+            case TRANSACTION_SERIALIZATION_ERROR:
+                return SqlStateCode.SERIALIZATION_FAILURE;
+
             default:
                 return SqlStateCode.INTERNAL_ERROR;
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/3ebc740f/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlStateCode.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlStateCode.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlStateCode.java
index 68ac200..0b9423f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlStateCode.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlStateCode.java
@@ -64,6 +64,9 @@ public final class SqlStateCode {
     /** Transaction state exception. */
     public final static String TRANSACTION_STATE_EXCEPTION = "25000";
 
+    /** Transaction state exception. */
+    public final static String SERIALIZATION_FAILURE = "40001";
+
     /** Parsing exception. */
     public final static String PARSING_EXCEPTION = "42000";
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/3ebc740f/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java
index c4d5eea..e3fef49 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java
@@ -2021,7 +2021,8 @@ public class IgniteH2Indexing implements GridQueryIndexing {
             return Collections.singletonList(H2Utils.zeroCursor());
         }
         catch (IgniteCheckedException e) {
-            throw new IgniteSQLException("Failed to execute DDL statement [stmt=" + qry.getSql() + ']', e);
+            throw new IgniteSQLException("Failed to execute DDL statement [stmt=" + qry.getSql() +
+                ", err=" + e.getMessage() + ']', e);
         }
     }
 
@@ -2107,7 +2108,8 @@ public class IgniteH2Indexing implements GridQueryIndexing {
     @SuppressWarnings("ThrowFromFinallyBlock")
     private void doCommit(@NotNull GridNearTxLocal tx) throws IgniteCheckedException {
         try {
-            if (!tx.isRollbackOnly())
+            // TODO: Why checking for rollback only?
+            //if (!tx.isRollbackOnly())
                 tx.commit();
         }
         finally {

http://git-wip-us.apache.org/repos/asf/ignite/blob/3ebc740f/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSizeTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSizeTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSizeTest.java
index fe1304a..36a2322 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSizeTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSizeTest.java
@@ -127,7 +127,7 @@ public class CacheMvccSizeTest extends CacheMvccAbstractTest {
                     }
                 }
             },
-            true, 0);
+            false, 0);
 
         checkSizeModificationByOperation("merge into person(id, name) values(1, 'a')", true, 1);
 
@@ -298,7 +298,7 @@ public class CacheMvccSizeTest extends CacheMvccAbstractTest {
         }
         catch (Exception e) {
             if (e.getCause().getCause() instanceof IgniteSQLException)
-                assertTrue(e.getMessage().toLowerCase().contains("version mismatch"));
+                assertTrue(e.getMessage().contains("Failed to finish transaction because it has been rolled back"));
             else {
                 e.printStackTrace();
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/3ebc740f/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlLockTimeoutTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlLockTimeoutTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlLockTimeoutTest.java
index eae79a5..bdd9a76 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlLockTimeoutTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlLockTimeoutTest.java
@@ -343,7 +343,7 @@ public class CacheMvccSqlLockTimeoutTest extends CacheMvccAbstractTest {
             }
             catch (Exception e) {
                 assertTrue(msgContains(e, "Failed to acquire lock within provided timeout for transaction")
-                    || msgContains(e, "Mvcc version mismatch"));
+                    || msgContains(e, "Cannot serialize transaction due to write conflict"));
             }
             finally {
                 ignite.context().cache().context().tm().resetContext();

http://git-wip-us.apache.org/repos/asf/ignite/blob/3ebc740f/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlTxQueriesAbstractTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlTxQueriesAbstractTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlTxQueriesAbstractTest.java
index 7076362..4abcaa1 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlTxQueriesAbstractTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlTxQueriesAbstractTest.java
@@ -1287,7 +1287,7 @@ public abstract class CacheMvccSqlTxQueriesAbstractTest extends CacheMvccAbstrac
         IgniteSQLException ex0 = X.cause(ex.get(), IgniteSQLException.class);
 
         assertNotNull("Exception has not been thrown.", ex0);
-        assertEquals("Mvcc version mismatch.", ex0.getMessage());
+        assertTrue(ex0.getMessage().startsWith("Cannot serialize transaction due to write conflict"));
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/3ebc740f/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlTxQueriesWithReducerAbstractTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlTxQueriesWithReducerAbstractTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlTxQueriesWithReducerAbstractTest.java
index a7cf292..7826e5f 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlTxQueriesWithReducerAbstractTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlTxQueriesWithReducerAbstractTest.java
@@ -680,7 +680,7 @@ public abstract class CacheMvccSqlTxQueriesWithReducerAbstractTest extends Cache
         IgniteSQLException ex0 = X.cause(ex.get(), IgniteSQLException.class);
 
         assertNotNull("Exception has not been thrown.", ex0);
-        assertEquals("Mvcc version mismatch.", ex0.getMessage());
+        assertTrue(ex0.getMessage().startsWith("Cannot serialize transaction due to write conflict"));
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/3ebc740f/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 7a33c6a..2381130 100644
--- a/modules/platforms/cpp/odbc-test/include/odbc_test_suite.h
+++ b/modules/platforms/cpp/odbc-test/include/odbc_test_suite.h
@@ -44,7 +44,16 @@ namespace ignite
             void Prepare();
 
             /**
-             * Establish connection to node.
+             * Establish connection to node using provided handles.
+             *
+             * @param conn Connection.
+             * @param statement Statement to allocate.
+             * @param connectStr Connection string.
+             */
+            void Connect(SQLHDBC& conn, SQLHSTMT& statement, const std::string& connectStr);
+
+            /**
+             * Establish connection to node using default handles.
              *
              * @param connectStr Connection string.
              */

http://git-wip-us.apache.org/repos/asf/ignite/blob/3ebc740f/modules/platforms/cpp/odbc-test/include/test_utils.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/include/test_utils.h b/modules/platforms/cpp/odbc-test/include/test_utils.h
index a1de23e..58a4347 100644
--- a/modules/platforms/cpp/odbc-test/include/test_utils.h
+++ b/modules/platforms/cpp/odbc-test/include/test_utils.h
@@ -29,6 +29,12 @@
 
 #include "ignite/ignition.h"
 
+#define ODBC_THROW_ON_ERROR(ret, type, handle)          \
+    if (!SQL_SUCCEEDED(ret))                            \
+    {                                                   \
+        throw ignite_test::GetOdbcError(type, handle);  \
+    }
+
 #define ODBC_FAIL_ON_ERROR(ret, type, handle)                       \
     if (!SQL_SUCCEEDED(ret))                                        \
     {                                                               \
@@ -43,6 +49,50 @@
         BOOST_FAIL(ignite_test::GetOdbcErrorMessage(type, handle) + ", msg = " + msg); \
     }
 
+/**
+ * Client ODBC erorr.
+ */
+class OdbcClientError : public std::exception
+{
+public:
+    /**
+     * Constructor
+     *
+     * @param sqlstate SQL state.
+     * @param message Error message.
+     */
+    OdbcClientError(const std::string& sqlstate, const std::string& message) :
+        sqlstate(sqlstate),
+        message(message)
+    {
+        // No-op.
+    }
+
+    /**
+     * Destructor.
+     */
+    virtual ~OdbcClientError() IGNITE_NO_THROW
+    {
+         // No-op.
+    }
+
+    /**
+     * Implementation of the standard std::exception::what() method.
+     * Synonym for GetText() method.
+     *
+     * @return Error message string.
+     */
+    virtual const char* what() const IGNITE_NO_THROW
+    {
+        return message.c_str();
+    }
+
+    /** SQL state. */
+    std::string sqlstate;
+
+    /** Error message. */
+    std::string message;
+};
 
 namespace ignite_test
 {
@@ -50,6 +100,15 @@ namespace ignite_test
     enum { ODBC_BUFFER_SIZE = 1024 };
 
     /**
+     * Extract error.
+     *
+     * @param handleType Type of the handle.
+     * @param handle Handle.
+     * @return Error.
+     */
+    OdbcClientError GetOdbcError(SQLSMALLINT handleType, SQLHANDLE handle);
+
+    /**
      * Extract error state.
      *
      * @param handleType Type of the handle.

http://git-wip-us.apache.org/repos/asf/ignite/blob/3ebc740f/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 4f5be91..b79d13a 100644
--- a/modules/platforms/cpp/odbc-test/src/odbc_test_suite.cpp
+++ b/modules/platforms/cpp/odbc-test/src/odbc_test_suite.cpp
@@ -56,6 +56,34 @@ namespace ignite
             BOOST_REQUIRE(dbc != NULL);
         }
 
+        void OdbcTestSuite::Connect(SQLHDBC& conn, SQLHSTMT& statement, const std::string& connectStr)
+        {
+            // Allocate a connection handle
+            SQLAllocHandle(SQL_HANDLE_DBC, env, &conn);
+
+            BOOST_REQUIRE(conn != NULL);
+
+            // Connect string
+            std::vector<SQLCHAR> connectStr0(connectStr.begin(), connectStr.end());
+
+            SQLCHAR outstr[ODBC_BUFFER_SIZE];
+            SQLSMALLINT outstrlen;
+
+            // Connecting to ODBC server.
+            SQLRETURN ret = SQLDriverConnect(conn, NULL, &connectStr0[0], static_cast<SQLSMALLINT>(connectStr0.size()),
+                outstr, sizeof(outstr), &outstrlen, SQL_DRIVER_COMPLETE);
+
+            if (!SQL_SUCCEEDED(ret))
+            {
+                BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_DBC, conn));
+            }
+
+            // Allocate a statement handle
+            SQLAllocHandle(SQL_HANDLE_STMT, conn, &statement);
+
+            BOOST_REQUIRE(statement != NULL);
+        }
+
         void OdbcTestSuite::Connect(const std::string& connectStr)
         {
             Prepare();

http://git-wip-us.apache.org/repos/asf/ignite/blob/3ebc740f/modules/platforms/cpp/odbc-test/src/test_utils.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/test_utils.cpp b/modules/platforms/cpp/odbc-test/src/test_utils.cpp
index fc8cbd3..68bd787 100644
--- a/modules/platforms/cpp/odbc-test/src/test_utils.cpp
+++ b/modules/platforms/cpp/odbc-test/src/test_utils.cpp
@@ -23,6 +23,21 @@
 
 namespace ignite_test
 {
+    OdbcClientError GetOdbcError(SQLSMALLINT handleType, SQLHANDLE handle)
+    {
+        SQLCHAR sqlstate[7] = {};
+        SQLINTEGER nativeCode;
+
+        SQLCHAR message[ODBC_BUFFER_SIZE];
+        SQLSMALLINT reallen = 0;
+
+        SQLGetDiagRec(handleType, handle, 1, sqlstate, &nativeCode, message, ODBC_BUFFER_SIZE, &reallen);
+
+        return OdbcClientError(
+            std::string(reinterpret_cast<char*>(sqlstate)),
+            std::string(reinterpret_cast<char*>(message), reallen));
+    }
+
     std::string GetOdbcErrorState(SQLSMALLINT handleType, SQLHANDLE handle)
     {
         SQLCHAR sqlstate[7] = {};

http://git-wip-us.apache.org/repos/asf/ignite/blob/3ebc740f/modules/platforms/cpp/odbc-test/src/transaction_test.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/transaction_test.cpp b/modules/platforms/cpp/odbc-test/src/transaction_test.cpp
index 73e54b8..ed1b054 100644
--- a/modules/platforms/cpp/odbc-test/src/transaction_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/transaction_test.cpp
@@ -75,51 +75,56 @@ struct TransactionTestSuiteFixture : public odbc::OdbcTestSuite
      */
     void InsertTestValue(int64_t key, const std::string& value)
     {
-        SQLCHAR insertReq[] = "INSERT INTO TestType(_key, strField) VALUES(?, ?)";
+        InsertTestValue(stmt, key, value);
+    }
 
-        SQLRETURN ret;
+    /**
+     * Insert test string value in cache and make all the neccessary checks.
+     *
+     * @param stmt Statement.
+     * @param key Key.
+     * @param value Value.
+     */
+    static void InsertTestValue(SQLHSTMT stmt, int64_t key, const std::string& value)
+    {
+        SQLCHAR insertReq[] = "INSERT INTO TestType(_key, strField) VALUES(?, ?)";
 
-        ret = SQLPrepare(stmt, insertReq, SQL_NTS);
+        SQLRETURN ret = SQLPrepare(stmt, insertReq, SQL_NTS);
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         char strField[1024] = { 0 };
         SQLLEN strFieldLen = 0;
 
         ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_BIGINT, 0, 0, &key, 0, 0);
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         ret = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, sizeof(strField),
             sizeof(strField), &strField, sizeof(strField), &strFieldLen);
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         strncpy(strField, value.c_str(), sizeof(strField));
         strFieldLen = SQL_NTS;
 
         ret = SQLExecute(stmt);
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         SQLLEN affected = 0;
         ret = SQLRowCount(stmt, &affected);
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         BOOST_CHECK_EQUAL(affected, 1);
 
         ret = SQLMoreResults(stmt);
 
         if (ret != SQL_NO_DATA)
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+            ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
-        ResetStatement();
+        ResetStatement(stmt);
     }
 
     /**
@@ -130,14 +135,23 @@ struct TransactionTestSuiteFixture : public odbc::OdbcTestSuite
      */
     void UpdateTestValue(int64_t key, const std::string& value)
     {
-        SQLCHAR insertReq[] = "UPDATE TestType SET strField=? WHERE _key=?";
+        UpdateTestValue(stmt, key, value);
+    }
 
-        SQLRETURN ret;
+    /**
+     * Update test string value in cache and make all the neccessary checks.
+     *
+     * @param stmt Statement.
+     * @param key Key.
+     * @param value Value.
+     */
+    static void UpdateTestValue(SQLHSTMT stmt, int64_t key, const std::string& value)
+    {
+        SQLCHAR insertReq[] = "UPDATE TestType SET strField=? WHERE _key=?";
 
-        ret = SQLPrepare(stmt, insertReq, SQL_NTS);
+        SQLRETURN ret = SQLPrepare(stmt, insertReq, SQL_NTS);
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         char strField[1024] = { 0 };
         SQLLEN strFieldLen = 0;
@@ -145,36 +159,32 @@ struct TransactionTestSuiteFixture : public odbc::OdbcTestSuite
         ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, sizeof(strField),
             sizeof(strField), &strField, sizeof(strField), &strFieldLen);
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         ret = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_BIGINT, 0, 0, &key, 0, 0);
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         strncpy(strField, value.c_str(), sizeof(strField));
         strFieldLen = SQL_NTS;
 
         ret = SQLExecute(stmt);
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         SQLLEN affected = 0;
         ret = SQLRowCount(stmt, &affected);
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         BOOST_CHECK_EQUAL(affected, 1);
 
         ret = SQLMoreResults(stmt);
 
         if (ret != SQL_NO_DATA)
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+            ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
-        ResetStatement();
+        ResetStatement(stmt);
     }
 
     /**
@@ -184,41 +194,45 @@ struct TransactionTestSuiteFixture : public odbc::OdbcTestSuite
      */
     void DeleteTestValue(int64_t key)
     {
-        SQLCHAR insertReq[] = "DELETE FROM TestType WHERE _key=?";
+        DeleteTestValue(stmt, key);
+    }
 
-        SQLRETURN ret;
+    /**
+     * Delete test string value.
+     *
+     * @param stmt Statement.
+     * @param key Key.
+     */
+    static void DeleteTestValue(SQLHSTMT stmt, int64_t key)
+    {
+        SQLCHAR insertReq[] = "DELETE FROM TestType WHERE _key=?";
 
-        ret = SQLPrepare(stmt, insertReq, SQL_NTS);
+        SQLRETURN ret = SQLPrepare(stmt, insertReq, SQL_NTS);
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_BIGINT, 0, 0, &key, 0, 0);
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         ret = SQLExecute(stmt);
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         SQLLEN affected = 0;
         ret = SQLRowCount(stmt, &affected);
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         BOOST_CHECK_EQUAL(affected, 1);
 
         ret = SQLMoreResults(stmt);
 
         if (ret != SQL_NO_DATA)
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+            ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
-        ResetStatement();
+        ResetStatement(stmt);
     }
-
     /**
      * Selects and checks the value.
      *
@@ -227,6 +241,18 @@ struct TransactionTestSuiteFixture : public odbc::OdbcTestSuite
      */
     void CheckTestValue(int64_t key, const std::string& expect)
     {
+        CheckTestValue(stmt, key, expect);
+    }
+
+    /**
+     * Selects and checks the value.
+     *
+     * @param stmt Statement.
+     * @param key Key.
+     * @param expect Expected value.
+     */
+    static void CheckTestValue(SQLHSTMT stmt, int64_t key, const std::string& expect)
+    {
         // Just selecting everything to make sure everything is OK
         SQLCHAR selectReq[] = "SELECT strField FROM TestType WHERE _key = ?";
 
@@ -235,23 +261,19 @@ struct TransactionTestSuiteFixture : public odbc::OdbcTestSuite
 
         SQLRETURN ret = SQLBindCol(stmt, 1, SQL_C_CHAR, &strField, sizeof(strField), &strFieldLen);
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_BIGINT, 0, 0, &key, 0, 0);
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         ret = SQLExecDirect(stmt, selectReq, sizeof(selectReq));
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         ret = SQLFetch(stmt);
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         BOOST_CHECK_EQUAL(std::string(strField, strFieldLen), expect);
 
@@ -262,9 +284,9 @@ struct TransactionTestSuiteFixture : public odbc::OdbcTestSuite
         ret = SQLMoreResults(stmt);
 
         if (ret != SQL_NO_DATA)
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+            ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
-        ResetStatement();
+        ResetStatement(stmt);
     }
 
     /**
@@ -274,6 +296,17 @@ struct TransactionTestSuiteFixture : public odbc::OdbcTestSuite
      */
     void CheckNoTestValue(int64_t key)
     {
+        CheckNoTestValue(stmt, key);
+    }
+
+    /**
+     * Selects and checks that value is absent.
+     *
+     * @param stmt Statement.
+     * @param key Key.
+     */
+    static void CheckNoTestValue(SQLHSTMT stmt, int64_t key)
+    {
         // Just selecting everything to make sure everything is OK
         SQLCHAR selectReq[] = "SELECT strField FROM TestType WHERE _key = ?";
 
@@ -282,32 +315,31 @@ struct TransactionTestSuiteFixture : public odbc::OdbcTestSuite
 
         SQLRETURN ret = SQLBindCol(stmt, 1, SQL_C_CHAR, &strField, sizeof(strField), &strFieldLen);
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_BIGINT, 0, 0, &key, 0, 0);
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         ret = SQLExecDirect(stmt, selectReq, sizeof(selectReq));
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         ret = SQLFetch(stmt);
 
         BOOST_CHECK_EQUAL(ret, SQL_NO_DATA);
 
-        if (ret != SQL_NO_DATA && !SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        if (ret != SQL_NO_DATA)
+            ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         ret = SQLMoreResults(stmt);
 
+        BOOST_CHECK_EQUAL(ret, SQL_NO_DATA);
+
         if (ret != SQL_NO_DATA)
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+            ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
-        ResetStatement();
+        ResetStatement(stmt);
     }
 
     /**
@@ -315,15 +347,23 @@ struct TransactionTestSuiteFixture : public odbc::OdbcTestSuite
      */
     void ResetStatement()
     {
+        ResetStatement(stmt);
+    }
+
+    /**
+     * Reset statement state.
+     *
+     * @param stmt Statement.
+     */
+    static void ResetStatement(SQLHSTMT stmt)
+    {
         SQLRETURN ret = SQLFreeStmt(stmt, SQL_RESET_PARAMS);
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
 
         ret = SQLFreeStmt(stmt, SQL_UNBIND);
 
-        if (!SQL_SUCCEEDED(ret))
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+        ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
     }
 
     /** Node started during the test. */
@@ -738,4 +778,72 @@ BOOST_AUTO_TEST_CASE(TransactionEnvironmentTxModeCommit)
     CheckTestValue(42, "Some");
 }
 
+BOOST_AUTO_TEST_CASE(TransactionVersionMismatchError)
+{
+    Connect("DRIVER={Apache Ignite};address=127.0.0.1:11110;schema=cache");
+
+    InsertTestValue(1, "test_1");
+
+    SQLRETURN ret = SQLSetConnectAttr(dbc, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, 0);
+
+    ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_DBC, dbc);
+
+    CheckTestValue(1, "test_1");
+
+    SQLHDBC dbc2;
+    SQLHSTMT stmt2;
+
+    Connect(dbc2, stmt2, "DRIVER={Apache Ignite};address=127.0.0.1:11110;schema=cache");
+
+    ret = SQLSetConnectAttr(dbc2, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, 0);
+
+    ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_DBC, dbc2);
+
+    InsertTestValue(stmt2, 2, "test_2");
+
+    ret = SQLEndTran(SQL_HANDLE_DBC, dbc2, SQL_COMMIT);
+
+    ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_DBC, dbc2);
+
+    CheckTestValue(stmt2, 1, "test_1");
+    CheckTestValue(stmt2, 2, "test_2");
+
+    try
+    {
+        InsertTestValue(2, "test_2");
+
+        BOOST_FAIL("Exception is expected");
+    }
+    catch (OdbcClientError& err)
+    {
+        BOOST_CHECK(err.message.find("Cannot serialize transaction due to write conflict") != err.message.npos);
+        BOOST_CHECK_EQUAL(err.sqlstate, "40001");
+
+        ResetStatement(stmt);
+    }
+
+    try
+    {
+        CheckTestValue(1, "test_1");
+
+        BOOST_FAIL("Exception is expected");
+    }
+    catch (OdbcClientError& err)
+    {
+        BOOST_CHECK(err.message.find("Transaction is already completed") != err.message.npos);
+        BOOST_CHECK_EQUAL(err.sqlstate, "25000");
+
+        ResetStatement(stmt);
+    }
+
+    ret = SQLEndTran(SQL_HANDLE_DBC, dbc, SQL_ROLLBACK);
+    ODBC_THROW_ON_ERROR(ret, SQL_HANDLE_DBC, dbc);
+
+    SQLFreeHandle(SQL_HANDLE_STMT, stmt2);
+
+    SQLDisconnect(dbc2);
+
+    SQLFreeHandle(SQL_HANDLE_DBC, dbc2);
+}
+
 BOOST_AUTO_TEST_SUITE_END()

http://git-wip-us.apache.org/repos/asf/ignite/blob/3ebc740f/modules/platforms/cpp/odbc/include/ignite/odbc/common_types.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/common_types.h b/modules/platforms/cpp/odbc/include/ignite/odbc/common_types.h
index 29bb022..9241bbc 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/common_types.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/common_types.h
@@ -95,9 +95,15 @@ namespace ignite
                 /** Invalid cursor state. */
                 S24000_INVALID_CURSOR_STATE,
 
+                /** Invalid transaction state. */
+                S25000_INVALID_TRANSACTION_STATE,
+
                 /** Invalid schema name. */
                 S3F000_INVALID_SCHEMA_NAME,
 
+                /** Serialization failure. */
+                S40001_SERIALIZATION_FAILURE,
+
                 /** Syntax error or access violation. */
                 S42000_SYNTAX_ERROR_OR_ACCESS_VIOLATION,
 
@@ -371,7 +377,13 @@ namespace ignite
                 ENTRY_PROCESSING = 4005,
 
                 /** Cache not found. */
-                CACHE_NOT_FOUND = 4006
+                CACHE_NOT_FOUND = 4006,
+
+                /** Transaction is already completed. */
+                TRANSACTION_COMPLETED = 5004,
+
+                /** Transaction serialization error. */
+                TRANSACTION_SERIALIZATION_ERROR = 5005
             };
         };
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/3ebc740f/modules/platforms/cpp/odbc/src/common_types.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/common_types.cpp b/modules/platforms/cpp/odbc/src/common_types.cpp
index 10c4f77..72b3cc6 100644
--- a/modules/platforms/cpp/odbc/src/common_types.cpp
+++ b/modules/platforms/cpp/odbc/src/common_types.cpp
@@ -28,7 +28,7 @@ namespace ignite
         {
             switch (result)
             {
-                case SqlResult::AI_SUCCESS: 
+                case SqlResult::AI_SUCCESS:
                     return SQL_SUCCESS;
 
                 case SqlResult::AI_SUCCESS_WITH_INFO:
@@ -157,6 +157,12 @@ namespace ignite
                 case ResponseStatus::COLUMN_ALREADY_EXISTS:
                     return SqlState::S42S21_COLUMN_ALREADY_EXISTS;
 
+                case ResponseStatus::TRANSACTION_COMPLETED:
+                    return SqlState::S25000_INVALID_TRANSACTION_STATE;
+
+                case ResponseStatus::TRANSACTION_SERIALIZATION_ERROR:
+                    return SqlState::S40001_SERIALIZATION_FAILURE;
+
                 case ResponseStatus::CACHE_NOT_FOUND:
                 case ResponseStatus::NULL_TABLE_DESCRIPTOR:
                 case ResponseStatus::CONVERSION_FAILED:

http://git-wip-us.apache.org/repos/asf/ignite/blob/3ebc740f/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record.cpp b/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record.cpp
index 7b82b40..d3a3692 100644
--- a/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record.cpp
+++ b/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record.cpp
@@ -79,9 +79,15 @@ namespace
     /** SQL state 24000 constant. */
     const std::string STATE_24000 = "24000";
 
+    /** SQL state 25000 constant. */
+    const std::string STATE_25000 = "25000";
+
     /** SQL state 3F000 constant. */
     const std::string STATE_3F000 = "3F000";
 
+    /** SQL state 40001 constant. */
+    const std::string STATE_40001 = "40001";
+
     /** SQL state 42000 constant. */
     const std::string STATE_42000 = "42000";
 
@@ -305,9 +311,15 @@ namespace ignite
                     case SqlState::S24000_INVALID_CURSOR_STATE:
                         return STATE_24000;
 
+                    case SqlState::S25000_INVALID_TRANSACTION_STATE:
+                        return STATE_25000;
+
                     case SqlState::S3F000_INVALID_SCHEMA_NAME:
                         return STATE_3F000;
 
+                    case SqlState::S40001_SERIALIZATION_FAILURE:
+                        return STATE_40001;
+
                     case SqlState::S42000_SYNTAX_ERROR_OR_ACCESS_VIOLATION:
                         return STATE_42000;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/3ebc740f/modules/yardstick/src/main/java/org/apache/ignite/yardstick/jdbc/mvcc/MvccUpdateContentionBenchmark.java
----------------------------------------------------------------------
diff --git a/modules/yardstick/src/main/java/org/apache/ignite/yardstick/jdbc/mvcc/MvccUpdateContentionBenchmark.java b/modules/yardstick/src/main/java/org/apache/ignite/yardstick/jdbc/mvcc/MvccUpdateContentionBenchmark.java
index 77c8c50..91128c0 100644
--- a/modules/yardstick/src/main/java/org/apache/ignite/yardstick/jdbc/mvcc/MvccUpdateContentionBenchmark.java
+++ b/modules/yardstick/src/main/java/org/apache/ignite/yardstick/jdbc/mvcc/MvccUpdateContentionBenchmark.java
@@ -32,7 +32,7 @@ import static org.yardstickframework.BenchmarkUtils.println;
  */
 public class MvccUpdateContentionBenchmark extends AbstractDistributedMvccBenchmark {
     /** Expected expception message in mvcc on mode on update fail. */
-    private static final String MVCC_EXC_MSG = "Mvcc version mismatch.";
+    private static final String MVCC_EXC_MSG = "Cannot serialize transaction due to write conflict";
 
     /** Expected exception message in mvcc off mode on update fail. */
     private static final String NO_MVCC_EXC_MSG_PREFIX =
@@ -53,7 +53,7 @@ public class MvccUpdateContentionBenchmark extends AbstractDistributedMvccBenchm
             execute(new SqlFieldsQuery(UPDATE_QRY).setArgs(start, end));
         }
         catch (IgniteSQLException exc) {
-            if ((args.atomicMode() == CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT && !exc.getMessage().equals(MVCC_EXC_MSG)) ||
+            if ((args.atomicMode() == CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT && !exc.getMessage().startsWith(MVCC_EXC_MSG)) ||
                 (args.atomicMode() != CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT && !exc.getMessage().startsWith(NO_MVCC_EXC_MSG_PREFIX)))
                 throw new RuntimeException("Exception with unexpected message is thrown.", exc);