From 99d3926318dd03df6316a43a595d53b4ae4f40b5 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 21 Nov 2006 14:04:20 +0100 Subject: [PATCH 1/6] ndb - bug#24447 api disconnect just after SCAN_TABREQ ndb/src/kernel/blocks/dbtc/DbtcMain.cpp: 1) add error insert for faking DISCONNECT of API just after SCAN_TABREQ 2) handle error :-) ndb/test/ndbapi/testScan.cpp: Add etstcase for bug 24447 ndb/test/run-test/daily-basic-tests.txt: Add etstcase for bug 24447 --- ndb/src/kernel/blocks/dbtc/DbtcMain.cpp | 38 +++++++++++++++++++++-- ndb/test/ndbapi/testScan.cpp | 41 ++++++++++++++++++++++++- ndb/test/run-test/daily-basic-tests.txt | 4 +++ 3 files changed, 80 insertions(+), 3 deletions(-) diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index 59e6bd35baf..cdab0635dce 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -8619,6 +8619,20 @@ void Dbtc::execSCAN_TABREQ(Signal* signal) * IF ANY TO RECEIVE. **********************************************************/ scanptr.p->scanState = ScanRecord::WAIT_AI; + + if (ERROR_INSERTED(8038)) + { + /** + * Force API_FAILREQ + */ + DisconnectRep * const rep = (DisconnectRep *)signal->getDataPtrSend(); + rep->nodeId = refToNode(apiConnectptr.p->ndbapiBlockref); + rep->err = 8038; + + EXECUTE_DIRECT(CMVMI, GSN_DISCONNECT_REP, signal, 2); + CLEAR_ERROR_INSERT_VALUE; + } + return; SCAN_error_check: @@ -8706,6 +8720,7 @@ void Dbtc::initScanrec(ScanRecordPtr scanptr, jam(); ScanFragRecPtr ptr; ndbrequire(list.seize(ptr)); + ptr.p->scanFragState = ScanFragRec::IDLE; ptr.p->scanRec = scanptr.i; ptr.p->scanFragId = 0; ptr.p->m_apiPtr = cdata[i]; @@ -9457,9 +9472,17 @@ Dbtc::close_scan_req(Signal* signal, ScanRecordPtr scanPtr, bool req_received){ ScanRecord* scanP = scanPtr.p; ndbrequire(scanPtr.p->scanState != ScanRecord::IDLE); + ScanRecord::ScanState old = scanPtr.p->scanState; scanPtr.p->scanState = ScanRecord::CLOSING_SCAN; scanPtr.p->m_close_scan_req = req_received; + if (old == ScanRecord::WAIT_FRAGMENT_COUNT) + { + jam(); + scanPtr.p->scanState = old; + return; // Will continue on execDI_FCOUNTCONF + } + /** * Queue : Action * ============= : ================= @@ -9487,11 +9510,22 @@ Dbtc::close_scan_req(Signal* signal, ScanRecordPtr scanPtr, bool req_received){ ScanFragRecPtr curr = ptr; // Remove while iterating... running.next(ptr); - if(curr.p->scanFragState == ScanFragRec::WAIT_GET_PRIMCONF){ + switch(curr.p->scanFragState){ + case ScanFragRec::IDLE: + jam(); // real early abort + ndbrequire(old == ScanRecord::WAIT_AI); + running.release(curr); + continue; + case ScanFragRec::WAIT_GET_PRIMCONF: jam(); continue; + case ScanFragRec::LQH_ACTIVE: + jam(); + break; + default: + jamLine(curr.p->scanFragState); + ndbrequire(false); } - ndbrequire(curr.p->scanFragState == ScanFragRec::LQH_ACTIVE); curr.p->startFragTimer(ctcTimer); curr.p->scanFragState = ScanFragRec::LQH_ACTIVE; diff --git a/ndb/test/ndbapi/testScan.cpp b/ndb/test/ndbapi/testScan.cpp index f1018d29846..e228c9c0bd1 100644 --- a/ndb/test/ndbapi/testScan.cpp +++ b/ndb/test/ndbapi/testScan.cpp @@ -622,7 +622,7 @@ int runRestarter(NDBT_Context* ctx, NDBT_Step* step){ int nodeId = restarter.getDbNodeId(lastId); lastId = (lastId + 1) % restarter.getNumDbNodes(); - if(restarter.restartOneDbNode(nodeId) != 0){ + if(restarter.restartOneDbNode(nodeId, false, false, true) != 0){ g_err << "Failed to restartNextDbNode" << endl; result = NDBT_FAILED; break; @@ -1080,6 +1080,39 @@ int runScanRestart(NDBT_Context* ctx, NDBT_Step* step){ } +int +runBug24447(NDBT_Context* ctx, NDBT_Step* step){ + int loops = 1; //ctx->getNumLoops(); + int records = ctx->getNumRecords(); + int abort = ctx->getProperty("AbortProb", 15); + NdbRestarter restarter; + HugoTransactions hugoTrans(*ctx->getTab()); + int i = 0; + while (iisTestStopped()) + { + g_info << i++ << ": "; + + int nodeId = restarter.getRandomNotMasterNodeId(rand()); + if (nodeId == -1) + nodeId = restarter.getMasterNodeId(); + if (restarter.insertErrorInNode(nodeId, 8038) != 0) + { + ndbout << "Could not insert error in node="< Date: Tue, 21 Nov 2006 14:06:20 +0100 Subject: [PATCH 2/6] ndb - update error code list (for bug#24447) ndb/src/kernel/blocks/ERROR_codes.txt: ndb - update error code list --- ndb/src/kernel/blocks/ERROR_codes.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ndb/src/kernel/blocks/ERROR_codes.txt b/ndb/src/kernel/blocks/ERROR_codes.txt index 874c128a56d..a1472cf8376 100644 --- a/ndb/src/kernel/blocks/ERROR_codes.txt +++ b/ndb/src/kernel/blocks/ERROR_codes.txt @@ -6,7 +6,7 @@ Next DBTUP 4014 Next DBLQH 5043 Next DBDICT 6006 Next DBDIH 7178 -Next DBTC 8038 +Next DBTC 8039 Next CMVMI 9000 Next BACKUP 10022 Next DBUTIL 11002 @@ -285,6 +285,11 @@ ABORT OF TCKEYREQ 8037 : Invalid schema version in TCINDXREQ +------ + +8038 : Simulate API disconnect just after SCAN_TAB_REQ + + CMVMI ----- 9000 Set RestartOnErrorInsert to restart -n From 9e9f5fc2ce5ec25bb968c54c5b846ca01055a428 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 22 Nov 2006 14:05:40 +0100 Subject: [PATCH 3/6] ndb - bug#24461 - LockPagesInMemory ignored actually do run mlockall ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp: actually do run mlockall --- ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp b/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp index f9290a75afb..fde73b4e22a 100644 --- a/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp +++ b/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp @@ -330,9 +330,6 @@ void Cmvmi::execSTTOR(Signal* signal) signal->theData[2] = NodeInfo::REP; execOPEN_COMREQ(signal); globalData.theStartLevel = NodeState::SL_STARTED; - sendSTTORRY(signal); - } else { - jam(); if(theConfig.lockPagesInMainMemory()){ int res = NdbMem_MemLockAll(); @@ -341,7 +338,6 @@ void Cmvmi::execSTTOR(Signal* signal) warningEvent("Failed to memlock pages"); } } - sendSTTORRY(signal); } } From 55640f608db5813f381913cb541fec989ac708f1 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 22 Nov 2006 14:13:32 +0100 Subject: [PATCH 4/6] ndb - bug#24461 m ove mlock to much earlier in startphases not to affect heartbeats ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp: move mlock to much earlier in startphases not to affect heartbeats --- ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp b/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp index fde73b4e22a..6519444c364 100644 --- a/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp +++ b/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp @@ -311,6 +311,16 @@ void Cmvmi::execSTTOR(Signal* signal) jamEntry(); if (theStartPhase == 1){ jam(); + + if(theConfig.lockPagesInMainMemory()) + { + int res = NdbMem_MemLockAll(); + if(res != 0){ + g_eventLogger.warning("Failed to memlock pages"); + warningEvent("Failed to memlock pages"); + } + } + sendSTTORRY(signal); return; } else if (theStartPhase == 3) { @@ -330,14 +340,6 @@ void Cmvmi::execSTTOR(Signal* signal) signal->theData[2] = NodeInfo::REP; execOPEN_COMREQ(signal); globalData.theStartLevel = NodeState::SL_STARTED; - - if(theConfig.lockPagesInMainMemory()){ - int res = NdbMem_MemLockAll(); - if(res != 0){ - g_eventLogger.warning("Failed to memlock pages"); - warningEvent("Failed to memlock pages"); - } - } sendSTTORRY(signal); } } From a908db7b74eb5925bf3ca6ab019b44df346bf4f8 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 11 Apr 2007 08:23:16 +0200 Subject: [PATCH 5/6] ndb - bug#27748 fix commit trigger on multi-update ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp: fix commit trigger on multi-update --- ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp b/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp index e16d3df6d8d..37bf33f0313 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp @@ -390,6 +390,7 @@ Dbtup::commitRecord(Signal* signal, fragptr.p = regFragPtr; tabptr.p = regTabPtr; + Uint32 hashValue = firstOpPtr.p->hashValue; if (opType == ZINSERT_DELETE) { ljam(); @@ -412,6 +413,7 @@ Dbtup::commitRecord(Signal* signal, //-------------------------------------------------------------------- Uint32 saveOpType = regOperPtr->optype; regOperPtr->optype = ZINSERT; + regOperPtr->hashValue = hashValue; operPtr.p = regOperPtr; checkDetachedTriggers(signal, @@ -444,6 +446,8 @@ Dbtup::commitRecord(Signal* signal, befOpPtr.p->changeMask.clear(); befOpPtr.p->changeMask.bitOR(attributeMask); befOpPtr.p->gci = regOperPtr->gci; + befOpPtr.p->optype = ZUPDATE; + befOpPtr.p->hashValue = hashValue; befOpPtr.p->optype = opType; operPtr.p = befOpPtr.p; @@ -478,11 +482,13 @@ Dbtup::commitRecord(Signal* signal, Uint32 fragPageId = befOpPtr.p->fragPageId; Uint32 pageIndex = befOpPtr.p->pageIndex; + befOpPtr.p->optype = ZDELETE; befOpPtr.p->realPageId = befOpPtr.p->realPageIdC; befOpPtr.p->pageOffset = befOpPtr.p->pageOffsetC; befOpPtr.p->fragPageId = befOpPtr.p->fragPageIdC; befOpPtr.p->pageIndex = befOpPtr.p->pageIndexC; befOpPtr.p->gci = regOperPtr->gci; + befOpPtr.p->hashValue = hashValue; befOpPtr.p->optype = opType; operPtr.p = befOpPtr.p; From aa051961c9ac4629fd7dca9f236172e47660bbeb Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 11 Apr 2007 11:41:12 -0700 Subject: [PATCH 6/6] Fixed bug #27484: a crash when incompatible row expressions with nested rows are used as arguments of the IN predicate. Added a function to check compatibility of row expressions. Made sure that this function to be called for Item_func_in objects by fix_length_and_dec(). mysql-test/r/row.result: Added a test case for bug #27484. mysql-test/t/row.test: Added a test case for bug #27484. --- mysql-test/r/row.result | 18 ++++++++++++ mysql-test/t/row.test | 25 ++++++++++++++++ sql/item_cmpfunc.cc | 65 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 104 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/row.result b/mysql-test/r/row.result index 76d6fa13766..1c1c4809f36 100644 --- a/mysql-test/r/row.result +++ b/mysql-test/r/row.result @@ -170,3 +170,21 @@ ROW(2,10) <=> ROW(3,4) SELECT ROW(NULL,10) <=> ROW(3,NULL); ROW(NULL,10) <=> ROW(3,NULL) 0 +SELECT ROW(1,ROW(2,3)) IN (ROW(1,ROW(2,3)),ROW(1,1)); +ERROR 21000: Operand should contain 2 column(s) +SELECT ROW(1,ROW(2,3)) IN (ROW(1,ROW(2,3)),ROW(1,1),ROW(1,ROW(2,3))); +ERROR 21000: Operand should contain 2 column(s) +SELECT ROW(1,ROW(2,3)) IN (ROW(1,ROW(2,3)),ROW(1,ROW(2,2,2))); +ERROR 21000: Operand should contain 2 column(s) +SELECT ROW(1,ROW(2,3,4)) IN (ROW(1,ROW(2,3,4)),ROW(1,ROW(2,2))); +ERROR 21000: Operand should contain 3 column(s) +SELECT ROW(1,ROW(2,3)) IN (ROW(1,ROW(2,3)),(SELECT 1,1)); +ERROR 21000: Operand should contain 2 column(s) +SELECT ROW(1,ROW(2,3)) IN (ROW(1,ROW(2,3)),(SELECT 1,1),ROW(1,ROW(2,4))); +ERROR 21000: Operand should contain 2 column(s) +SELECT ROW(1,ROW(2,3)) IN ((SELECT 1,1),ROW(1,ROW(2,3))); +ERROR 21000: Operand should contain 2 column(s) +SELECT ROW(2,1) IN (ROW(21,2),ROW(ROW(1,1,3),0)); +ERROR 21000: Operand should contain 1 column(s) +SELECT ROW(2,1) IN (ROW(ROW(1,1,3),0),ROW(21,2)); +ERROR 21000: Operand should contain 1 column(s) diff --git a/mysql-test/t/row.test b/mysql-test/t/row.test index d8d9a244134..6c66d45b942 100644 --- a/mysql-test/t/row.test +++ b/mysql-test/t/row.test @@ -83,4 +83,29 @@ drop table t1; SELECT ROW(2,10) <=> ROW(3,4); SELECT ROW(NULL,10) <=> ROW(3,NULL); +# +# Bug #27484: nested row expressions in IN predicate +# + +--error 1241 +SELECT ROW(1,ROW(2,3)) IN (ROW(1,ROW(2,3)),ROW(1,1)); +--error 1241 +SELECT ROW(1,ROW(2,3)) IN (ROW(1,ROW(2,3)),ROW(1,1),ROW(1,ROW(2,3))); +--error 1241 +SELECT ROW(1,ROW(2,3)) IN (ROW(1,ROW(2,3)),ROW(1,ROW(2,2,2))); +--error 1241 +SELECT ROW(1,ROW(2,3,4)) IN (ROW(1,ROW(2,3,4)),ROW(1,ROW(2,2))); + +--error 1241 +SELECT ROW(1,ROW(2,3)) IN (ROW(1,ROW(2,3)),(SELECT 1,1)); +--error 1241 +SELECT ROW(1,ROW(2,3)) IN (ROW(1,ROW(2,3)),(SELECT 1,1),ROW(1,ROW(2,4))); +--error 1241 +SELECT ROW(1,ROW(2,3)) IN ((SELECT 1,1),ROW(1,ROW(2,3))); + +--error 1241 +SELECT ROW(2,1) IN (ROW(21,2),ROW(ROW(1,1,3),0)); +--error 1241 +SELECT ROW(2,1) IN (ROW(ROW(1,1,3),0),ROW(21,2)); + # End of 4.1 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 4d54dfc2b39..ce3096da778 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -61,6 +61,42 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems) } +/* + Compare row signature of two expressions + + SYNOPSIS: + cmp_row_type() + item1 the first expression + item2 the second expression + + DESCRIPTION + The function checks that two expressions have compatible row signatures + i.e. that the number of columns they return are the same and that if they + are both row expressions then each component from the first expression has + a row signature compatible with the signature of the corresponding component + of the second expression. + + RETURN VALUES + 1 type incompatibility has been detected + 0 otherwise +*/ + +static int cmp_row_type(Item* item1, Item* item2) +{ + uint n= item1->cols(); + if (item2->check_cols(n)) + return 1; + for (uint i=0; iel(i)->check_cols(item1->el(i)->cols()) || + (item1->el(i)->result_type() == ROW_RESULT && + cmp_row_type(item1->el(i), item2->el(i)))) + return 1; + } + return 0; +} + + /* Aggregates result types from the array of items. @@ -75,14 +111,32 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems) This function aggregates result types from the array of items. Found type supposed to be used later for comparison of values of these items. Aggregation itself is performed by the item_cmp_type() function. + The function also checks compatibility of row signatures for the + submitted items (see the spec for the cmp_row_type function). + + RETURN VALUES + 1 type incompatibility has been detected + 0 otherwise */ -static void agg_cmp_type(THD *thd, Item_result *type, Item **items, uint nitems) +static int agg_cmp_type(THD *thd, Item_result *type, Item **items, uint nitems) { uint i; type[0]= items[0]->result_type(); for (i= 1 ; i < nitems ; i++) + { type[0]= item_cmp_type(type[0], items[i]->result_type()); + /* + When aggregating types of two row expressions we have to check + that they have the same cardinality and that each component + of the first row expression has a compatible row signature with + the signature of the corresponding component of the second row + expression. + */ + if (type[0] == ROW_RESULT && cmp_row_type(items[0], items[i])) + return 1; // error found: invalid usage of rows + } + return 0; } static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, @@ -984,7 +1038,8 @@ void Item_func_between::fix_length_and_dec() */ if (!args[0] || !args[1] || !args[2]) return; - agg_cmp_type(thd, &cmp_type, args, 3); + if ( agg_cmp_type(thd, &cmp_type, args, 3)) + return; if (cmp_type == STRING_RESULT && agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV)) return; @@ -1532,7 +1587,8 @@ void Item_func_case::fix_length_and_dec() for (nagg= 0; nagg < ncases/2 ; nagg++) agg[nagg+1]= args[nagg*2]; nagg++; - agg_cmp_type(current_thd, &cmp_type, agg, nagg); + if (agg_cmp_type(current_thd, &cmp_type, agg, nagg)) + return; if ((cmp_type == STRING_RESULT) && agg_arg_charsets(cmp_collation, agg, nagg, MY_COLL_CMP_CONV)) return; @@ -2013,7 +2069,8 @@ void Item_func_in::fix_length_and_dec() uint const_itm= 1; THD *thd= current_thd; - agg_cmp_type(thd, &cmp_type, args, arg_count); + if (agg_cmp_type(thd, &cmp_type, args, arg_count)) + return; if (cmp_type == STRING_RESULT && agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV))