mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Merge whalegate.ndb.mysql.com:/home/tomas/mysql-5.0
into whalegate.ndb.mysql.com:/home/tomas/mysql-5.0-ndb-merge
This commit is contained in:
8
mysql-test/r/ndb_bug26793.result
Normal file
8
mysql-test/r/ndb_bug26793.result
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
DROP TABLE IF EXISTS t1;
|
||||||
|
CREATE TABLE `test` (
|
||||||
|
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
|
||||||
|
`t` VARCHAR( 10 ) NOT NULL
|
||||||
|
) ENGINE = ndbcluster;
|
||||||
|
GRANT USAGE ON *.* TO user1@localhost IDENTIFIED BY 'pass';
|
||||||
|
DROP TABLE `test`.`test`;
|
||||||
|
drop user user1@localhost;
|
@ -405,3 +405,22 @@ a b
|
|||||||
1 1
|
1 1
|
||||||
10 10
|
10 10
|
||||||
drop table t2;
|
drop table t2;
|
||||||
|
create table t1 (id int primary key) engine ndb;
|
||||||
|
insert into t1 values (1), (2), (3);
|
||||||
|
create table t2 (id int primary key) engine ndb;
|
||||||
|
insert into t2 select id from t1;
|
||||||
|
create trigger kaboom after delete on t1
|
||||||
|
for each row begin
|
||||||
|
delete from t2 where id=old.id;
|
||||||
|
end|
|
||||||
|
select * from t1 order by id;
|
||||||
|
id
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
delete from t1 where id in (1,2);
|
||||||
|
select * from t2 order by id;
|
||||||
|
id
|
||||||
|
3
|
||||||
|
drop trigger kaboom;
|
||||||
|
drop table t1;
|
||||||
|
35
mysql-test/t/ndb_bug26793.test
Normal file
35
mysql-test/t/ndb_bug26793.test
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
-- source include/have_ndb.inc
|
||||||
|
|
||||||
|
--disable_warnings
|
||||||
|
DROP TABLE IF EXISTS t1;
|
||||||
|
--enable_warnings
|
||||||
|
|
||||||
|
CREATE TABLE `test` (
|
||||||
|
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
|
||||||
|
`t` VARCHAR( 10 ) NOT NULL
|
||||||
|
) ENGINE = ndbcluster;
|
||||||
|
|
||||||
|
# Add user1@localhost with a specific password
|
||||||
|
# and connect as that user
|
||||||
|
GRANT USAGE ON *.* TO user1@localhost IDENTIFIED BY 'pass';
|
||||||
|
connect (user1,localhost,user1,pass,*NO-ONE*);
|
||||||
|
|
||||||
|
# Run the query 100 times
|
||||||
|
disable_query_log;
|
||||||
|
disable_result_log;
|
||||||
|
let $i= 100;
|
||||||
|
while ($i)
|
||||||
|
{
|
||||||
|
select count(*) from information_schema.tables union all select count(*) from information_schema.tables union all select count(*) from information_schema.tables;
|
||||||
|
dec $i;
|
||||||
|
}
|
||||||
|
enable_query_log;
|
||||||
|
enable_result_log;
|
||||||
|
|
||||||
|
disconnect user1;
|
||||||
|
|
||||||
|
# Switch back to the default connection and cleanup
|
||||||
|
connection default;
|
||||||
|
DROP TABLE `test`.`test`;
|
||||||
|
drop user user1@localhost;
|
||||||
|
|
@ -291,3 +291,25 @@ insert into t2 values (1,1), (10,10);
|
|||||||
select * from t2 use index (ab) where a in(1,10) order by a;
|
select * from t2 use index (ab) where a in(1,10) order by a;
|
||||||
|
|
||||||
drop table t2;
|
drop table t2;
|
||||||
|
|
||||||
|
#bug#30337
|
||||||
|
|
||||||
|
create table t1 (id int primary key) engine ndb;
|
||||||
|
insert into t1 values (1), (2), (3);
|
||||||
|
|
||||||
|
create table t2 (id int primary key) engine ndb;
|
||||||
|
insert into t2 select id from t1;
|
||||||
|
|
||||||
|
delimiter |;
|
||||||
|
create trigger kaboom after delete on t1
|
||||||
|
for each row begin
|
||||||
|
delete from t2 where id=old.id;
|
||||||
|
end|
|
||||||
|
delimiter ;|
|
||||||
|
|
||||||
|
select * from t1 order by id;
|
||||||
|
delete from t1 where id in (1,2);
|
||||||
|
select * from t2 order by id;
|
||||||
|
|
||||||
|
drop trigger kaboom;
|
||||||
|
drop table t1;
|
||||||
|
@ -6,7 +6,7 @@ Next DBTUP 4014
|
|||||||
Next DBLQH 5043
|
Next DBLQH 5043
|
||||||
Next DBDICT 6007
|
Next DBDICT 6007
|
||||||
Next DBDIH 7183
|
Next DBDIH 7183
|
||||||
Next DBTC 8039
|
Next DBTC 8052
|
||||||
Next CMVMI 9000
|
Next CMVMI 9000
|
||||||
Next BACKUP 10022
|
Next BACKUP 10022
|
||||||
Next DBUTIL 11002
|
Next DBUTIL 11002
|
||||||
@ -296,6 +296,10 @@ ABORT OF TCKEYREQ
|
|||||||
|
|
||||||
8038 : Simulate API disconnect just after SCAN_TAB_REQ
|
8038 : Simulate API disconnect just after SCAN_TAB_REQ
|
||||||
|
|
||||||
|
8039 : Simulate failure of TransactionBufferMemory allocation for OI lookup
|
||||||
|
|
||||||
|
8051 : Simulate failure of allocation for saveINDXKEYINFO
|
||||||
|
|
||||||
|
|
||||||
CMVMI
|
CMVMI
|
||||||
-----
|
-----
|
||||||
|
@ -1497,12 +1497,12 @@ private:
|
|||||||
void clearCommitAckMarker(ApiConnectRecord * const regApiPtr,
|
void clearCommitAckMarker(ApiConnectRecord * const regApiPtr,
|
||||||
TcConnectRecord * const regTcPtr);
|
TcConnectRecord * const regTcPtr);
|
||||||
// Trigger and index handling
|
// Trigger and index handling
|
||||||
bool saveINDXKEYINFO(Signal* signal,
|
int saveINDXKEYINFO(Signal* signal,
|
||||||
TcIndexOperation* indexOp,
|
TcIndexOperation* indexOp,
|
||||||
const Uint32 *src,
|
const Uint32 *src,
|
||||||
Uint32 len);
|
Uint32 len);
|
||||||
bool receivedAllINDXKEYINFO(TcIndexOperation* indexOp);
|
bool receivedAllINDXKEYINFO(TcIndexOperation* indexOp);
|
||||||
bool saveINDXATTRINFO(Signal* signal,
|
int saveINDXATTRINFO(Signal* signal,
|
||||||
TcIndexOperation* indexOp,
|
TcIndexOperation* indexOp,
|
||||||
const Uint32 *src,
|
const Uint32 *src,
|
||||||
Uint32 len);
|
Uint32 len);
|
||||||
|
@ -1789,9 +1789,18 @@ start_failure:
|
|||||||
}//switch
|
}//switch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
inline
|
||||||
|
bool
|
||||||
|
compare_transid(Uint32* val0, Uint32* val1)
|
||||||
|
{
|
||||||
|
Uint32 tmp0 = val0[0] ^ val1[0];
|
||||||
|
Uint32 tmp1 = val0[1] ^ val1[1];
|
||||||
|
return (tmp0 | tmp1) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
void Dbtc::execKEYINFO(Signal* signal)
|
void Dbtc::execKEYINFO(Signal* signal)
|
||||||
{
|
{
|
||||||
UintR compare_transid1, compare_transid2;
|
|
||||||
jamEntry();
|
jamEntry();
|
||||||
apiConnectptr.i = signal->theData[0];
|
apiConnectptr.i = signal->theData[0];
|
||||||
tmaxData = 20;
|
tmaxData = 20;
|
||||||
@ -1801,10 +1810,8 @@ void Dbtc::execKEYINFO(Signal* signal)
|
|||||||
}//if
|
}//if
|
||||||
ptrAss(apiConnectptr, apiConnectRecord);
|
ptrAss(apiConnectptr, apiConnectRecord);
|
||||||
ttransid_ptr = 1;
|
ttransid_ptr = 1;
|
||||||
compare_transid1 = apiConnectptr.p->transid[0] ^ signal->theData[1];
|
if (compare_transid(apiConnectptr.p->transid, signal->theData+1) == false)
|
||||||
compare_transid2 = apiConnectptr.p->transid[1] ^ signal->theData[2];
|
{
|
||||||
compare_transid1 = compare_transid1 | compare_transid2;
|
|
||||||
if (compare_transid1 != 0) {
|
|
||||||
TCKEY_abort(signal, 19);
|
TCKEY_abort(signal, 19);
|
||||||
return;
|
return;
|
||||||
}//if
|
}//if
|
||||||
@ -2105,7 +2112,6 @@ void Dbtc::saveAttrbuf(Signal* signal)
|
|||||||
|
|
||||||
void Dbtc::execATTRINFO(Signal* signal)
|
void Dbtc::execATTRINFO(Signal* signal)
|
||||||
{
|
{
|
||||||
UintR compare_transid1, compare_transid2;
|
|
||||||
UintR Tdata1 = signal->theData[0];
|
UintR Tdata1 = signal->theData[0];
|
||||||
UintR Tlength = signal->length();
|
UintR Tlength = signal->length();
|
||||||
UintR TapiConnectFilesize = capiConnectFilesize;
|
UintR TapiConnectFilesize = capiConnectFilesize;
|
||||||
@ -2120,17 +2126,13 @@ void Dbtc::execATTRINFO(Signal* signal)
|
|||||||
return;
|
return;
|
||||||
}//if
|
}//if
|
||||||
|
|
||||||
UintR Tdata2 = signal->theData[1];
|
|
||||||
UintR Tdata3 = signal->theData[2];
|
|
||||||
ApiConnectRecord * const regApiPtr = &localApiConnectRecord[Tdata1];
|
ApiConnectRecord * const regApiPtr = &localApiConnectRecord[Tdata1];
|
||||||
compare_transid1 = regApiPtr->transid[0] ^ Tdata2;
|
|
||||||
compare_transid2 = regApiPtr->transid[1] ^ Tdata3;
|
|
||||||
apiConnectptr.p = regApiPtr;
|
apiConnectptr.p = regApiPtr;
|
||||||
compare_transid1 = compare_transid1 | compare_transid2;
|
|
||||||
|
|
||||||
if (compare_transid1 != 0) {
|
if (compare_transid(regApiPtr->transid, signal->theData+1) == false)
|
||||||
|
{
|
||||||
DEBUG("Drop ATTRINFO, wrong transid, lenght="<<Tlength
|
DEBUG("Drop ATTRINFO, wrong transid, lenght="<<Tlength
|
||||||
<< " transid("<<hex<<Tdata2<<", "<<Tdata3);
|
<< " transid("<<hex<<signal->theData[1]<<", "<<signal->theData[2]);
|
||||||
TCKEY_abort(signal, 19);
|
TCKEY_abort(signal, 19);
|
||||||
return;
|
return;
|
||||||
}//if
|
}//if
|
||||||
@ -5456,11 +5458,32 @@ void Dbtc::execTC_COMMITREQ(Signal* signal)
|
|||||||
}
|
}
|
||||||
}//Dbtc::execTC_COMMITREQ()
|
}//Dbtc::execTC_COMMITREQ()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TCROLLBACKREQ
|
||||||
|
*
|
||||||
|
* Format is:
|
||||||
|
*
|
||||||
|
* thedata[0] = apiconnectptr
|
||||||
|
* thedata[1] = transid[0]
|
||||||
|
* thedata[2] = transid[1]
|
||||||
|
* OPTIONAL thedata[3] = flags
|
||||||
|
*
|
||||||
|
* Flags:
|
||||||
|
* 0x1 = potentiallyBad data from API (try not to assert)
|
||||||
|
*/
|
||||||
void Dbtc::execTCROLLBACKREQ(Signal* signal)
|
void Dbtc::execTCROLLBACKREQ(Signal* signal)
|
||||||
{
|
{
|
||||||
|
bool potentiallyBad= false;
|
||||||
UintR compare_transid1, compare_transid2;
|
UintR compare_transid1, compare_transid2;
|
||||||
|
|
||||||
jamEntry();
|
jamEntry();
|
||||||
|
|
||||||
|
if(unlikely((signal->getLength() >= 4) && (signal->theData[3] & 0x1)))
|
||||||
|
{
|
||||||
|
ndbout_c("Trying to roll back potentially bad txn\n");
|
||||||
|
potentiallyBad= true;
|
||||||
|
}
|
||||||
|
|
||||||
apiConnectptr.i = signal->theData[0];
|
apiConnectptr.i = signal->theData[0];
|
||||||
if (apiConnectptr.i >= capiConnectFilesize) {
|
if (apiConnectptr.i >= capiConnectFilesize) {
|
||||||
goto TC_ROLL_warning;
|
goto TC_ROLL_warning;
|
||||||
@ -5547,12 +5570,14 @@ void Dbtc::execTCROLLBACKREQ(Signal* signal)
|
|||||||
|
|
||||||
TC_ROLL_warning:
|
TC_ROLL_warning:
|
||||||
jam();
|
jam();
|
||||||
warningHandlerLab(signal, __LINE__);
|
if(likely(potentiallyBad==false))
|
||||||
|
warningHandlerLab(signal, __LINE__);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TC_ROLL_system_error:
|
TC_ROLL_system_error:
|
||||||
jam();
|
jam();
|
||||||
systemErrorLab(signal, __LINE__);
|
if(likely(potentiallyBad==false))
|
||||||
|
systemErrorLab(signal, __LINE__);
|
||||||
return;
|
return;
|
||||||
}//Dbtc::execTCROLLBACKREQ()
|
}//Dbtc::execTCROLLBACKREQ()
|
||||||
|
|
||||||
@ -11559,6 +11584,7 @@ void Dbtc::execTCINDXREQ(Signal* signal)
|
|||||||
// This is a newly started transaction, clean-up
|
// This is a newly started transaction, clean-up
|
||||||
releaseAllSeizedIndexOperations(regApiPtr);
|
releaseAllSeizedIndexOperations(regApiPtr);
|
||||||
|
|
||||||
|
regApiPtr->apiConnectstate = CS_STARTED;
|
||||||
regApiPtr->transid[0] = tcIndxReq->transId1;
|
regApiPtr->transid[0] = tcIndxReq->transId1;
|
||||||
regApiPtr->transid[1] = tcIndxReq->transId2;
|
regApiPtr->transid[1] = tcIndxReq->transId2;
|
||||||
}//if
|
}//if
|
||||||
@ -11599,20 +11625,29 @@ void Dbtc::execTCINDXREQ(Signal* signal)
|
|||||||
Uint32 includedIndexLength = MIN(indexLength, indexBufSize);
|
Uint32 includedIndexLength = MIN(indexLength, indexBufSize);
|
||||||
indexOp->expectedAttrInfo = attrLength;
|
indexOp->expectedAttrInfo = attrLength;
|
||||||
Uint32 includedAttrLength = MIN(attrLength, attrBufSize);
|
Uint32 includedAttrLength = MIN(attrLength, attrBufSize);
|
||||||
if (saveINDXKEYINFO(signal,
|
|
||||||
indexOp,
|
int ret;
|
||||||
dataPtr,
|
if ((ret = saveINDXKEYINFO(signal,
|
||||||
includedIndexLength)) {
|
indexOp,
|
||||||
|
dataPtr,
|
||||||
|
includedIndexLength)) == 0)
|
||||||
|
{
|
||||||
jam();
|
jam();
|
||||||
// We have received all we need
|
// We have received all we need
|
||||||
readIndexTable(signal, regApiPtr, indexOp);
|
readIndexTable(signal, regApiPtr, indexOp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (ret == -1)
|
||||||
|
{
|
||||||
|
jam();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
dataPtr += includedIndexLength;
|
dataPtr += includedIndexLength;
|
||||||
if (saveINDXATTRINFO(signal,
|
if (saveINDXATTRINFO(signal,
|
||||||
indexOp,
|
indexOp,
|
||||||
dataPtr,
|
dataPtr,
|
||||||
includedAttrLength)) {
|
includedAttrLength) == 0) {
|
||||||
jam();
|
jam();
|
||||||
// We have received all we need
|
// We have received all we need
|
||||||
readIndexTable(signal, regApiPtr, indexOp);
|
readIndexTable(signal, regApiPtr, indexOp);
|
||||||
@ -11715,13 +11750,25 @@ void Dbtc::execINDXKEYINFO(Signal* signal)
|
|||||||
TcIndexOperationPtr indexOpPtr;
|
TcIndexOperationPtr indexOpPtr;
|
||||||
TcIndexOperation* indexOp;
|
TcIndexOperation* indexOp;
|
||||||
|
|
||||||
|
if (compare_transid(regApiPtr->transid, indxKeyInfo->transId) == false)
|
||||||
|
{
|
||||||
|
TCKEY_abort(signal, 19);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regApiPtr->apiConnectstate == CS_ABORTING)
|
||||||
|
{
|
||||||
|
jam();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if((indexOpPtr.i = regApiPtr->accumulatingIndexOp) != RNIL)
|
if((indexOpPtr.i = regApiPtr->accumulatingIndexOp) != RNIL)
|
||||||
{
|
{
|
||||||
indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i);
|
indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i);
|
||||||
if (saveINDXKEYINFO(signal,
|
if (saveINDXKEYINFO(signal,
|
||||||
indexOp,
|
indexOp,
|
||||||
src,
|
src,
|
||||||
keyInfoLength)) {
|
keyInfoLength) == 0) {
|
||||||
jam();
|
jam();
|
||||||
// We have received all we need
|
// We have received all we need
|
||||||
readIndexTable(signal, regApiPtr, indexOp);
|
readIndexTable(signal, regApiPtr, indexOp);
|
||||||
@ -11748,17 +11795,31 @@ void Dbtc::execINDXATTRINFO(Signal* signal)
|
|||||||
TcIndexOperationPtr indexOpPtr;
|
TcIndexOperationPtr indexOpPtr;
|
||||||
TcIndexOperation* indexOp;
|
TcIndexOperation* indexOp;
|
||||||
|
|
||||||
|
if (compare_transid(regApiPtr->transid, indxAttrInfo->transId) == false)
|
||||||
|
{
|
||||||
|
TCKEY_abort(signal, 19);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regApiPtr->apiConnectstate == CS_ABORTING)
|
||||||
|
{
|
||||||
|
jam();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if((indexOpPtr.i = regApiPtr->accumulatingIndexOp) != RNIL)
|
if((indexOpPtr.i = regApiPtr->accumulatingIndexOp) != RNIL)
|
||||||
{
|
{
|
||||||
indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i);
|
indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i);
|
||||||
if (saveINDXATTRINFO(signal,
|
if (saveINDXATTRINFO(signal,
|
||||||
indexOp,
|
indexOp,
|
||||||
src,
|
src,
|
||||||
attrInfoLength)) {
|
attrInfoLength) == 0) {
|
||||||
jam();
|
jam();
|
||||||
// We have received all we need
|
// We have received all we need
|
||||||
readIndexTable(signal, regApiPtr, indexOp);
|
readIndexTable(signal, regApiPtr, indexOp);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11766,12 +11827,13 @@ void Dbtc::execINDXATTRINFO(Signal* signal)
|
|||||||
* Save signal INDXKEYINFO
|
* Save signal INDXKEYINFO
|
||||||
* Return true if we have received all needed data
|
* Return true if we have received all needed data
|
||||||
*/
|
*/
|
||||||
bool Dbtc::saveINDXKEYINFO(Signal* signal,
|
int
|
||||||
TcIndexOperation* indexOp,
|
Dbtc::saveINDXKEYINFO(Signal* signal,
|
||||||
const Uint32 *src,
|
TcIndexOperation* indexOp,
|
||||||
Uint32 len)
|
const Uint32 *src,
|
||||||
|
Uint32 len)
|
||||||
{
|
{
|
||||||
if (!indexOp->keyInfo.append(src, len)) {
|
if (ERROR_INSERTED(8039) || !indexOp->keyInfo.append(src, len)) {
|
||||||
jam();
|
jam();
|
||||||
// Failed to seize keyInfo, abort transaction
|
// Failed to seize keyInfo, abort transaction
|
||||||
#ifdef VM_TRACE
|
#ifdef VM_TRACE
|
||||||
@ -11781,15 +11843,17 @@ bool Dbtc::saveINDXKEYINFO(Signal* signal,
|
|||||||
apiConnectptr.i = indexOp->connectionIndex;
|
apiConnectptr.i = indexOp->connectionIndex;
|
||||||
ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
|
ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
|
||||||
releaseIndexOperation(apiConnectptr.p, indexOp);
|
releaseIndexOperation(apiConnectptr.p, indexOp);
|
||||||
terrorCode = 4000;
|
terrorCode = 289;
|
||||||
|
if(TcKeyReq::getExecuteFlag(indexOp->tcIndxReq.requestInfo))
|
||||||
|
apiConnectptr.p->m_exec_flag= 1;
|
||||||
abortErrorLab(signal);
|
abortErrorLab(signal);
|
||||||
return false;
|
return -1;
|
||||||
}
|
}
|
||||||
if (receivedAllINDXKEYINFO(indexOp) && receivedAllINDXATTRINFO(indexOp)) {
|
if (receivedAllINDXKEYINFO(indexOp) && receivedAllINDXATTRINFO(indexOp)) {
|
||||||
jam();
|
jam();
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
return false;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Dbtc::receivedAllINDXKEYINFO(TcIndexOperation* indexOp)
|
bool Dbtc::receivedAllINDXKEYINFO(TcIndexOperation* indexOp)
|
||||||
@ -11801,12 +11865,13 @@ bool Dbtc::receivedAllINDXKEYINFO(TcIndexOperation* indexOp)
|
|||||||
* Save signal INDXATTRINFO
|
* Save signal INDXATTRINFO
|
||||||
* Return true if we have received all needed data
|
* Return true if we have received all needed data
|
||||||
*/
|
*/
|
||||||
bool Dbtc::saveINDXATTRINFO(Signal* signal,
|
int
|
||||||
TcIndexOperation* indexOp,
|
Dbtc::saveINDXATTRINFO(Signal* signal,
|
||||||
const Uint32 *src,
|
TcIndexOperation* indexOp,
|
||||||
Uint32 len)
|
const Uint32 *src,
|
||||||
|
Uint32 len)
|
||||||
{
|
{
|
||||||
if (!indexOp->attrInfo.append(src, len)) {
|
if (ERROR_INSERTED(8051) || !indexOp->attrInfo.append(src, len)) {
|
||||||
jam();
|
jam();
|
||||||
#ifdef VM_TRACE
|
#ifdef VM_TRACE
|
||||||
ndbout_c("Dbtc::saveINDXATTRINFO: Failed to seize attrInfo\n");
|
ndbout_c("Dbtc::saveINDXATTRINFO: Failed to seize attrInfo\n");
|
||||||
@ -11814,15 +11879,17 @@ bool Dbtc::saveINDXATTRINFO(Signal* signal,
|
|||||||
apiConnectptr.i = indexOp->connectionIndex;
|
apiConnectptr.i = indexOp->connectionIndex;
|
||||||
ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
|
ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
|
||||||
releaseIndexOperation(apiConnectptr.p, indexOp);
|
releaseIndexOperation(apiConnectptr.p, indexOp);
|
||||||
terrorCode = 4000;
|
terrorCode = 289;
|
||||||
|
if(TcKeyReq::getExecuteFlag(indexOp->tcIndxReq.requestInfo))
|
||||||
|
apiConnectptr.p->m_exec_flag= 1;
|
||||||
abortErrorLab(signal);
|
abortErrorLab(signal);
|
||||||
return false;
|
return -1;
|
||||||
}
|
}
|
||||||
if (receivedAllINDXKEYINFO(indexOp) && receivedAllINDXATTRINFO(indexOp)) {
|
if (receivedAllINDXKEYINFO(indexOp) && receivedAllINDXATTRINFO(indexOp)) {
|
||||||
jam();
|
jam();
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
return false;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Dbtc::receivedAllINDXATTRINFO(TcIndexOperation* indexOp)
|
bool Dbtc::receivedAllINDXATTRINFO(TcIndexOperation* indexOp)
|
||||||
@ -12006,6 +12073,9 @@ void Dbtc::execTCKEYREF(Signal* signal)
|
|||||||
tcIndxRef->transId[0] = tcKeyRef->transId[0];
|
tcIndxRef->transId[0] = tcKeyRef->transId[0];
|
||||||
tcIndxRef->transId[1] = tcKeyRef->transId[1];
|
tcIndxRef->transId[1] = tcKeyRef->transId[1];
|
||||||
tcIndxRef->errorCode = tcKeyRef->errorCode;
|
tcIndxRef->errorCode = tcKeyRef->errorCode;
|
||||||
|
|
||||||
|
releaseIndexOperation(regApiPtr, indexOp);
|
||||||
|
|
||||||
sendSignal(regApiPtr->ndbapiBlockref,
|
sendSignal(regApiPtr->ndbapiBlockref,
|
||||||
GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB);
|
GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB);
|
||||||
return;
|
return;
|
||||||
@ -12538,7 +12608,18 @@ void Dbtc::executeIndexOperation(Signal* signal,
|
|||||||
bool Dbtc::seizeIndexOperation(ApiConnectRecord* regApiPtr,
|
bool Dbtc::seizeIndexOperation(ApiConnectRecord* regApiPtr,
|
||||||
TcIndexOperationPtr& indexOpPtr)
|
TcIndexOperationPtr& indexOpPtr)
|
||||||
{
|
{
|
||||||
return regApiPtr->theSeizedIndexOperations.seize(indexOpPtr);
|
if (regApiPtr->theSeizedIndexOperations.seize(indexOpPtr))
|
||||||
|
{
|
||||||
|
ndbassert(indexOpPtr.p->expectedKeyInfo == 0);
|
||||||
|
ndbassert(indexOpPtr.p->keyInfo.getSize() == 0);
|
||||||
|
ndbassert(indexOpPtr.p->expectedAttrInfo == 0);
|
||||||
|
ndbassert(indexOpPtr.p->attrInfo.getSize() == 0);
|
||||||
|
ndbassert(indexOpPtr.p->expectedTransIdAI == 0);
|
||||||
|
ndbassert(indexOpPtr.p->transIdAI.getSize() == 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dbtc::releaseIndexOperation(ApiConnectRecord* regApiPtr,
|
void Dbtc::releaseIndexOperation(ApiConnectRecord* regApiPtr,
|
||||||
|
@ -892,7 +892,12 @@ NdbBlob::readParts(char* buf, Uint32 part, Uint32 count)
|
|||||||
while (n < count) {
|
while (n < count) {
|
||||||
NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTable);
|
NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTable);
|
||||||
if (tOp == NULL ||
|
if (tOp == NULL ||
|
||||||
tOp->committedRead() == -1 ||
|
/*
|
||||||
|
* This was committedRead() before. However lock on main
|
||||||
|
* table tuple does not fully protect blob parts since DBTUP
|
||||||
|
* commits each tuple separately.
|
||||||
|
*/
|
||||||
|
tOp->readTuple() == -1 ||
|
||||||
setPartKeyValue(tOp, part + n) == -1 ||
|
setPartKeyValue(tOp, part + n) == -1 ||
|
||||||
tOp->getValue((Uint32)3, buf) == NULL) {
|
tOp->getValue((Uint32)3, buf) == NULL) {
|
||||||
setErrorCode(tOp);
|
setErrorCode(tOp);
|
||||||
|
@ -481,12 +481,27 @@ NdbTransaction::executeNoBlobs(ExecType aTypeOfExec,
|
|||||||
while (1) {
|
while (1) {
|
||||||
int noOfComp = tNdb->sendPollNdb(3 * timeout, 1, forceSend);
|
int noOfComp = tNdb->sendPollNdb(3 * timeout, 1, forceSend);
|
||||||
if (noOfComp == 0) {
|
if (noOfComp == 0) {
|
||||||
/**
|
/*
|
||||||
* This timeout situation can occur if NDB crashes.
|
* Just for fun, this is only one of two places where
|
||||||
|
* we could hit this error... It's quite possible we
|
||||||
|
* hit it in Ndbif.cpp in Ndb::check_send_timeout()
|
||||||
|
*
|
||||||
|
* We behave rather similarly in both places.
|
||||||
|
* Hitting this is certainly a bug though...
|
||||||
*/
|
*/
|
||||||
ndbout << "This timeout should never occur, execute(..)" << endl;
|
g_eventLogger.error("WARNING: Timeout in executeNoBlobs() waiting for "
|
||||||
theError.code = 4012;
|
"response from NDB data nodes. This should NEVER "
|
||||||
setOperationErrorCodeAbort(4012); // Error code for "Cluster Failure"
|
"occur. You have likely hit a NDB Bug. Please "
|
||||||
|
"file a bug.");
|
||||||
|
DBUG_PRINT("error",("This timeout should never occure, execute()"));
|
||||||
|
g_eventLogger.error("Forcibly trying to rollback txn (%p"
|
||||||
|
") to try to clean up data node resources.",
|
||||||
|
this);
|
||||||
|
executeNoBlobs(NdbTransaction::Rollback);
|
||||||
|
theError.code = 4012;
|
||||||
|
theError.status= NdbError::PermanentError;
|
||||||
|
theError.classification= NdbError::TimeoutExpired;
|
||||||
|
setOperationErrorCodeAbort(4012); // ndbd timeout
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
}//if
|
}//if
|
||||||
|
|
||||||
@ -550,7 +565,12 @@ NdbTransaction::executeAsynchPrepare( ExecType aTypeOfExec,
|
|||||||
*/
|
*/
|
||||||
if (theError.code != 0)
|
if (theError.code != 0)
|
||||||
DBUG_PRINT("enter", ("Resetting error %d on execute", theError.code));
|
DBUG_PRINT("enter", ("Resetting error %d on execute", theError.code));
|
||||||
theError.code = 0;
|
/**
|
||||||
|
* for timeout (4012) we want sendROLLBACK to behave differently.
|
||||||
|
* Else, normal behaviour of reset errcode
|
||||||
|
*/
|
||||||
|
if (theError.code != 4012)
|
||||||
|
theError.code = 0;
|
||||||
NdbScanOperation* tcOp = m_theFirstScanOperation;
|
NdbScanOperation* tcOp = m_theFirstScanOperation;
|
||||||
if (tcOp != 0){
|
if (tcOp != 0){
|
||||||
// Execute any cursor operations
|
// Execute any cursor operations
|
||||||
@ -873,6 +893,12 @@ NdbTransaction::sendROLLBACK() // Send a TCROLLBACKREQ signal;
|
|||||||
tSignal.setData(theTCConPtr, 1);
|
tSignal.setData(theTCConPtr, 1);
|
||||||
tSignal.setData(tTransId1, 2);
|
tSignal.setData(tTransId1, 2);
|
||||||
tSignal.setData(tTransId2, 3);
|
tSignal.setData(tTransId2, 3);
|
||||||
|
if(theError.code == 4012)
|
||||||
|
{
|
||||||
|
g_eventLogger.error("Sending TCROLLBACKREQ with Bad flag");
|
||||||
|
tSignal.setLength(tSignal.getLength() + 1); // + flags
|
||||||
|
tSignal.setData(0x1, 4); // potentially bad data
|
||||||
|
}
|
||||||
tReturnCode = tp->sendSignal(&tSignal,theDBnode);
|
tReturnCode = tp->sendSignal(&tSignal,theDBnode);
|
||||||
if (tReturnCode != -1) {
|
if (tReturnCode != -1) {
|
||||||
theSendStatus = sendTC_ROLLBACK;
|
theSendStatus = sendTC_ROLLBACK;
|
||||||
|
@ -173,6 +173,8 @@ ErrorBundle ErrorCodes[] = {
|
|||||||
{ 4022, TR, "Out of Send Buffer space in NDB API" },
|
{ 4022, TR, "Out of Send Buffer space in NDB API" },
|
||||||
{ 4032, TR, "Out of Send Buffer space in NDB API" },
|
{ 4032, TR, "Out of Send Buffer space in NDB API" },
|
||||||
{ 288, TR, "Out of index operations in transaction coordinator (increase MaxNoOfConcurrentIndexOperations)" },
|
{ 288, TR, "Out of index operations in transaction coordinator (increase MaxNoOfConcurrentIndexOperations)" },
|
||||||
|
{ 289, TR, "Out of transaction buffer memory in TC (increase TransactionBufferMemory)" },
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* InsufficientSpace
|
* InsufficientSpace
|
||||||
*/
|
*/
|
||||||
|
@ -1297,6 +1297,102 @@ runBug25059(NDBT_Context* ctx, NDBT_Step* step)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tcSaveINDX_test(NDBT_Context* ctx, NDBT_Step* step, int inject_err)
|
||||||
|
{
|
||||||
|
int result= NDBT_OK;
|
||||||
|
Ndb* pNdb = GETNDB(step);
|
||||||
|
NdbDictionary::Dictionary * dict = pNdb->getDictionary();
|
||||||
|
const NdbDictionary::Index * idx = dict->getIndex(pkIdxName, *ctx->getTab());
|
||||||
|
|
||||||
|
HugoOperations ops(*ctx->getTab(), idx);
|
||||||
|
|
||||||
|
g_err << "Using INDEX: " << pkIdxName << endl;
|
||||||
|
|
||||||
|
NdbRestarter restarter;
|
||||||
|
|
||||||
|
int loops = ctx->getNumLoops();
|
||||||
|
const int rows = ctx->getNumRecords();
|
||||||
|
const int batchsize = ctx->getProperty("BatchSize", 1);
|
||||||
|
|
||||||
|
for(int bs=1; bs < loops; bs++)
|
||||||
|
{
|
||||||
|
int c= 0;
|
||||||
|
while (c++ < loops)
|
||||||
|
{
|
||||||
|
g_err << "BS " << bs << " LOOP #" << c << endl;
|
||||||
|
|
||||||
|
g_err << "inserting error on op#" << c << endl;
|
||||||
|
|
||||||
|
CHECK(ops.startTransaction(pNdb) == 0);
|
||||||
|
for(int i=1;i<=c;i++)
|
||||||
|
{
|
||||||
|
if(i==c)
|
||||||
|
{
|
||||||
|
if(restarter.insertErrorInAllNodes(inject_err)!=0)
|
||||||
|
{
|
||||||
|
g_err << "**** FAILED to insert error" << endl;
|
||||||
|
result= NDBT_FAILED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CHECK(ops.indexReadRecords(pNdb, pkIdxName, i,false,1) == 0);
|
||||||
|
if(i%bs==0 || i==c)
|
||||||
|
{
|
||||||
|
if(i<c)
|
||||||
|
{
|
||||||
|
if(ops.execute_NoCommit(pNdb, AO_IgnoreError)!=NDBT_OK)
|
||||||
|
{
|
||||||
|
g_err << "**** executeNoCommit should have succeeded" << endl;
|
||||||
|
result= NDBT_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(ops.execute_NoCommit(pNdb, AO_IgnoreError)!=289)
|
||||||
|
{
|
||||||
|
g_err << "**** executeNoCommit should have failed with 289"
|
||||||
|
<< endl;
|
||||||
|
result= NDBT_FAILED;
|
||||||
|
}
|
||||||
|
g_err << "NdbError.code= " <<
|
||||||
|
ops.getTransaction()->getNdbError().code << endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(ops.closeTransaction(pNdb) == 0);
|
||||||
|
|
||||||
|
if(restarter.insertErrorInAllNodes(0) != 0)
|
||||||
|
{
|
||||||
|
g_err << "**** Failed to error insert(0)" << endl;
|
||||||
|
return NDBT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(ops.startTransaction(pNdb) == 0);
|
||||||
|
if (ops.indexReadRecords(pNdb, pkIdxName,0,0,rows) != 0){
|
||||||
|
g_err << "**** Index read failed" << endl;
|
||||||
|
return NDBT_FAILED;
|
||||||
|
}
|
||||||
|
CHECK(ops.closeTransaction(pNdb) == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
runBug28804(NDBT_Context* ctx, NDBT_Step* step)
|
||||||
|
{
|
||||||
|
return tcSaveINDX_test(ctx, step, 8039);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
runBug28804_ATTRINFO(NDBT_Context* ctx, NDBT_Step* step)
|
||||||
|
{
|
||||||
|
return tcSaveINDX_test(ctx, step, 8051);
|
||||||
|
}
|
||||||
|
|
||||||
NDBT_TESTSUITE(testIndex);
|
NDBT_TESTSUITE(testIndex);
|
||||||
TESTCASE("CreateAll",
|
TESTCASE("CreateAll",
|
||||||
"Test that we can create all various indexes on each table\n"
|
"Test that we can create all various indexes on each table\n"
|
||||||
@ -1628,6 +1724,27 @@ TESTCASE("Bug25059",
|
|||||||
STEP(runBug25059);
|
STEP(runBug25059);
|
||||||
FINALIZER(createPkIndex_Drop);
|
FINALIZER(createPkIndex_Drop);
|
||||||
}
|
}
|
||||||
|
TESTCASE("Bug28804",
|
||||||
|
"Test behaviour on out of TransactionBufferMemory for index lookup"){
|
||||||
|
TC_PROPERTY("LoggedIndexes", (unsigned)0);
|
||||||
|
INITIALIZER(runClearTable);
|
||||||
|
INITIALIZER(createPkIndex);
|
||||||
|
INITIALIZER(runLoadTable);
|
||||||
|
STEP(runBug28804);
|
||||||
|
FINALIZER(createPkIndex_Drop);
|
||||||
|
FINALIZER(runClearTable);
|
||||||
|
}
|
||||||
|
TESTCASE("Bug28804_ATTRINFO",
|
||||||
|
"Test behaviour on out of TransactionBufferMemory for index lookup"
|
||||||
|
" in saveINDXATTRINFO"){
|
||||||
|
TC_PROPERTY("LoggedIndexes", (unsigned)0);
|
||||||
|
INITIALIZER(runClearTable);
|
||||||
|
INITIALIZER(createPkIndex);
|
||||||
|
INITIALIZER(runLoadTable);
|
||||||
|
STEP(runBug28804_ATTRINFO);
|
||||||
|
FINALIZER(createPkIndex_Drop);
|
||||||
|
FINALIZER(runClearTable);
|
||||||
|
}
|
||||||
NDBT_TESTSUITE_END(testIndex);
|
NDBT_TESTSUITE_END(testIndex);
|
||||||
|
|
||||||
int main(int argc, const char** argv){
|
int main(int argc, const char** argv){
|
||||||
|
@ -779,3 +779,11 @@ cmd: DbAsyncGenerator
|
|||||||
args: -time 60 -p 1 -proc 25
|
args: -time 60 -p 1 -proc 25
|
||||||
type: bench
|
type: bench
|
||||||
|
|
||||||
|
max-time: 180
|
||||||
|
cmd: testIndex
|
||||||
|
args: -n Bug28804 T1 T3
|
||||||
|
|
||||||
|
max-time: 180
|
||||||
|
cmd: testIndex
|
||||||
|
args: -n Bug28804_ATTRINFO T1 T3
|
||||||
|
|
||||||
|
@ -1758,9 +1758,15 @@ int ha_ndbcluster::unique_index_read(const byte *key,
|
|||||||
|
|
||||||
if (execute_no_commit_ie(this,trans,false) != 0)
|
if (execute_no_commit_ie(this,trans,false) != 0)
|
||||||
{
|
{
|
||||||
table->status= STATUS_NOT_FOUND;
|
int err= ndb_err(trans);
|
||||||
DBUG_RETURN(ndb_err(trans));
|
if(err==HA_ERR_KEY_NOT_FOUND)
|
||||||
|
table->status= STATUS_NOT_FOUND;
|
||||||
|
else
|
||||||
|
table->status= STATUS_GARBAGE;
|
||||||
|
|
||||||
|
DBUG_RETURN(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The value have now been fetched from NDB
|
// The value have now been fetched from NDB
|
||||||
unpack_record(buf);
|
unpack_record(buf);
|
||||||
table->status= 0;
|
table->status= 0;
|
||||||
@ -3310,6 +3316,8 @@ int ha_ndbcluster::info(uint flag)
|
|||||||
DBUG_PRINT("info", ("HA_STATUS_AUTO"));
|
DBUG_PRINT("info", ("HA_STATUS_AUTO"));
|
||||||
if (m_table && table->found_next_number_field)
|
if (m_table && table->found_next_number_field)
|
||||||
{
|
{
|
||||||
|
if ((my_errno= check_ndb_connection()))
|
||||||
|
DBUG_RETURN(my_errno);
|
||||||
Ndb *ndb= get_ndb();
|
Ndb *ndb= get_ndb();
|
||||||
|
|
||||||
Uint64 auto_increment_value64;
|
Uint64 auto_increment_value64;
|
||||||
@ -6462,7 +6470,8 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
|
|||||||
if (uses_blob_value(m_retrieve_all_fields) ||
|
if (uses_blob_value(m_retrieve_all_fields) ||
|
||||||
(cur_index_type == UNIQUE_INDEX &&
|
(cur_index_type == UNIQUE_INDEX &&
|
||||||
has_null_in_unique_index(active_index) &&
|
has_null_in_unique_index(active_index) &&
|
||||||
null_value_index_search(ranges, ranges+range_count, buffer)))
|
null_value_index_search(ranges, ranges+range_count, buffer))
|
||||||
|
|| m_delete_cannot_batch || m_update_cannot_batch)
|
||||||
{
|
{
|
||||||
m_disable_multi_read= TRUE;
|
m_disable_multi_read= TRUE;
|
||||||
DBUG_RETURN(handler::read_multi_range_first(found_range_p,
|
DBUG_RETURN(handler::read_multi_range_first(found_range_p,
|
||||||
|
Reference in New Issue
Block a user