diff options
author | mskold/marty@mysql.com/quadfish.(none) <> | 2007-12-06 17:15:21 +0100 |
---|---|---|
committer | mskold/marty@mysql.com/quadfish.(none) <> | 2007-12-06 17:15:21 +0100 |
commit | 27c025061d8bd3478ea4bd2512dbf2e4ca0c56db (patch) | |
tree | aa4869373d31aa5f1ecf96103d3d79d859b6d901 | |
parent | 88fc48fd5e342a7ad8cc6ac15a9dbe7c508fb019 (diff) | |
download | mariadb-git-27c025061d8bd3478ea4bd2512dbf2e4ca0c56db.tar.gz |
bug#21072 Duplicate key error in NDB references wrong key: Return correct key for non-batching inserts
-rw-r--r-- | mysql-test/r/ndb_charset.result | 8 | ||||
-rw-r--r-- | mysql-test/r/ndb_index_unique.result | 14 | ||||
-rw-r--r-- | mysql-test/r/ndb_update.result | 2 | ||||
-rw-r--r-- | ndb/include/kernel/signaldata/TcKeyRef.hpp | 3 | ||||
-rw-r--r-- | ndb/include/kernel/signaldata/TcRollbackRep.hpp | 3 | ||||
-rw-r--r-- | ndb/include/ndbapi/NdbDictionary.hpp | 7 | ||||
-rw-r--r-- | ndb/src/kernel/blocks/dbtc/Dbtc.hpp | 1 | ||||
-rw-r--r-- | ndb/src/kernel/blocks/dbtc/DbtcMain.cpp | 21 | ||||
-rw-r--r-- | ndb/src/ndbapi/NdbDictionary.cpp | 9 | ||||
-rw-r--r-- | ndb/src/ndbapi/NdbOperationExec.cpp | 7 | ||||
-rw-r--r-- | ndb/src/ndbapi/NdbTransaction.cpp | 13 | ||||
-rw-r--r-- | ndb/src/ndbapi/ndberror.c | 2 | ||||
-rw-r--r-- | sql/ha_ndbcluster.cc | 23 |
13 files changed, 92 insertions, 21 deletions
diff --git a/mysql-test/r/ndb_charset.result b/mysql-test/r/ndb_charset.result index 9e519c39496..ed2b144cac9 100644 --- a/mysql-test/r/ndb_charset.result +++ b/mysql-test/r/ndb_charset.result @@ -112,9 +112,9 @@ unique key(a) ) engine=ndb; insert into t1 values(1, 'aAa'); insert into t1 values(2, 'aaa'); -ERROR 23000: Duplicate entry '' for key 0 +ERROR 23000: Duplicate entry 'aaa' for key 2 insert into t1 values(3, 'AAA'); -ERROR 23000: Duplicate entry '' for key 0 +ERROR 23000: Duplicate entry 'AAA' for key 2 select * from t1 order by p; p a 1 aAa @@ -138,9 +138,9 @@ unique key(a) ) engine=ndb; insert into t1 values (1,'A'),(2,'b '),(3,'C '),(4,'d '),(5,'E'),(6,'f'); insert into t1 values(99,'b'); -ERROR 23000: Duplicate entry '' for key 0 +ERROR 23000: Duplicate entry 'b' for key 2 insert into t1 values(99,'a '); -ERROR 23000: Duplicate entry '' for key 0 +ERROR 23000: Duplicate entry 'a ' for key 2 select a,length(a) from t1 order by a; a length(a) A 1 diff --git a/mysql-test/r/ndb_index_unique.result b/mysql-test/r/ndb_index_unique.result index 670fbe5b4e0..b3607fbe072 100644 --- a/mysql-test/r/ndb_index_unique.result +++ b/mysql-test/r/ndb_index_unique.result @@ -22,7 +22,7 @@ select * from t1 where b = 4 order by a; a b c 3 4 6 insert into t1 values(8, 2, 3); -ERROR 23000: Duplicate entry '' for key 0 +ERROR 23000: Duplicate entry '2' for key 2 select * from t1 order by a; a b c 1 2 3 @@ -89,7 +89,7 @@ a b c 1 1 1 4 4 NULL insert into t1 values(5,1,1); -ERROR 23000: Duplicate entry '' for key 0 +ERROR 23000: Duplicate entry '1-1' for key 2 drop table t1; CREATE TABLE t2 ( a int unsigned NOT NULL PRIMARY KEY, @@ -112,7 +112,7 @@ select * from t2 where b = 4 order by a; a b c 3 4 6 insert into t2 values(8, 2, 3); -ERROR 23000: Duplicate entry '' for key 0 +ERROR 23000: Duplicate entry '2-3' for key 2 select * from t2 order by a; a b c 1 2 3 @@ -135,7 +135,7 @@ a b c 8 2 3 create unique index bi using hash on t2(b); insert into t2 values(9, 3, 1); -ERROR 23000: Duplicate entry '' for key 0 +ERROR 23000: Duplicate entry '3' for key 3 alter table t2 drop index bi; insert into t2 values(9, 3, 1); select * from t2 order by a; @@ -225,7 +225,7 @@ pk a 3 NULL 4 4 insert into t1 values (5,0); -ERROR 23000: Duplicate entry '' for key 0 +ERROR 23000: Duplicate entry '0' for key 2 select * from t1 order by pk; pk a -1 NULL @@ -258,7 +258,7 @@ pk a b c 0 NULL 18 NULL 1 3 19 abc insert into t2 values(2,3,19,'abc'); -ERROR 23000: Duplicate entry '' for key 0 +ERROR 23000: Duplicate entry '3-abc' for key 2 select * from t2 order by pk; pk a b c -1 1 17 NULL @@ -678,7 +678,7 @@ create table t1 (a int primary key, b varchar(1000) not null, unique key (b)) engine=ndb charset=utf8; insert into t1 values (1, repeat(_utf8 0xe288ab6474, 200)); insert into t1 values (2, repeat(_utf8 0xe288ab6474, 200)); -ERROR 23000: Duplicate entry '' for key 0 +ERROR 23000: Duplicate entry '∫dt∫dt∫dt∫dt∫dt∫dt∫dt∫dt∫dt∫dt∫dt∫dt∫d' for key 2 select a, sha1(b) from t1; a sha1(b) 1 08f5d02c8b8bc244f275bdfc22c42c5cab0d9d7d diff --git a/mysql-test/r/ndb_update.result b/mysql-test/r/ndb_update.result index 7848a47bcef..6bbf3e6a4e1 100644 --- a/mysql-test/r/ndb_update.result +++ b/mysql-test/r/ndb_update.result @@ -26,7 +26,7 @@ pk1 b c 2 2 2 4 1 1 UPDATE t1 set pk1 = 1, c = 2 where pk1 = 4; -ERROR 23000: Duplicate entry '' for key 0 +ERROR 23000: Duplicate entry '2' for key 2 UPDATE IGNORE t1 set pk1 = 1, c = 2 where pk1 = 4; select * from t1 order by pk1; pk1 b c diff --git a/ndb/include/kernel/signaldata/TcKeyRef.hpp b/ndb/include/kernel/signaldata/TcKeyRef.hpp index 2846ce3854f..56f6cdae29d 100644 --- a/ndb/include/kernel/signaldata/TcKeyRef.hpp +++ b/ndb/include/kernel/signaldata/TcKeyRef.hpp @@ -40,12 +40,13 @@ class TcKeyRef { friend bool printTCKEYREF(FILE *, const Uint32 *, Uint32, Uint16); public: - STATIC_CONST( SignalLength = 4 ); + STATIC_CONST( SignalLength = 5 ); private: Uint32 connectPtr; Uint32 transId[2]; Uint32 errorCode; + Uint32 errorData; }; #endif diff --git a/ndb/include/kernel/signaldata/TcRollbackRep.hpp b/ndb/include/kernel/signaldata/TcRollbackRep.hpp index 3b5e2f3d3cb..609756605d5 100644 --- a/ndb/include/kernel/signaldata/TcRollbackRep.hpp +++ b/ndb/include/kernel/signaldata/TcRollbackRep.hpp @@ -38,12 +38,13 @@ class TcRollbackRep { friend bool printTCROLBACKREP(FILE *, const Uint32 *, Uint32, Uint16); public: - STATIC_CONST( SignalLength = 4 ); + STATIC_CONST( SignalLength = 5 ); private: Uint32 connectPtr; Uint32 transId[2]; Uint32 returnCode; + Uint32 errorData; }; #endif diff --git a/ndb/include/ndbapi/NdbDictionary.hpp b/ndb/include/ndbapi/NdbDictionary.hpp index 445bb513ffc..24fb9811b3d 100644 --- a/ndb/include/ndbapi/NdbDictionary.hpp +++ b/ndb/include/ndbapi/NdbDictionary.hpp @@ -792,7 +792,12 @@ public: * Get the name of the table being indexed */ const char * getTable() const; - + + /** + * Get the table representing the index + */ + const Table * getIndexTable() const; + /** * Get the number of columns in the index */ diff --git a/ndb/src/kernel/blocks/dbtc/Dbtc.hpp b/ndb/src/kernel/blocks/dbtc/Dbtc.hpp index 710d2fde182..6fb03fa2407 100644 --- a/ndb/src/kernel/blocks/dbtc/Dbtc.hpp +++ b/ndb/src/kernel/blocks/dbtc/Dbtc.hpp @@ -727,6 +727,7 @@ public: // Index op return context UintR indexOp; UintR clientData; + Uint32 errorData; UintR attrInfoLen; UintR accumulatingIndexOp; diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index 91adae183f4..57daffbf331 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -5107,6 +5107,7 @@ void Dbtc::releaseDirtyWrite(Signal* signal) void Dbtc::execLQHKEYREF(Signal* signal) { const LqhKeyRef * const lqhKeyRef = (LqhKeyRef *)signal->getDataPtr(); + Uint32 indexId = 0; jamEntry(); UintR compare_transid1, compare_transid2; @@ -5158,6 +5159,10 @@ void Dbtc::execLQHKEYREF(Signal* signal) ptrCheckGuard(opPtr, ctcConnectFilesize, localTcConnectRecord); // The operation executed an index trigger + TcIndexData* indexData = c_theIndexes.getPtr(currentIndexId); + indexId = indexData->indexId; + regApiPtr->errorData = indexId; + ndbout_c("LQHKEYREF, found index %u", indexId); const Uint32 opType = regTcPtr->operation; if (errCode == ZALREADYEXIST) errCode = terrorCode = ZNOTUNIQUE; @@ -5170,7 +5175,6 @@ void Dbtc::execLQHKEYREF(Signal* signal) } else { jam(); /** ZDELETE && NOT_FOUND */ - TcIndexData* indexData = c_theIndexes.getPtr(currentIndexId); if(indexData->indexState == IS_BUILDING && state != CS_ABORTING){ jam(); /** @@ -5242,12 +5246,16 @@ void Dbtc::execLQHKEYREF(Signal* signal) jam(); regApiPtr->lqhkeyreqrec--; // Compensate for extra during read tcKeyRef->connectPtr = indexOp; + ndbout_c("TCKEYREF, sending index %u", indexId); + tcKeyRef->errorData = indexId; EXECUTE_DIRECT(DBTC, GSN_TCKEYREF, signal, TcKeyRef::SignalLength); apiConnectptr.i = save; apiConnectptr.p = regApiPtr; } else { jam(); tcKeyRef->connectPtr = clientData; + ndbout_c("TCKEYREF, sending index %u", indexId); + tcKeyRef->errorData = indexId; sendSignal(regApiPtr->ndbapiBlockref, GSN_TCKEYREF, signal, TcKeyRef::SignalLength, JBB); }//if @@ -10548,6 +10556,7 @@ void Dbtc::releaseAbortResources(Signal* signal) tcRollbackRep->transId[0] = apiConnectptr.p->transid[0]; tcRollbackRep->transId[1] = apiConnectptr.p->transid[1]; tcRollbackRep->returnCode = apiConnectptr.p->returncode; + tcRollbackRep->errorData = apiConnectptr.p->errorData; sendSignal(blockRef, GSN_TCROLLBACKREP, signal, TcRollbackRep::SignalLength, JBB); } @@ -11972,6 +11981,7 @@ void Dbtc::execTCKEYCONF(Signal* signal) tcIndxRef->transId[0] = regApiPtr->transid[0]; tcIndxRef->transId[1] = regApiPtr->transid[1]; tcIndxRef->errorCode = 4349; + tcIndxRef->errorData = 0; sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB); return; @@ -11991,6 +12001,7 @@ void Dbtc::execTCKEYCONF(Signal* signal) tcIndxRef->transId[0] = regApiPtr->transid[0]; tcIndxRef->transId[1] = regApiPtr->transid[1]; tcIndxRef->errorCode = 4349; + tcIndxRef->errorData = 0; sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB); return; @@ -12074,6 +12085,7 @@ void Dbtc::execTCKEYREF(Signal* signal) tcIndxRef->transId[0] = tcKeyRef->transId[0]; tcIndxRef->transId[1] = tcKeyRef->transId[1]; tcIndxRef->errorCode = tcKeyRef->errorCode; + tcIndxRef->errorData = 0; releaseIndexOperation(regApiPtr, indexOp); @@ -12151,6 +12163,7 @@ void Dbtc::execTRANSID_AI(Signal* signal) tcIndxRef->transId[0] = regApiPtr->transid[0]; tcIndxRef->transId[1] = regApiPtr->transid[1]; tcIndxRef->errorCode = 4000; + tcIndxRef->errorData = 0; sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB); return; @@ -12166,6 +12179,7 @@ void Dbtc::execTRANSID_AI(Signal* signal) tcIndxRef->transId[0] = regApiPtr->transid[0]; tcIndxRef->transId[1] = regApiPtr->transid[1]; tcIndxRef->errorCode = 4349; + tcIndxRef->errorData = 0; sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB); return; @@ -12194,6 +12208,7 @@ void Dbtc::execTRANSID_AI(Signal* signal) tcIndxRef->transId[0] = regApiPtr->transid[0]; tcIndxRef->transId[1] = regApiPtr->transid[1]; tcIndxRef->errorCode = 4349; + tcIndxRef->errorData = 0; sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB); */ @@ -12219,6 +12234,7 @@ void Dbtc::execTRANSID_AI(Signal* signal) tcIndxRef->transId[0] = regApiPtr->transid[0]; tcIndxRef->transId[1] = regApiPtr->transid[1]; tcIndxRef->errorCode = 4349; + // tcIndxRef->errorData = ??; Where to find indexId sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB); return; @@ -12272,6 +12288,7 @@ void Dbtc::readIndexTable(Signal* signal, tcIndxRef->transId[0] = regApiPtr->transid[0]; tcIndxRef->transId[1] = regApiPtr->transid[1]; tcIndxRef->errorCode = 4000; + // tcIndxRef->errorData = ??; Where to find indexId sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB); return; @@ -12414,6 +12431,7 @@ void Dbtc::executeIndexOperation(Signal* signal, tcIndxRef->transId[0] = regApiPtr->transid[0]; tcIndxRef->transId[1] = regApiPtr->transid[1]; tcIndxRef->errorCode = 4349; + tcIndxRef->errorData = 0; sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB); return; @@ -13012,6 +13030,7 @@ void Dbtc::insertIntoIndexTable(Signal* signal, } regApiPtr->currSavePointId = currSavePointId; + ndbout_c("TCKEYREQ, saving index %u", indexData->indexId); tcConnectptr.p->currentIndexId = indexData->indexId; // *********** KEYINFO *********** diff --git a/ndb/src/ndbapi/NdbDictionary.cpp b/ndb/src/ndbapi/NdbDictionary.cpp index 86a6624959e..32a2cd8ba0c 100644 --- a/ndb/src/ndbapi/NdbDictionary.cpp +++ b/ndb/src/ndbapi/NdbDictionary.cpp @@ -542,6 +542,15 @@ NdbDictionary::Index::getTable() const { return m_impl.getTable(); } +const NdbDictionary::Table * +NdbDictionary::Index::getIndexTable() const { + NdbTableImpl * t = m_impl.m_table; + if (t) { + return t->m_facade; + } + return 0; +} + unsigned NdbDictionary::Index::getNoOfColumns() const { return m_impl.m_columns.size(); diff --git a/ndb/src/ndbapi/NdbOperationExec.cpp b/ndb/src/ndbapi/NdbOperationExec.cpp index feff9ed5f36..9a50b000a1a 100644 --- a/ndb/src/ndbapi/NdbOperationExec.cpp +++ b/ndb/src/ndbapi/NdbOperationExec.cpp @@ -24,6 +24,7 @@ #include "Interpreter.hpp" #include <AttributeHeader.hpp> #include <signaldata/TcKeyReq.hpp> +#include <signaldata/TcKeyRef.hpp> #include <signaldata/KeyInfo.hpp> #include <signaldata/AttrInfo.hpp> #include <signaldata/ScanTab.hpp> @@ -550,6 +551,12 @@ NdbOperation::receiveTCKEYREF( NdbApiSignal* aSignal) theNdbCon->theReturnStatus = NdbTransaction::ReturnFailure; } theError.code = aSignal->readData(4); + if (aSignal->getLength() == TcKeyRef::SignalLength) + { + // Signal may contain additional error data + theError.details = (char *) aSignal->readData(5); + } + theNdbCon->setOperationErrorCodeAbort(aSignal->readData(4), ao); if(theOperationType != ReadRequest || !theSimpleIndicator) // not simple read diff --git a/ndb/src/ndbapi/NdbTransaction.cpp b/ndb/src/ndbapi/NdbTransaction.cpp index 1ebc5b7ef24..262deb0050e 100644 --- a/ndb/src/ndbapi/NdbTransaction.cpp +++ b/ndb/src/ndbapi/NdbTransaction.cpp @@ -30,6 +30,7 @@ #include <signaldata/TcCommit.hpp> #include <signaldata/TcKeyFailConf.hpp> #include <signaldata/TcHbRep.hpp> +#include <signaldata/TcRollbackRep.hpp> /***************************************************************************** NdbTransaction( Ndb* aNdb ); @@ -1757,6 +1758,8 @@ Remark: Handles the reception of the ROLLBACKREP signal. int NdbTransaction::receiveTCROLLBACKREP( NdbApiSignal* aSignal) { + DBUG_ENTER("NdbTransaction::receiveTCROLLBACKREP"); + /**************************************************************************** Check that we are expecting signals from this transaction and that it doesn't belong to a transaction already completed. Simply ignore messages from other @@ -1764,6 +1767,12 @@ transactions. ****************************************************************************/ if(checkState_TransId(aSignal->getDataPtr() + 1)){ theError.code = aSignal->readData(4);// Override any previous errors + if (aSignal->getLength() == TcRollbackRep::SignalLength) + { + DBUG_PRINT("info", ("Found error data %u", aSignal->readData(5))); + // Signal may contain additional error data + theError.details = (char *) aSignal->readData(5); + } /**********************************************************************/ /* A serious error has occured. This could be due to deadlock or */ @@ -1775,14 +1784,14 @@ transactions. theCompletionStatus = CompletedFailure; theCommitStatus = Aborted; theReturnStatus = ReturnFailure; - return 0; + DBUG_RETURN(0); } else { #ifdef NDB_NO_DROPPED_SIGNAL abort(); #endif } - return -1; + DBUG_RETURN(-1); }//NdbTransaction::receiveTCROLLBACKREP() /******************************************************************************* diff --git a/ndb/src/ndbapi/ndberror.c b/ndb/src/ndbapi/ndberror.c index 56eb2c0f8bd..4c60e384e6c 100644 --- a/ndb/src/ndbapi/ndberror.c +++ b/ndb/src/ndbapi/ndberror.c @@ -640,8 +640,6 @@ ndberror_update(ndberror_struct * error){ if(!found){ error->status = ST_U; } - - error->details = 0; } int diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index d29e9345c11..478347e4175 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -540,6 +540,27 @@ int ha_ndbcluster::ndb_err(NdbTransaction *trans) err.code, res)); if (res == HA_ERR_FOUND_DUPP_KEY) { + uint error_data= (uint) err.details; + uint dupkey= MAX_KEY; + + DBUG_PRINT("info", ("HA_ERR_FOUND_DUPP_KEY, index table %u", error_data)); + for (uint i= 0; i < MAX_KEY; i++) + { + if (m_index[i].type == UNIQUE_INDEX || + m_index[i].type == UNIQUE_ORDERED_INDEX) + { + const NDBINDEX *unique_index= + (const NDBINDEX *) m_index[i].unique_index; + if (unique_index && + unique_index->getIndexTable() && + (uint) unique_index->getIndexTable()->getTableId() == error_data) + { + DBUG_PRINT("info", ("Found violated key %u", i)); + dupkey= i; + break; + } + } + } if (m_rows_to_insert == 1) { /* @@ -547,7 +568,7 @@ int ha_ndbcluster::ndb_err(NdbTransaction *trans) violations here, so we need to return MAX_KEY for non-primary to signal that key is unknown */ - m_dupkey= err.code == 630 ? table->s->primary_key : MAX_KEY; + m_dupkey= err.code == 630 ? table->s->primary_key : dupkey; } else { |