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/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 diff --git a/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp b/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp index f9290a75afb..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,18 +340,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(); - if(res != 0){ - g_eventLogger.warning("Failed to memlock pages"); - warningEvent("Failed to memlock pages"); - } - } - sendSTTORRY(signal); } } 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/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; 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="<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))