diff --git a/mysql-test/r/ndb_insert.result b/mysql-test/r/ndb_insert.result
index 11d322a06dea92a0711cfae09e080f17337050a4..1da958ef0f727fe34b48b6f44672e5f0f8d4445c 100644
--- a/mysql-test/r/ndb_insert.result
+++ b/mysql-test/r/ndb_insert.result
@@ -577,6 +577,25 @@ pk1	b	c
 2	2	17
 4	4	3
 6	6	3
+DELETE FROM t1;
+CREATE UNIQUE INDEX bi ON t1(b);
+INSERT INTO t1 VALUES 
+(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
+(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
+INSERT INTO t1 VALUES(0,1,0),(21,21,21) ON DUPLICATE KEY UPDATE pk1=b+10,b=b+10;
+select * from t1 order by pk1;
+pk1	b	c
+2	2	2
+3	3	3
+4	4	4
+5	5	5
+6	6	6
+7	7	7
+8	8	8
+9	9	9
+10	10	10
+11	11	1
+21	21	21
 DROP TABLE t1;
 CREATE TABLE t1(a INT) ENGINE=ndb;
 INSERT IGNORE INTO t1 VALUES (1);
@@ -586,7 +605,7 @@ INSERT IGNORE INTO t1 SELECT a FROM t1;
 INSERT IGNORE INTO t1 SELECT a FROM t1;
 INSERT IGNORE INTO t1 VALUES (1);
 INSERT IGNORE INTO t1 VALUES (1);
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
 a
 1
 1
@@ -606,4 +625,11 @@ a
 1
 1
 1
+DELETE FROM t1;
+CREATE UNIQUE INDEX ai ON t1(a);
+INSERT IGNORE INTO t1 VALUES (1);
+INSERT IGNORE INTO t1 VALUES (1);
+SELECT * FROM t1 ORDER BY a;
+a
+1
 DROP TABLE t1;
diff --git a/mysql-test/r/ndb_replace.result b/mysql-test/r/ndb_replace.result
index 6aa1a387661271362f3d37959e848d1bc83c9836..5e49968ca64145d1a3677bf00b1e0f1714bc7cc8 100644
--- a/mysql-test/r/ndb_replace.result
+++ b/mysql-test/r/ndb_replace.result
@@ -19,3 +19,15 @@ gesuchnr	benutzer_id
 2	1
 3	2
 drop table t1;
+CREATE TABLE t1(i INT PRIMARY KEY AUTO_INCREMENT, 
+j INT, 
+k INT, 
+UNIQUE INDEX(j)
+) ENGINE = ndb;
+INSERT  INTO t1 VALUES (1,1,23),(2,2,24);
+REPLACE INTO t1 (j,k) VALUES (1,42);
+REPLACE INTO t1 (i,j) VALUES (17,2);
+SELECT * from t1 ORDER BY i;
+i	j	k
+3	1	42
+17	2	24
diff --git a/mysql-test/t/ndb_insert.test b/mysql-test/t/ndb_insert.test
index 92bc51bcf4f8fb4e47c1ba52d796e1f39797ebc1..4fe847058c4375b3b6ffcab1600d2b1e15ec1edb 100644
--- a/mysql-test/t/ndb_insert.test
+++ b/mysql-test/t/ndb_insert.test
@@ -591,14 +591,14 @@ DELETE FROM t1 WHERE pk1 = 2 OR pk1 = 4 OR pk1 = 6;
 INSERT INTO t1 VALUES(1,1,1),(2,2,17),(3,4,5) ON DUPLICATE KEY UPDATE pk1=b;
 select * from t1 where pk1 = b and b != c order by pk1;
 
-# The following test case currently does not work
-#DELETE FROM t1;
-#CREATE UNIQUE INDEX bi ON t1(b);
-#INSERT INTO t1 VALUES 
-#(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
-#(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
-#INSERT INTO t1 VALUES(0,1,0),(21,21,21) ON DUPLICATE KEY UPDATE pk1=b+10,c=b+10;
-#select * from t1 order by pk1;
+# Test handling of duplicate unique
+DELETE FROM t1;
+CREATE UNIQUE INDEX bi ON t1(b);
+INSERT INTO t1 VALUES 
+(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
+(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
+INSERT INTO t1 VALUES(0,1,0),(21,21,21) ON DUPLICATE KEY UPDATE pk1=b+10,b=b+10;
+select * from t1 order by pk1;
 
 DROP TABLE t1;
 
@@ -614,7 +614,12 @@ INSERT IGNORE INTO t1 SELECT a FROM t1;
 INSERT IGNORE INTO t1 SELECT a FROM t1;
 INSERT IGNORE INTO t1 VALUES (1);
 INSERT IGNORE INTO t1 VALUES (1);
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
+DELETE FROM t1;
+CREATE UNIQUE INDEX ai ON t1(a);
+INSERT IGNORE INTO t1 VALUES (1);
+INSERT IGNORE INTO t1 VALUES (1);
+SELECT * FROM t1 ORDER BY a;
 DROP TABLE t1;
 
 # End of 4.1 tests
diff --git a/mysql-test/t/ndb_replace.test b/mysql-test/t/ndb_replace.test
index b97a0322a6a99cf5c0de45f203a5d9add4a92684..6cad80ef8ea5badddc06087c55a8ed5d9ad6691f 100644
--- a/mysql-test/t/ndb_replace.test
+++ b/mysql-test/t/ndb_replace.test
@@ -27,4 +27,15 @@ replace into t1 (gesuchnr,benutzer_id) values (1,1);
 select * from t1 order by gesuchnr;
 drop table t1;
 
+# bug#17431
+CREATE TABLE t1(i INT PRIMARY KEY AUTO_INCREMENT, 
+                j INT, 
+                k INT, 
+                UNIQUE INDEX(j)
+               ) ENGINE = ndb;
+INSERT  INTO t1 VALUES (1,1,23),(2,2,24);
+REPLACE INTO t1 (j,k) VALUES (1,42);
+REPLACE INTO t1 (i,j) VALUES (17,2);
+SELECT * from t1 ORDER BY i;
+
 # End of 4.1 tests
diff --git a/storage/ndb/include/ndbapi/NdbIndexOperation.hpp b/storage/ndb/include/ndbapi/NdbIndexOperation.hpp
index a8a15978568008dc8f8c281210593281beb52534..d16cd071f77e8d7b7a8d6962be8b612209065aa0 100644
--- a/storage/ndb/include/ndbapi/NdbIndexOperation.hpp
+++ b/storage/ndb/include/ndbapi/NdbIndexOperation.hpp
@@ -129,6 +129,11 @@ public:
    */
   int deleteTuple();
 
+  /**
+   * Get index object for this operation
+   */
+  const NdbDictionary::Index * getIndex() const;
+
 #ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
   /**
    * Define the NdbIndexOperation to be a standard operation of type 
diff --git a/storage/ndb/include/ndbapi/NdbOperation.hpp b/storage/ndb/include/ndbapi/NdbOperation.hpp
index 3a442c94253a5f467190fb24546863f330333268..e747dedb84b3b1c40f6874c01cd1b48a46f04630 100644
--- a/storage/ndb/include/ndbapi/NdbOperation.hpp
+++ b/storage/ndb/include/ndbapi/NdbOperation.hpp
@@ -56,9 +56,32 @@ public:
    */
 
   /**
-   * Lock when performing read
+   * Different access types (supported by sub-classes of NdbOperation)
    */
+
+  enum Type {
+    PrimaryKeyAccess     ///< Read, insert, update, or delete using pk
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+    = 0                  // NdbOperation
+#endif
+    ,UniqueIndexAccess   ///< Read, update, or delete using unique index
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+    = 1                  // NdbIndexOperation
+#endif
+    ,TableScan          ///< Full table scan
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+    = 2                  // NdbScanOperation
+#endif
+    ,OrderedIndexScan   ///< Ordered index scan
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+    = 3                  // NdbIndexScanOperation
+#endif
+  };
   
+  /**
+   * Lock when performing read
+   */
+
   enum LockMode {
     LM_Read                 ///< Read with shared lock
 #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
@@ -720,6 +743,11 @@ public:
    */
   const NdbDictionary::Table * getTable() const;
 
+  /**
+   * Get the type of access for this operation
+   */
+  const Type getType() const;
+
   /** @} *********************************************************************/
 
 #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
@@ -773,7 +801,7 @@ protected:
   int init(const class NdbTableImpl*, NdbTransaction* aCon);
   void initInterpreter();
 
-  NdbOperation(Ndb* aNdb);	
+  NdbOperation(Ndb* aNdb, Type aType = PrimaryKeyAccess);	
   virtual ~NdbOperation();
   void	next(NdbOperation*);		// Set next pointer		      
   NdbOperation*	    next();	        // Get next pointer		       
@@ -887,6 +915,8 @@ protected:
  * These are the private variables that are defined in the operation objects.
  *****************************************************************************/
 
+  Type m_type;
+
   NdbReceiver theReceiver;
 
   NdbError theError;			// Errorcode	       
@@ -1050,6 +1080,19 @@ NdbOperation::getFirstRecAttr() const
   return theReceiver.theFirstRecAttr;
 }
 
+/******************************************************************************
+Type getType()
+                                                                                
+Return Value    Return the Type.
+Remark:         Gets type of access.
+******************************************************************************/
+inline
+const NdbOperation::Type
+NdbOperation::getType() const
+{
+  return m_type;
+}
+                                                                                
 /******************************************************************************
 OperationStatus  Status();
 
diff --git a/storage/ndb/include/ndbapi/NdbScanOperation.hpp b/storage/ndb/include/ndbapi/NdbScanOperation.hpp
index 048e7a0c9523767fce154461b25720b8e4cf1d88..6f80a1627fe98e9657e304b915115e5642a32355 100644
--- a/storage/ndb/include/ndbapi/NdbScanOperation.hpp
+++ b/storage/ndb/include/ndbapi/NdbScanOperation.hpp
@@ -178,7 +178,8 @@ public:
   int restart(bool forceSend = false);
   
 protected:
-  NdbScanOperation(Ndb* aNdb);
+  NdbScanOperation(Ndb* aNdb,
+                   NdbOperation::Type aType = NdbOperation::TableScan);
   virtual ~NdbScanOperation();
 
   int nextResultImpl(bool fetchAllowed = true, bool forceSend = false);
diff --git a/storage/ndb/src/ndbapi/NdbIndexOperation.cpp b/storage/ndb/src/ndbapi/NdbIndexOperation.cpp
index 250af1622626e8ba90808b5d9025e0bff160dcef..39dbab423d341b98a77686b3d54b947f2853bb89 100644
--- a/storage/ndb/src/ndbapi/NdbIndexOperation.cpp
+++ b/storage/ndb/src/ndbapi/NdbIndexOperation.cpp
@@ -26,7 +26,7 @@
 #include <signaldata/IndxAttrInfo.hpp>
 
 NdbIndexOperation::NdbIndexOperation(Ndb* aNdb) :
-  NdbOperation(aNdb),
+  NdbOperation(aNdb, NdbOperation::UniqueIndexAccess),
   m_theIndex(NULL)
 {
   m_tcReqGSN = GSN_TCINDXREQ;
@@ -164,6 +164,12 @@ int NdbIndexOperation::interpretedDeleteTuple()
   return NdbOperation::interpretedDeleteTuple();
 }
 
+const NdbDictionary::Index*
+NdbIndexOperation::getIndex() const
+{
+  return m_theIndex;
+}
+
 int 
 NdbIndexOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint64  aTransactionId)
 {
diff --git a/storage/ndb/src/ndbapi/NdbOperation.cpp b/storage/ndb/src/ndbapi/NdbOperation.cpp
index c88b3a5e6ac3a5cfbd32f2a5f2582c7b46b5273e..769ce0662ef8c2754061c90dca892afa46c98057 100644
--- a/storage/ndb/src/ndbapi/NdbOperation.cpp
+++ b/storage/ndb/src/ndbapi/NdbOperation.cpp
@@ -37,7 +37,8 @@
  *                aTable: Pointers to the Table object
  * Remark:        Creat an object of NdbOperation. 
  ****************************************************************************/
-NdbOperation::NdbOperation(Ndb* aNdb) :
+NdbOperation::NdbOperation(Ndb* aNdb, NdbOperation::Type aType) :
+  m_type(aType),
   theReceiver(aNdb),
   theErrorLine(0),
   theNdb(aNdb),
diff --git a/storage/ndb/src/ndbapi/NdbScanOperation.cpp b/storage/ndb/src/ndbapi/NdbScanOperation.cpp
index c841a371af9b02beadeaff73c51e37256b22ad24..ad80d2e7c0cb1aabfd6e61639b3a4b9c9d13e8a2 100644
--- a/storage/ndb/src/ndbapi/NdbScanOperation.cpp
+++ b/storage/ndb/src/ndbapi/NdbScanOperation.cpp
@@ -37,8 +37,8 @@
 
 #define DEBUG_NEXT_RESULT 0
 
-NdbScanOperation::NdbScanOperation(Ndb* aNdb) :
-  NdbOperation(aNdb),
+NdbScanOperation::NdbScanOperation(Ndb* aNdb, NdbOperation::Type aType) :
+  NdbOperation(aNdb, aType),
   m_transConnection(NULL)
 {
   theParallelism = 0;
@@ -1032,7 +1032,7 @@ NdbScanOperation::getBlobHandle(Uint32 anAttrId)
 }
 
 NdbIndexScanOperation::NdbIndexScanOperation(Ndb* aNdb)
-  : NdbScanOperation(aNdb)
+  : NdbScanOperation(aNdb, NdbOperation::OrderedIndexScan)
 {
 }
 
diff --git a/storage/ndb/src/ndbapi/NdbTransaction.cpp b/storage/ndb/src/ndbapi/NdbTransaction.cpp
index f309c448fd3604ceaf91fdc1e9cd6d180fec18b6..82125985b52b9475388bbe2e0026e1b448d00c96 100644
--- a/storage/ndb/src/ndbapi/NdbTransaction.cpp
+++ b/storage/ndb/src/ndbapi/NdbTransaction.cpp
@@ -1193,6 +1193,8 @@ NdbTransaction::getNdbIndexScanOperation(const NdbIndexImpl* index,
       {
 	tOp->m_currentTable = table;
       }
+      // Mark that this really an NdbIndexScanOperation
+      tOp->m_type = NdbOperation::OrderedIndexScan; 
       return tOp;
     } else {
       setOperationErrorCodeAbort(4271);
@@ -1254,6 +1256,8 @@ NdbTransaction::getNdbScanOperation(const NdbTableImpl * tab)
   
   if (tOp->init(tab, this) != -1) {
     define_scan_op(tOp);
+    // Mark that this NdbIndexScanOperation is used as NdbScanOperation
+    tOp->m_type = NdbOperation::TableScan; 
     return tOp;
   } else {
     theNdb->releaseScanOperation(tOp);