Loading mysql-test/r/ndb_insert.result +117 −2 Original line number Diff line number Diff line Loading @@ -420,6 +420,9 @@ 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); ERROR 23000: Duplicate entry '10' for key 1 select count(*) from t1; count(*) 2000 begin; SELECT COUNT(*) FROM t1; COUNT(*) Loading @@ -437,9 +440,121 @@ SELECT COUNT(*) FROM t1; COUNT(*) 2000 commit; SELECT COUNT(*) FROM t1; COUNT(*) ERROR HY000: Got error 4350 'Transaction already aborted' from ndbcluster select * from t1 where pk1=1; pk1 b c 1 1 1 select * from t1 where pk1=10; pk1 b c 10 10 10 select count(*) from t1 where pk1 <= 10 order by pk1; count(*) 11 select count(*) from t1; count(*) 2000 begin; 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); ERROR 23000: Duplicate entry '10' for key 1 rollback; select * from t1 where pk1=1; pk1 b c 1 1 1 select * from t1 where pk1=10; pk1 b c 10 10 10 select count(*) from t1 where pk1 <= 10 order by pk1; count(*) 11 select count(*) from t1; count(*) 2000 begin; 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); ERROR 23000: Duplicate entry '10' for key 1 SELECT * FROM t1 WHERE pk1=10; ERROR HY000: Got error 4350 'Transaction already aborted' from ndbcluster rollback; select * from t1 where pk1=1; pk1 b c 1 1 1 select * from t1 where pk1=10; pk1 b c 10 10 10 select count(*) from t1 where pk1 <= 10 order by pk1; count(*) 11 select count(*) from t1; count(*) 2000 begin; 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); ERROR 23000: Duplicate entry '10' for key 1 SELECT * FROM t1 WHERE pk1=10; ERROR HY000: Got error 4350 'Transaction already aborted' from ndbcluster SELECT * FROM t1 WHERE pk1=10; ERROR HY000: Got error 4350 'Transaction already aborted' from ndbcluster commit; ERROR HY000: Got error 4350 'Transaction already aborted' from ndbcluster select * from t1 where pk1=1; pk1 b c 1 1 1 select * from t1 where pk1=10; pk1 b c 10 10 10 select count(*) from t1 where pk1 <= 10 order by pk1; count(*) 11 select count(*) from t1; count(*) 2000 begin; 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); ERROR 23000: Duplicate entry '10' for key 1 INSERT INTO t1 values (4000, 40, 44); ERROR HY000: Got error 4350 'Transaction already aborted' from ndbcluster rollback; select * from t1 where pk1=1; pk1 b c 1 1 1 select * from t1 where pk1=10; pk1 b c 10 10 10 select count(*) from t1 where pk1 <= 10 order by pk1; count(*) 11 select count(*) from t1; count(*) 2000 insert into t1 select * from t1 where b < 10 order by pk1; ERROR 23000: Duplicate entry '9' for key 1 begin; INSERT IGNORE INTO t1 VALUES(1,2,3); ERROR HY000: Table storage engine for 't1' doesn't have this option commit; select * from t1 where pk1=1; pk1 b c 1 1 1 INSERT IGNORE INTO t1 VALUES(1,2,3); ERROR HY000: Table storage engine for 't1' doesn't have this option select * from t1 where pk1=1; pk1 b c 1 1 1 REPLACE INTO t1 values(1, 2, 3); select * from t1 where pk1=1; pk1 b c 1 2 3 INSERT INTO t1 VALUES(1,1,1) ON DUPLICATE KEY UPDATE b=79; ERROR HY000: Table storage engine for 't1' doesn't have this option select * from t1 where pk1=1; pk1 b c 1 2 3 DROP TABLE t1; mysql-test/t/ndb_insert.test +113 −6 Original line number Diff line number Diff line Loading @@ -437,27 +437,117 @@ 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); select count(*) from t1; # # Insert duplicate rows, inside transaction # try to commit # begin; --error 1062 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); --error 1296 commit; select * from t1 where pk1=1; select * from t1 where pk1=10; select count(*) from t1 where pk1 <= 10 order by pk1; select count(*) from t1; # # Insert duplicate rows, inside transaction # since failing inserts rollbacks whole transaction # all select count (except second) return same value # rollback # SELECT COUNT(*) FROM t1; begin; --error 1062 INSERT INTO t1 VALUES (2001,2001,2001),(2002,2002,2002),(2003,2003,2003),(2004,2004,2004),(2005,2005,2005); SELECT COUNT(*) FROM t1; (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); rollback; select * from t1 where pk1=1; select * from t1 where pk1=10; select count(*) from t1 where pk1 <= 10 order by pk1; select count(*) from t1; # # Insert duplicate rows, inside transaction # then try to select, finally rollback # begin; --error 1062 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); SELECT COUNT(*) FROM t1; --error 1296 SELECT * FROM t1 WHERE pk1=10; rollback; select * from t1 where pk1=1; select * from t1 where pk1=10; select count(*) from t1 where pk1 <= 10 order by pk1; select count(*) from t1; # # Insert duplicate rows, inside transaction # then try to select, finally commit # begin; --error 1062 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); --error 1296 SELECT * FROM t1 WHERE pk1=10; --error 1296 SELECT * FROM t1 WHERE pk1=10; --error 1296 commit; SELECT COUNT(*) FROM t1; select * from t1 where pk1=1; select * from t1 where pk1=10; select count(*) from t1 where pk1 <= 10 order by pk1; select count(*) from t1; # # Insert duplicate rows, inside transaction # then try to do another insert # begin; --error 1062 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); --error 1296 INSERT INTO t1 values (4000, 40, 44); rollback; select * from t1 where pk1=1; select * from t1 where pk1=10; select count(*) from t1 where pk1 <= 10 order by pk1; select count(*) from t1; # # Insert duplicate rows using "insert .. select" Loading @@ -466,4 +556,21 @@ SELECT COUNT(*) FROM t1; insert into t1 select * from t1 where b < 10 order by pk1; begin; --error 1031 INSERT IGNORE INTO t1 VALUES(1,2,3); commit; select * from t1 where pk1=1; --error 1031 INSERT IGNORE INTO t1 VALUES(1,2,3); select * from t1 where pk1=1; REPLACE INTO t1 values(1, 2, 3); select * from t1 where pk1=1; --error 1031 INSERT INTO t1 VALUES(1,1,1) ON DUPLICATE KEY UPDATE b=79; select * from t1 where pk1=1; DROP TABLE t1; ndb/src/ndbapi/NdbConnection.cpp +56 −40 Original line number Diff line number Diff line Loading @@ -145,27 +145,29 @@ NdbConnection::init() }//NdbConnection::init() /***************************************************************************** setOperationErrorCode(int anErrorCode); setOperationErrorCode(int error); Remark: Sets an error code on the connection object from an operation object. *****************************************************************************/ void NdbConnection::setOperationErrorCode(int anErrorCode) NdbConnection::setOperationErrorCode(int error) { if (theError.code == 0) theError.code = anErrorCode; }//NdbConnection::setOperationErrorCode() DBUG_ENTER("NdbConnection::setOperationErrorCode"); setErrorCode(error); DBUG_VOID_RETURN; } /***************************************************************************** setOperationErrorCodeAbort(int anErrorCode); setOperationErrorCodeAbort(int error); Remark: Sets an error code on the connection object from an operation object. *****************************************************************************/ void NdbConnection::setOperationErrorCodeAbort(int anErrorCode) NdbConnection::setOperationErrorCodeAbort(int error) { DBUG_ENTER("NdbConnection::setOperationErrorCodeAbort"); if (theTransactionIsStarted == false) { theCommitStatus = Aborted; } else if ((m_abortOption == AbortOnError) && Loading @@ -173,9 +175,9 @@ NdbConnection::setOperationErrorCodeAbort(int anErrorCode) (theCommitStatus != Aborted)) { theCommitStatus = NeedAbort; }//if if (theError.code == 0) theError.code = anErrorCode; }//NdbConnection::setOperationErrorCodeAbort() setErrorCode(error); DBUG_VOID_RETURN; } /***************************************************************************** setErrorCode(int anErrorCode); Loading @@ -183,10 +185,15 @@ setErrorCode(int anErrorCode); Remark: Sets an error indication on the connection object. *****************************************************************************/ void NdbConnection::setErrorCode(int anErrorCode) NdbConnection::setErrorCode(int error) { DBUG_ENTER("NdbConnection::setErrorCode"); DBUG_PRINT("enter", ("error: %d, theError.code: %d", error, theError.code)); if (theError.code == 0) theError.code = anErrorCode; theError.code = error; DBUG_VOID_RETURN; }//NdbConnection::setErrorCode() int Loading Loading @@ -262,8 +269,12 @@ NdbConnection::execute(ExecType aTypeOfExec, AbortOption abortOption, int forceSend) { DBUG_ENTER("NdbConnection::execute"); DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d", aTypeOfExec, abortOption)); if (! theBlobFlag) return executeNoBlobs(aTypeOfExec, abortOption, forceSend); DBUG_RETURN(executeNoBlobs(aTypeOfExec, abortOption, forceSend)); /* * execute prepared ops in batches, as requested by blobs Loading Loading @@ -346,7 +357,7 @@ NdbConnection::execute(ExecType aTypeOfExec, } } while (theFirstOpInList != NULL || tExecType != aTypeOfExec); return ret; DBUG_RETURN(ret); } int Loading @@ -354,6 +365,10 @@ NdbConnection::executeNoBlobs(ExecType aTypeOfExec, AbortOption abortOption, int forceSend) { DBUG_ENTER("NdbConnection::executeNoBlobs"); DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d", aTypeOfExec, abortOption)); //------------------------------------------------------------------------ // We will start by preparing all operations in the transaction defined // since last execute or since beginning. If this works ok we will continue Loading @@ -376,7 +391,7 @@ NdbConnection::executeNoBlobs(ExecType aTypeOfExec, */ ndbout << "This timeout should never occur, execute(..)" << endl; setOperationErrorCodeAbort(4012); // Error code for "Cluster Failure" return -1; DBUG_RETURN(-1); }//if /* Loading @@ -400,13 +415,13 @@ NdbConnection::executeNoBlobs(ExecType aTypeOfExec, } #endif if (theReturnStatus == ReturnFailure) { return -1; DBUG_RETURN(-1); }//if break; } } thePendingBlobOps = 0; return 0; DBUG_RETURN(0); }//NdbConnection::execute() /***************************************************************************** Loading @@ -430,9 +445,15 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, void* anyObject, AbortOption abortOption) { DBUG_ENTER("NdbConnection::executeAsynchPrepare"); DBUG_PRINT("enter", ("aTypeOfExec: %d, aCallback: %x, anyObject: %x", aTypeOfExec, aCallback, anyObject)); /** * Reset error.code on execute */ if (theError.code != 0) DBUG_PRINT("enter", ("Resetting error %d on execute", theError.code)); theError.code = 0; NdbScanOperation* tcOp = m_theFirstScanOperation; if (tcOp != 0){ Loading @@ -441,7 +462,7 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, int tReturnCode; tReturnCode = tcOp->executeCursor(theDBnode); if (tReturnCode == -1) { return; DBUG_VOID_RETURN; }//if tcOp = (NdbScanOperation*)tcOp->next(); } // while Loading @@ -463,17 +484,6 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, theCallbackFunction = aCallback; theCallbackObject = anyObject; m_abortOption = abortOption; // SendStatusType tSendStatus = theSendStatus; // if (tSendStatus != InitState) { /**************************************************************************** * The application is obviously doing strange things. We should probably * report to the application the problem in some manner. Since we don't have * a good way of handling the problem we avoid discovering the problem. * Should be handled at some point in time. ****************************************************************************/ // return; // } m_waitForReply = true; tNdb->thePreparedTransactionsArray[tnoOfPreparedTransactions] = this; theTransArrayIndex = tnoOfPreparedTransactions; Loading Loading @@ -502,7 +512,11 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, } else { theSendStatus = sendABORTfail; }//if return; if (theCommitStatus == Aborted){ DBUG_PRINT("exit", ("theCommitStatus: Aborted")); setErrorCode(4350); } DBUG_VOID_RETURN; }//if if (tTransactionIsStarted == true) { if (tLastOp != NULL) { Loading @@ -520,7 +534,7 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, * We will use the commit method. *********************************************************************/ theSendStatus = sendCOMMITstate; return; DBUG_VOID_RETURN; } else { /********************************************************************** * We need to put it into the array of completed transactions to Loading @@ -532,7 +546,7 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, * put it into the completed array. **********************************************************************/ theSendStatus = sendCompleted; return; // No Commit with no operations is OK DBUG_VOID_RETURN; // No Commit with no operations is OK }//if }//if } else if (tTransactionIsStarted == false) { Loading Loading @@ -560,7 +574,7 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, * will put it into the completed array. ***********************************************************************/ theSendStatus = sendCompleted; return; DBUG_VOID_RETURN; }//if } Loading @@ -573,7 +587,7 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, tReturnCode = tOp->prepareSend(theTCConPtr, theTransactionId); if (tReturnCode == -1) { theSendStatus = sendABORTfail; return; DBUG_VOID_RETURN; }//if /************************************************************************* Loading @@ -596,7 +610,7 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, theNoOfOpSent = 0; theNoOfOpCompleted = 0; theSendStatus = sendOperations; return; DBUG_VOID_RETURN; }//NdbConnection::executeAsynchPrepare() void NdbConnection::close() Loading Loading @@ -665,6 +679,8 @@ Remark: Send all operations belonging to this connection. int NdbConnection::doSend() { DBUG_ENTER("NdbConnection::doSend"); /* This method assumes that at least one operation have been defined. This is ensured by the caller of this routine (=execute). Loading @@ -687,7 +703,7 @@ NdbConnection::doSend() theSendStatus = sendTC_OP; theTransactionIsStarted = true; tNdb->insert_sent_list(this); return 0; DBUG_RETURN(0); }//case case sendABORT: case sendABORTfail:{ Loading @@ -699,18 +715,18 @@ NdbConnection::doSend() theReturnStatus = ReturnFailure; }//if if (sendROLLBACK() == 0) { return 0; DBUG_RETURN(0); }//if break; }//case case sendCOMMITstate: if (sendCOMMIT() == 0) { return 0; DBUG_RETURN(0); }//if break; case sendCompleted: theNdb->insert_completed_list(this); return 0; DBUG_RETURN(0); default: ndbout << "Inconsistent theSendStatus = " << theSendStatus << endl; abort(); Loading @@ -720,7 +736,7 @@ NdbConnection::doSend() theReleaseOnClose = true; theTransactionIsStarted = false; theCommitStatus = Aborted; return -1; DBUG_RETURN(-1); }//NdbConnection::doSend() /************************************************************************** Loading ndb/src/ndbapi/ndberror.c +1 −0 Original line number Diff line number Diff line Loading @@ -228,6 +228,7 @@ ErrorBundle ErrorCodes[] = { { 4347, IE, "Bad state at alter index" }, { 4348, IE, "Inconsistency detected at alter index" }, { 4349, IE, "Inconsistency detected at index usage" }, { 4350, IE, "Transaction already aborted" }, /** * Application error Loading sql/ha_ndbcluster.cc +21 −8 Original line number Diff line number Diff line Loading @@ -122,6 +122,8 @@ static const err_code_mapping err_map[]= { 827, HA_ERR_RECORD_FILE_FULL }, { 832, HA_ERR_RECORD_FILE_FULL }, { 0, 1 }, { -1, -1 } }; Loading Loading @@ -246,8 +248,6 @@ int ha_ndbcluster::ndb_err(NdbConnection *trans) { int res; const NdbError err= trans->getNdbError(); if (!err.code) return 0; // Don't log things to DBUG log if no error DBUG_ENTER("ndb_err"); ERR_PRINT(err); Loading Loading @@ -283,10 +283,11 @@ bool ha_ndbcluster::get_error_message(int error, DBUG_ENTER("ha_ndbcluster::get_error_message"); DBUG_PRINT("enter", ("error: %d", error)); if (!m_ndb) Ndb* ndb = (Ndb*)current_thd->transaction.ndb; if (!ndb) DBUG_RETURN(false); const NdbError err= m_ndb->getNdbError(error); const NdbError err= ndb->getNdbError(error); bool temporary= err.status==NdbError::TemporaryError; buf->set(err.message, strlen(err.message), &my_charset_bin); DBUG_PRINT("exit", ("message: %s, temporary: %d", buf->ptr(), temporary)); Loading Loading @@ -1522,6 +1523,11 @@ int ha_ndbcluster::write_row(byte *record) int res; DBUG_ENTER("write_row"); if(m_ignore_dup_key_not_supported) { DBUG_RETURN(HA_ERR_WRONG_COMMAND); } statistic_increment(ha_write_count,&LOCK_status); if (table->timestamp_default_now) update_timestamp(record+table->timestamp_default_now-1); Loading Loading @@ -2479,14 +2485,20 @@ int ha_ndbcluster::extra(enum ha_extra_function operation) break; case HA_EXTRA_IGNORE_DUP_KEY: /* Dup keys don't rollback everything*/ DBUG_PRINT("info", ("HA_EXTRA_IGNORE_DUP_KEY")); if (current_thd->lex->sql_command == SQLCOM_REPLACE) { DBUG_PRINT("info", ("Turning ON use of write instead of insert")); m_use_write= TRUE; } else { m_ignore_dup_key_not_supported= TRUE; } break; case HA_EXTRA_NO_IGNORE_DUP_KEY: DBUG_PRINT("info", ("HA_EXTRA_NO_IGNORE_DUP_KEY")); DBUG_PRINT("info", ("Turning OFF use of write instead of insert")); m_use_write= false; m_ignore_dup_key_not_supported= false; break; case HA_EXTRA_RETRIEVE_ALL_COLS: /* Retrieve all columns, not just those where field->query_id is the same as Loading Loading @@ -3364,6 +3376,7 @@ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg): HA_NO_PREFIX_CHAR_KEYS), m_share(0), m_use_write(false), m_ignore_dup_key_not_supported(false), retrieve_all_fields(FALSE), rows_to_insert(1), rows_inserted(0), Loading Loading
mysql-test/r/ndb_insert.result +117 −2 Original line number Diff line number Diff line Loading @@ -420,6 +420,9 @@ 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); ERROR 23000: Duplicate entry '10' for key 1 select count(*) from t1; count(*) 2000 begin; SELECT COUNT(*) FROM t1; COUNT(*) Loading @@ -437,9 +440,121 @@ SELECT COUNT(*) FROM t1; COUNT(*) 2000 commit; SELECT COUNT(*) FROM t1; COUNT(*) ERROR HY000: Got error 4350 'Transaction already aborted' from ndbcluster select * from t1 where pk1=1; pk1 b c 1 1 1 select * from t1 where pk1=10; pk1 b c 10 10 10 select count(*) from t1 where pk1 <= 10 order by pk1; count(*) 11 select count(*) from t1; count(*) 2000 begin; 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); ERROR 23000: Duplicate entry '10' for key 1 rollback; select * from t1 where pk1=1; pk1 b c 1 1 1 select * from t1 where pk1=10; pk1 b c 10 10 10 select count(*) from t1 where pk1 <= 10 order by pk1; count(*) 11 select count(*) from t1; count(*) 2000 begin; 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); ERROR 23000: Duplicate entry '10' for key 1 SELECT * FROM t1 WHERE pk1=10; ERROR HY000: Got error 4350 'Transaction already aborted' from ndbcluster rollback; select * from t1 where pk1=1; pk1 b c 1 1 1 select * from t1 where pk1=10; pk1 b c 10 10 10 select count(*) from t1 where pk1 <= 10 order by pk1; count(*) 11 select count(*) from t1; count(*) 2000 begin; 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); ERROR 23000: Duplicate entry '10' for key 1 SELECT * FROM t1 WHERE pk1=10; ERROR HY000: Got error 4350 'Transaction already aborted' from ndbcluster SELECT * FROM t1 WHERE pk1=10; ERROR HY000: Got error 4350 'Transaction already aborted' from ndbcluster commit; ERROR HY000: Got error 4350 'Transaction already aborted' from ndbcluster select * from t1 where pk1=1; pk1 b c 1 1 1 select * from t1 where pk1=10; pk1 b c 10 10 10 select count(*) from t1 where pk1 <= 10 order by pk1; count(*) 11 select count(*) from t1; count(*) 2000 begin; 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); ERROR 23000: Duplicate entry '10' for key 1 INSERT INTO t1 values (4000, 40, 44); ERROR HY000: Got error 4350 'Transaction already aborted' from ndbcluster rollback; select * from t1 where pk1=1; pk1 b c 1 1 1 select * from t1 where pk1=10; pk1 b c 10 10 10 select count(*) from t1 where pk1 <= 10 order by pk1; count(*) 11 select count(*) from t1; count(*) 2000 insert into t1 select * from t1 where b < 10 order by pk1; ERROR 23000: Duplicate entry '9' for key 1 begin; INSERT IGNORE INTO t1 VALUES(1,2,3); ERROR HY000: Table storage engine for 't1' doesn't have this option commit; select * from t1 where pk1=1; pk1 b c 1 1 1 INSERT IGNORE INTO t1 VALUES(1,2,3); ERROR HY000: Table storage engine for 't1' doesn't have this option select * from t1 where pk1=1; pk1 b c 1 1 1 REPLACE INTO t1 values(1, 2, 3); select * from t1 where pk1=1; pk1 b c 1 2 3 INSERT INTO t1 VALUES(1,1,1) ON DUPLICATE KEY UPDATE b=79; ERROR HY000: Table storage engine for 't1' doesn't have this option select * from t1 where pk1=1; pk1 b c 1 2 3 DROP TABLE t1;
mysql-test/t/ndb_insert.test +113 −6 Original line number Diff line number Diff line Loading @@ -437,27 +437,117 @@ 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); select count(*) from t1; # # Insert duplicate rows, inside transaction # try to commit # begin; --error 1062 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); --error 1296 commit; select * from t1 where pk1=1; select * from t1 where pk1=10; select count(*) from t1 where pk1 <= 10 order by pk1; select count(*) from t1; # # Insert duplicate rows, inside transaction # since failing inserts rollbacks whole transaction # all select count (except second) return same value # rollback # SELECT COUNT(*) FROM t1; begin; --error 1062 INSERT INTO t1 VALUES (2001,2001,2001),(2002,2002,2002),(2003,2003,2003),(2004,2004,2004),(2005,2005,2005); SELECT COUNT(*) FROM t1; (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); rollback; select * from t1 where pk1=1; select * from t1 where pk1=10; select count(*) from t1 where pk1 <= 10 order by pk1; select count(*) from t1; # # Insert duplicate rows, inside transaction # then try to select, finally rollback # begin; --error 1062 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); SELECT COUNT(*) FROM t1; --error 1296 SELECT * FROM t1 WHERE pk1=10; rollback; select * from t1 where pk1=1; select * from t1 where pk1=10; select count(*) from t1 where pk1 <= 10 order by pk1; select count(*) from t1; # # Insert duplicate rows, inside transaction # then try to select, finally commit # begin; --error 1062 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); --error 1296 SELECT * FROM t1 WHERE pk1=10; --error 1296 SELECT * FROM t1 WHERE pk1=10; --error 1296 commit; SELECT COUNT(*) FROM t1; select * from t1 where pk1=1; select * from t1 where pk1=10; select count(*) from t1 where pk1 <= 10 order by pk1; select count(*) from t1; # # Insert duplicate rows, inside transaction # then try to do another insert # begin; --error 1062 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); --error 1296 INSERT INTO t1 values (4000, 40, 44); rollback; select * from t1 where pk1=1; select * from t1 where pk1=10; select count(*) from t1 where pk1 <= 10 order by pk1; select count(*) from t1; # # Insert duplicate rows using "insert .. select" Loading @@ -466,4 +556,21 @@ SELECT COUNT(*) FROM t1; insert into t1 select * from t1 where b < 10 order by pk1; begin; --error 1031 INSERT IGNORE INTO t1 VALUES(1,2,3); commit; select * from t1 where pk1=1; --error 1031 INSERT IGNORE INTO t1 VALUES(1,2,3); select * from t1 where pk1=1; REPLACE INTO t1 values(1, 2, 3); select * from t1 where pk1=1; --error 1031 INSERT INTO t1 VALUES(1,1,1) ON DUPLICATE KEY UPDATE b=79; select * from t1 where pk1=1; DROP TABLE t1;
ndb/src/ndbapi/NdbConnection.cpp +56 −40 Original line number Diff line number Diff line Loading @@ -145,27 +145,29 @@ NdbConnection::init() }//NdbConnection::init() /***************************************************************************** setOperationErrorCode(int anErrorCode); setOperationErrorCode(int error); Remark: Sets an error code on the connection object from an operation object. *****************************************************************************/ void NdbConnection::setOperationErrorCode(int anErrorCode) NdbConnection::setOperationErrorCode(int error) { if (theError.code == 0) theError.code = anErrorCode; }//NdbConnection::setOperationErrorCode() DBUG_ENTER("NdbConnection::setOperationErrorCode"); setErrorCode(error); DBUG_VOID_RETURN; } /***************************************************************************** setOperationErrorCodeAbort(int anErrorCode); setOperationErrorCodeAbort(int error); Remark: Sets an error code on the connection object from an operation object. *****************************************************************************/ void NdbConnection::setOperationErrorCodeAbort(int anErrorCode) NdbConnection::setOperationErrorCodeAbort(int error) { DBUG_ENTER("NdbConnection::setOperationErrorCodeAbort"); if (theTransactionIsStarted == false) { theCommitStatus = Aborted; } else if ((m_abortOption == AbortOnError) && Loading @@ -173,9 +175,9 @@ NdbConnection::setOperationErrorCodeAbort(int anErrorCode) (theCommitStatus != Aborted)) { theCommitStatus = NeedAbort; }//if if (theError.code == 0) theError.code = anErrorCode; }//NdbConnection::setOperationErrorCodeAbort() setErrorCode(error); DBUG_VOID_RETURN; } /***************************************************************************** setErrorCode(int anErrorCode); Loading @@ -183,10 +185,15 @@ setErrorCode(int anErrorCode); Remark: Sets an error indication on the connection object. *****************************************************************************/ void NdbConnection::setErrorCode(int anErrorCode) NdbConnection::setErrorCode(int error) { DBUG_ENTER("NdbConnection::setErrorCode"); DBUG_PRINT("enter", ("error: %d, theError.code: %d", error, theError.code)); if (theError.code == 0) theError.code = anErrorCode; theError.code = error; DBUG_VOID_RETURN; }//NdbConnection::setErrorCode() int Loading Loading @@ -262,8 +269,12 @@ NdbConnection::execute(ExecType aTypeOfExec, AbortOption abortOption, int forceSend) { DBUG_ENTER("NdbConnection::execute"); DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d", aTypeOfExec, abortOption)); if (! theBlobFlag) return executeNoBlobs(aTypeOfExec, abortOption, forceSend); DBUG_RETURN(executeNoBlobs(aTypeOfExec, abortOption, forceSend)); /* * execute prepared ops in batches, as requested by blobs Loading Loading @@ -346,7 +357,7 @@ NdbConnection::execute(ExecType aTypeOfExec, } } while (theFirstOpInList != NULL || tExecType != aTypeOfExec); return ret; DBUG_RETURN(ret); } int Loading @@ -354,6 +365,10 @@ NdbConnection::executeNoBlobs(ExecType aTypeOfExec, AbortOption abortOption, int forceSend) { DBUG_ENTER("NdbConnection::executeNoBlobs"); DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d", aTypeOfExec, abortOption)); //------------------------------------------------------------------------ // We will start by preparing all operations in the transaction defined // since last execute or since beginning. If this works ok we will continue Loading @@ -376,7 +391,7 @@ NdbConnection::executeNoBlobs(ExecType aTypeOfExec, */ ndbout << "This timeout should never occur, execute(..)" << endl; setOperationErrorCodeAbort(4012); // Error code for "Cluster Failure" return -1; DBUG_RETURN(-1); }//if /* Loading @@ -400,13 +415,13 @@ NdbConnection::executeNoBlobs(ExecType aTypeOfExec, } #endif if (theReturnStatus == ReturnFailure) { return -1; DBUG_RETURN(-1); }//if break; } } thePendingBlobOps = 0; return 0; DBUG_RETURN(0); }//NdbConnection::execute() /***************************************************************************** Loading @@ -430,9 +445,15 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, void* anyObject, AbortOption abortOption) { DBUG_ENTER("NdbConnection::executeAsynchPrepare"); DBUG_PRINT("enter", ("aTypeOfExec: %d, aCallback: %x, anyObject: %x", aTypeOfExec, aCallback, anyObject)); /** * Reset error.code on execute */ if (theError.code != 0) DBUG_PRINT("enter", ("Resetting error %d on execute", theError.code)); theError.code = 0; NdbScanOperation* tcOp = m_theFirstScanOperation; if (tcOp != 0){ Loading @@ -441,7 +462,7 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, int tReturnCode; tReturnCode = tcOp->executeCursor(theDBnode); if (tReturnCode == -1) { return; DBUG_VOID_RETURN; }//if tcOp = (NdbScanOperation*)tcOp->next(); } // while Loading @@ -463,17 +484,6 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, theCallbackFunction = aCallback; theCallbackObject = anyObject; m_abortOption = abortOption; // SendStatusType tSendStatus = theSendStatus; // if (tSendStatus != InitState) { /**************************************************************************** * The application is obviously doing strange things. We should probably * report to the application the problem in some manner. Since we don't have * a good way of handling the problem we avoid discovering the problem. * Should be handled at some point in time. ****************************************************************************/ // return; // } m_waitForReply = true; tNdb->thePreparedTransactionsArray[tnoOfPreparedTransactions] = this; theTransArrayIndex = tnoOfPreparedTransactions; Loading Loading @@ -502,7 +512,11 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, } else { theSendStatus = sendABORTfail; }//if return; if (theCommitStatus == Aborted){ DBUG_PRINT("exit", ("theCommitStatus: Aborted")); setErrorCode(4350); } DBUG_VOID_RETURN; }//if if (tTransactionIsStarted == true) { if (tLastOp != NULL) { Loading @@ -520,7 +534,7 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, * We will use the commit method. *********************************************************************/ theSendStatus = sendCOMMITstate; return; DBUG_VOID_RETURN; } else { /********************************************************************** * We need to put it into the array of completed transactions to Loading @@ -532,7 +546,7 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, * put it into the completed array. **********************************************************************/ theSendStatus = sendCompleted; return; // No Commit with no operations is OK DBUG_VOID_RETURN; // No Commit with no operations is OK }//if }//if } else if (tTransactionIsStarted == false) { Loading Loading @@ -560,7 +574,7 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, * will put it into the completed array. ***********************************************************************/ theSendStatus = sendCompleted; return; DBUG_VOID_RETURN; }//if } Loading @@ -573,7 +587,7 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, tReturnCode = tOp->prepareSend(theTCConPtr, theTransactionId); if (tReturnCode == -1) { theSendStatus = sendABORTfail; return; DBUG_VOID_RETURN; }//if /************************************************************************* Loading @@ -596,7 +610,7 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, theNoOfOpSent = 0; theNoOfOpCompleted = 0; theSendStatus = sendOperations; return; DBUG_VOID_RETURN; }//NdbConnection::executeAsynchPrepare() void NdbConnection::close() Loading Loading @@ -665,6 +679,8 @@ Remark: Send all operations belonging to this connection. int NdbConnection::doSend() { DBUG_ENTER("NdbConnection::doSend"); /* This method assumes that at least one operation have been defined. This is ensured by the caller of this routine (=execute). Loading @@ -687,7 +703,7 @@ NdbConnection::doSend() theSendStatus = sendTC_OP; theTransactionIsStarted = true; tNdb->insert_sent_list(this); return 0; DBUG_RETURN(0); }//case case sendABORT: case sendABORTfail:{ Loading @@ -699,18 +715,18 @@ NdbConnection::doSend() theReturnStatus = ReturnFailure; }//if if (sendROLLBACK() == 0) { return 0; DBUG_RETURN(0); }//if break; }//case case sendCOMMITstate: if (sendCOMMIT() == 0) { return 0; DBUG_RETURN(0); }//if break; case sendCompleted: theNdb->insert_completed_list(this); return 0; DBUG_RETURN(0); default: ndbout << "Inconsistent theSendStatus = " << theSendStatus << endl; abort(); Loading @@ -720,7 +736,7 @@ NdbConnection::doSend() theReleaseOnClose = true; theTransactionIsStarted = false; theCommitStatus = Aborted; return -1; DBUG_RETURN(-1); }//NdbConnection::doSend() /************************************************************************** Loading
ndb/src/ndbapi/ndberror.c +1 −0 Original line number Diff line number Diff line Loading @@ -228,6 +228,7 @@ ErrorBundle ErrorCodes[] = { { 4347, IE, "Bad state at alter index" }, { 4348, IE, "Inconsistency detected at alter index" }, { 4349, IE, "Inconsistency detected at index usage" }, { 4350, IE, "Transaction already aborted" }, /** * Application error Loading
sql/ha_ndbcluster.cc +21 −8 Original line number Diff line number Diff line Loading @@ -122,6 +122,8 @@ static const err_code_mapping err_map[]= { 827, HA_ERR_RECORD_FILE_FULL }, { 832, HA_ERR_RECORD_FILE_FULL }, { 0, 1 }, { -1, -1 } }; Loading Loading @@ -246,8 +248,6 @@ int ha_ndbcluster::ndb_err(NdbConnection *trans) { int res; const NdbError err= trans->getNdbError(); if (!err.code) return 0; // Don't log things to DBUG log if no error DBUG_ENTER("ndb_err"); ERR_PRINT(err); Loading Loading @@ -283,10 +283,11 @@ bool ha_ndbcluster::get_error_message(int error, DBUG_ENTER("ha_ndbcluster::get_error_message"); DBUG_PRINT("enter", ("error: %d", error)); if (!m_ndb) Ndb* ndb = (Ndb*)current_thd->transaction.ndb; if (!ndb) DBUG_RETURN(false); const NdbError err= m_ndb->getNdbError(error); const NdbError err= ndb->getNdbError(error); bool temporary= err.status==NdbError::TemporaryError; buf->set(err.message, strlen(err.message), &my_charset_bin); DBUG_PRINT("exit", ("message: %s, temporary: %d", buf->ptr(), temporary)); Loading Loading @@ -1522,6 +1523,11 @@ int ha_ndbcluster::write_row(byte *record) int res; DBUG_ENTER("write_row"); if(m_ignore_dup_key_not_supported) { DBUG_RETURN(HA_ERR_WRONG_COMMAND); } statistic_increment(ha_write_count,&LOCK_status); if (table->timestamp_default_now) update_timestamp(record+table->timestamp_default_now-1); Loading Loading @@ -2479,14 +2485,20 @@ int ha_ndbcluster::extra(enum ha_extra_function operation) break; case HA_EXTRA_IGNORE_DUP_KEY: /* Dup keys don't rollback everything*/ DBUG_PRINT("info", ("HA_EXTRA_IGNORE_DUP_KEY")); if (current_thd->lex->sql_command == SQLCOM_REPLACE) { DBUG_PRINT("info", ("Turning ON use of write instead of insert")); m_use_write= TRUE; } else { m_ignore_dup_key_not_supported= TRUE; } break; case HA_EXTRA_NO_IGNORE_DUP_KEY: DBUG_PRINT("info", ("HA_EXTRA_NO_IGNORE_DUP_KEY")); DBUG_PRINT("info", ("Turning OFF use of write instead of insert")); m_use_write= false; m_ignore_dup_key_not_supported= false; break; case HA_EXTRA_RETRIEVE_ALL_COLS: /* Retrieve all columns, not just those where field->query_id is the same as Loading Loading @@ -3364,6 +3376,7 @@ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg): HA_NO_PREFIX_CHAR_KEYS), m_share(0), m_use_write(false), m_ignore_dup_key_not_supported(false), retrieve_all_fields(FALSE), rows_to_insert(1), rows_inserted(0), Loading