From 445e828785da97c7292103f539835098b2dd67b0 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 31 May 2006 15:07:11 +0200 Subject: [PATCH 1/9] Removed dead code that had been commented out --- ndb/src/ndbapi/NdbDictionaryImpl.cpp | 2 +- ndb/src/ndbapi/NdbDictionaryImpl.hpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp index 80a584651d1..c2604ebe682 100644 --- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -2147,7 +2147,7 @@ NdbDictionaryImpl::dropIndex(const char * indexName, m_error.code = 4243; return -1; } - int ret = dropIndex(*idx); //, tableName); + int ret = dropIndex(*idx); // If index stored in cache is incompatible with the one in the kernel // we must clear the cache and try again if (ret == INCOMPATIBLE_VERSION) { diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.hpp b/ndb/src/ndbapi/NdbDictionaryImpl.hpp index 8763a444503..ad587a10e1d 100644 --- a/ndb/src/ndbapi/NdbDictionaryImpl.hpp +++ b/ndb/src/ndbapi/NdbDictionaryImpl.hpp @@ -379,7 +379,6 @@ public: int createIndex(NdbIndexImpl &ix); int dropIndex(const char * indexName, const char * tableName); - // int dropIndex(NdbIndexImpl &, const char * tableName); int dropIndex(NdbIndexImpl &); NdbTableImpl * getIndexTable(NdbIndexImpl * index, NdbTableImpl * table); From 22e3b0c66f695e18269e2fc221461611fa5132c3 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 2 Jun 2006 07:26:45 +0200 Subject: [PATCH 2/9] Bug #18864 TRUNCATE TABLE doesn't reset AUTO_INCREMENT value on ndb table --- mysql-test/r/ndb_truncate.result | 23 ++++++++++++++++------- mysql-test/t/ndb_truncate.test | 23 ++++++++++++++--------- sql/ha_ndbcluster.cc | 6 ++++++ sql/handler.h | 3 +-- 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/mysql-test/r/ndb_truncate.result b/mysql-test/r/ndb_truncate.result index 38f3a78029c..811e5e3afeb 100644 --- a/mysql-test/r/ndb_truncate.result +++ b/mysql-test/r/ndb_truncate.result @@ -1,14 +1,23 @@ -DROP TABLE IF EXISTS t2; -CREATE TABLE t2 ( -a bigint unsigned NOT NULL PRIMARY KEY, +DROP TABLE IF EXISTS t1, t2; +CREATE TABLE t1 ( +a bigint unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY, b int unsigned not null, c int unsigned ) engine=ndbcluster; -select count(*) from t2; +select count(*) from t1; count(*) 5000 -truncate table t2; -select count(*) from t2; +select * from t1 order by a limit 2; +a b c +1 509 2500 +2 510 7 +truncate table t1; +select count(*) from t1; count(*) 0 -drop table t2; +insert into t1 values(NULL,1,1),(NULL,2,2); +select * from t1 order by a; +a b c +1 1 1 +2 2 2 +drop table t1; diff --git a/mysql-test/t/ndb_truncate.test b/mysql-test/t/ndb_truncate.test index 73af70d0d0f..a1ef4be0d48 100644 --- a/mysql-test/t/ndb_truncate.test +++ b/mysql-test/t/ndb_truncate.test @@ -2,12 +2,11 @@ -- source include/not_embedded.inc --disable_warnings -DROP TABLE IF EXISTS t2; +DROP TABLE IF EXISTS t1, t2; --enable_warnings - -CREATE TABLE t2 ( - a bigint unsigned NOT NULL PRIMARY KEY, +CREATE TABLE t1 ( + a bigint unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY, b int unsigned not null, c int unsigned ) engine=ndbcluster; @@ -20,17 +19,23 @@ let $1=500; disable_query_log; while ($1) { - eval insert into t2 values($1*10, $1+9, 5*$1), ($1*10+1, $1+10, 7),($1*10+2, $1+10, 7*$1), ($1*10+3, $1+10, 10+$1), ($1*10+4, $1+10, 70*$1), ($1*10+5, $1+10, 7), ($1*10+6, $1+10, 9), ($1*10+7, $1+299, 899), ($1*10+8, $1+10, 12), ($1*10+9, $1+10, 14*$1); + eval insert into t1 values(NULL, $1+9, 5*$1), (NULL, $1+10, 7),(NULL, $1+10, 7*$1), (NULL, $1+10, 10+$1), (NULL, $1+10, 70*$1), (NULL, $1+10, 7), (NULL, $1+10, 9), (NULL, $1+299, 899), (NULL, $1+10, 12), (NULL, $1+10, 14*$1); dec $1; } enable_query_log; -select count(*) from t2; +select count(*) from t1; -truncate table t2; +select * from t1 order by a limit 2; -select count(*) from t2; +truncate table t1; -drop table t2; +select count(*) from t1; + +insert into t1 values(NULL,1,1),(NULL,2,2); + +select * from t1 order by a; + +drop table t1; # End of 4.1 tests diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 3f2c6cbc6bb..ecbe42860ef 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -3767,6 +3767,12 @@ int ha_ndbcluster::create(const char *name, set_dbname(name2); set_tabname(name2); + if (current_thd->lex->sql_command == SQLCOM_TRUNCATE) + { + DBUG_PRINT("info", ("Dropping and re-creating table for TRUNCATE")); + if ((my_errno= delete_table(name))) + DBUG_RETURN(my_errno); + } if (create_from_engine) { /* diff --git a/sql/handler.h b/sql/handler.h index d4bb19dd7b2..e361dfd4559 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -533,8 +533,7 @@ extern TYPELIB myisam_stats_method_typelib; #define ha_supports_generate(T) (T != DB_TYPE_INNODB && \ T != DB_TYPE_BERKELEY_DB && \ T != DB_TYPE_ARCHIVE_DB && \ - T != DB_TYPE_FEDERATED_DB && \ - T != DB_TYPE_NDBCLUSTER) + T != DB_TYPE_FEDERATED_DB) bool ha_caching_allowed(THD* thd, char* table_key, uint key_length, uint8 cache_type); From 753b44e581249a243aba37bc0e6ef7d2cfcec295 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 2 Jun 2006 09:40:34 +0200 Subject: [PATCH 3/9] Bug #18864 TRUNCATE TABLE doesn't reset AUTO_INCREMENT value on ndb table --- sql/ha_ndbcluster.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 245efcc482f..dc04d60e868 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -70,7 +70,7 @@ handlerton ndbcluster_hton = { NULL, /* create_cursor_read_view */ NULL, /* set_cursor_read_view */ NULL, /* close_cursor_read_view */ - HTON_NO_FLAGS + HTON_CAN_RECREATE }; #define NDB_AUTO_INCREMENT_RETRIES 10 From 20e54ae6c579167c38ae9183e465f19ef0e60169 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 Jun 2006 16:12:38 +0200 Subject: [PATCH 4/9] Fix for Bug #18184 SELECT ... FOR UPDATE does not work..: implemented ha_ndblcuster::unlock_row() and explicitly lock all rows that are not being unlocked --- mysql-test/r/ndb_lock.result | 59 ++++++++++++++ mysql-test/t/ndb_lock.test | 76 ++++++++++++++++++ ndb/include/ndbapi/NdbIndexScanOperation.hpp | 7 +- ndb/include/ndbapi/NdbResultSet.hpp | 21 +++++ ndb/include/ndbapi/NdbScanOperation.hpp | 6 +- ndb/src/ndbapi/NdbResultSet.cpp | 11 +++ ndb/src/ndbapi/NdbScanOperation.cpp | 30 +++++--- ndb/src/ndbapi/ndberror.c | 2 +- sql/ha_ndbcluster.cc | 81 +++++++++++++++++--- sql/ha_ndbcluster.h | 2 + 10 files changed, 269 insertions(+), 26 deletions(-) diff --git a/mysql-test/r/ndb_lock.result b/mysql-test/r/ndb_lock.result index b8c2c58aac4..0267d092047 100644 --- a/mysql-test/r/ndb_lock.result +++ b/mysql-test/r/ndb_lock.result @@ -63,3 +63,62 @@ pk u o 5 5 5 insert into t1 values (1,1,1); drop table t1; +create table t1 (x integer not null primary key, y varchar(32)) engine = ndb; +insert into t1 values (1,'one'), (2,'two'),(3,"three"); +begin; +select * from t1 where x = 1 for update; +x y +1 one +begin; +select * from t1 where x = 2 for update; +x y +2 two +select * from t1 where x = 1 for update; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +rollback; +commit; +begin; +select * from t1 where y = 'one' or y = 'three' for update; +x y +3 three +1 one +begin; +select * from t1 where x = 2 for update; +x y +2 two +select * from t1 where x = 1 for update; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +rollback; +commit; +begin; +select * from t1 where x = 1 lock in share mode; +x y +1 one +begin; +select * from t1 where x = 1 lock in share mode; +x y +1 one +select * from t1 where x = 2 for update; +x y +2 two +select * from t1 where x = 1 for update; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +rollback; +commit; +begin; +select * from t1 where y = 'one' or y = 'three' lock in share mode; +x y +3 three +1 one +begin; +select * from t1 where y = 'one' lock in share mode; +x y +1 one +select * from t1 where x = 2 for update; +x y +2 two +select * from t1 where x = 1 for update; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +rollback; +commit; +drop table t1; diff --git a/mysql-test/t/ndb_lock.test b/mysql-test/t/ndb_lock.test index 6945f91ee39..42721c7d3f5 100644 --- a/mysql-test/t/ndb_lock.test +++ b/mysql-test/t/ndb_lock.test @@ -69,4 +69,80 @@ insert into t1 values (1,1,1); drop table t1; +# Lock for update + +create table t1 (x integer not null primary key, y varchar(32)) engine = ndb; + +insert into t1 values (1,'one'), (2,'two'),(3,"three"); + +# PK access +connection con1; +begin; +select * from t1 where x = 1 for update; + +connection con2; +begin; +select * from t1 where x = 2 for update; +--error 1205 +select * from t1 where x = 1 for update; +rollback; + +connection con1; +commit; + +# scan +connection con1; +begin; +select * from t1 where y = 'one' or y = 'three' for update; + +connection con2; +begin; +# Have to check with pk access here since scans take locks on +# all rows and then release them in chunks +select * from t1 where x = 2 for update; +--error 1205 +select * from t1 where x = 1 for update; +rollback; + +connection con1; +commit; + +# share locking + +# PK access +connection con1; +begin; +select * from t1 where x = 1 lock in share mode; + +connection con2; +begin; +select * from t1 where x = 1 lock in share mode; +select * from t1 where x = 2 for update; +--error 1205 +select * from t1 where x = 1 for update; +rollback; + +connection con1; +commit; + +# scan +connection con1; +begin; +select * from t1 where y = 'one' or y = 'three' lock in share mode; + +connection con2; +begin; +select * from t1 where y = 'one' lock in share mode; +# Have to check with pk access here since scans take locks on +# all rows and then release them in chunks +select * from t1 where x = 2 for update; +--error 1205 +select * from t1 where x = 1 for update; +rollback; + +connection con1; +commit; + +drop table t1; + # End of 4.1 tests diff --git a/ndb/include/ndbapi/NdbIndexScanOperation.hpp b/ndb/include/ndbapi/NdbIndexScanOperation.hpp index 7cd2daea6a6..e96f46e0f32 100644 --- a/ndb/include/ndbapi/NdbIndexScanOperation.hpp +++ b/ndb/include/ndbapi/NdbIndexScanOperation.hpp @@ -45,14 +45,15 @@ public: NdbResultSet* readTuples(LockMode = LM_Read, Uint32 batch = 0, Uint32 parallel = 0, - bool order_by = false); + bool order_by = false, + bool keyinfo = false); inline NdbResultSet* readTuples(int parallell){ - return readTuples(LM_Read, 0, parallell, false); + return readTuples(LM_Read, 0, parallell); } inline NdbResultSet* readTuplesExclusive(int parallell = 0){ - return readTuples(LM_Exclusive, 0, parallell, false); + return readTuples(LM_Exclusive, 0, parallell); } /** diff --git a/ndb/include/ndbapi/NdbResultSet.hpp b/ndb/include/ndbapi/NdbResultSet.hpp index dc0288a380c..2a196b1c6ae 100644 --- a/ndb/include/ndbapi/NdbResultSet.hpp +++ b/ndb/include/ndbapi/NdbResultSet.hpp @@ -101,6 +101,27 @@ public: */ int restart(bool forceSend = false); + /** + * Lock current row by transfering scan operation to a locking transaction. + * Use this function + * when a scan has found a record that you want to lock. + * 1. Start a new transaction. + * 2. Call the function takeOverForUpdate using your new transaction + * as parameter, all the properties of the found record will be copied + * to the new transaction. + * 3. When you execute the new transaction, the lock held by the scan will + * be transferred to the new transaction(it's taken over). + * + * @note You must have started the scan with openScanExclusive + * or explictly have requested keyinfo to be able to lock + * the found tuple. + * + * @param lockingTrans the locking transaction connection. + * @return an NdbOperation or NULL. + */ + NdbOperation* lockTuple(); + NdbOperation* lockTuple(NdbConnection* lockingTrans); + /** * Transfer scan operation to an updating transaction. Use this function * when a scan has found a record that you want to update. diff --git a/ndb/include/ndbapi/NdbScanOperation.hpp b/ndb/include/ndbapi/NdbScanOperation.hpp index f6e68dd4abe..af656720efb 100644 --- a/ndb/include/ndbapi/NdbScanOperation.hpp +++ b/ndb/include/ndbapi/NdbScanOperation.hpp @@ -64,14 +64,16 @@ public: * Tuples are not stored in NdbResultSet until execute(NoCommit) * has been executed and nextResult has been called. * + * @param keyinfo Return primary key, needed to be able to call lockTuple * @param parallel Scan parallelism * @param batch No of rows to fetch from each fragment at a time * @param LockMode Scan lock handling * @returns NdbResultSet. - * @note specifying 0 for batch and parallall means max performance + * @note specifying 0 for batch and parallell means max performance */ NdbResultSet* readTuples(LockMode = LM_Read, - Uint32 batch = 0, Uint32 parallel = 0); + Uint32 batch = 0, Uint32 parallel = 0, + bool keyinfo = false); inline NdbResultSet* readTuples(int parallell){ return readTuples(LM_Read, 0, parallell); diff --git a/ndb/src/ndbapi/NdbResultSet.cpp b/ndb/src/ndbapi/NdbResultSet.cpp index 87b304126ba..780660169b3 100644 --- a/ndb/src/ndbapi/NdbResultSet.cpp +++ b/ndb/src/ndbapi/NdbResultSet.cpp @@ -72,6 +72,17 @@ void NdbResultSet::close(bool forceSend) m_operation->closeScan(forceSend, true); } +NdbOperation* +NdbResultSet::lockTuple(){ + return lockTuple(m_operation->m_transConnection); +} + +NdbOperation* +NdbResultSet::lockTuple(NdbConnection* takeOverTrans){ + return m_operation->takeOverScanOp(NdbOperation::ReadRequest, + takeOverTrans); +} + NdbOperation* NdbResultSet::updateTuple(){ return updateTuple(m_operation->m_transConnection); diff --git a/ndb/src/ndbapi/NdbScanOperation.cpp b/ndb/src/ndbapi/NdbScanOperation.cpp index fc5a22cce17..0a39651ce28 100644 --- a/ndb/src/ndbapi/NdbScanOperation.cpp +++ b/ndb/src/ndbapi/NdbScanOperation.cpp @@ -126,7 +126,8 @@ NdbScanOperation::init(const NdbTableImpl* tab, NdbConnection* myConnection) NdbResultSet* NdbScanOperation::readTuples(NdbScanOperation::LockMode lm, Uint32 batch, - Uint32 parallel) + Uint32 parallel, + bool keyinfo) { m_ordered = 0; @@ -170,7 +171,7 @@ NdbResultSet* NdbScanOperation::readTuples(NdbScanOperation::LockMode lm, return 0; } - m_keyInfo = lockExcl ? 1 : 0; + m_keyInfo = (keyinfo || lockExcl) ? 1 : 0; bool range = false; if (m_accessTable->m_indexType == NdbDictionary::Index::OrderedIndex || @@ -956,18 +957,28 @@ NdbScanOperation::takeOverScanOp(OperationType opType, NdbConnection* pTrans){ if (newOp == NULL){ return NULL; } + if (!m_keyInfo) + { + // Cannot take over lock if no keyinfo was requested + setErrorCodeAbort(4604); + return NULL; + } pTrans->theSimpleState = 0; const Uint32 len = (tRecAttr->attrSize() * tRecAttr->arraySize() + 3)/4-1; newOp->theTupKeyLen = len; newOp->theOperationType = opType; - if (opType == DeleteRequest) { - newOp->theStatus = GetValue; - } else { - newOp->theStatus = SetValue; + switch (opType) { + case (ReadRequest): + newOp->theLockMode = theLockMode; + // Fall through + case (DeleteRequest): + newOp->theStatus = GetValue; + break; + default: + newOp->theStatus = SetValue; } - const Uint32 * src = (Uint32*)tRecAttr->aRef(); const Uint32 tScanInfo = src[len] & 0x3FFFF; const Uint32 tTakeOverNode = src[len] >> 20; @@ -1241,8 +1252,9 @@ NdbResultSet* NdbIndexScanOperation::readTuples(LockMode lm, Uint32 batch, Uint32 parallel, - bool order_by){ - NdbResultSet * rs = NdbScanOperation::readTuples(lm, batch, 0); + bool order_by, + bool keyinfo){ + NdbResultSet * rs = NdbScanOperation::readTuples(lm, batch, 0, keyinfo); if(rs && order_by){ m_ordered = 1; Uint32 cnt = m_accessTable->getNoOfColumns() - 1; diff --git a/ndb/src/ndbapi/ndberror.c b/ndb/src/ndbapi/ndberror.c index 69fc47ff70c..dea1b8c40ae 100644 --- a/ndb/src/ndbapi/ndberror.c +++ b/ndb/src/ndbapi/ndberror.c @@ -281,7 +281,7 @@ ErrorBundle ErrorCodes[] = { { 4601, AE, "Transaction is not started"}, { 4602, AE, "You must call getNdbOperation before executeScan" }, { 4603, AE, "There can only be ONE operation in a scan transaction" }, - { 4604, AE, "takeOverScanOp, opType must be UpdateRequest or DeleteRequest" }, + { 4604, AE, "takeOverScanOp, to take over a scanned row one must explicitly request keyinfo in readTuples call" }, { 4605, AE, "You may only call openScanRead or openScanExclusive once for each operation"}, { 4607, AE, "There may only be one operation in a scan transaction"}, { 4608, AE, "You can not takeOverScan unless you have used openScanExclusive"}, diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index ecbe42860ef..161b1ead2e0 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -1,4 +1,4 @@ - /* Copyright (C) 2000-2003 MySQL AB + /* Copyright (C) 2000-2003 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1043,12 +1043,23 @@ void ha_ndbcluster::release_metadata() int ha_ndbcluster::get_ndb_lock_type(enum thr_lock_type type) { + DBUG_ENTER("ha_ndbcluster::get_ndb_lock_type"); if (type >= TL_WRITE_ALLOW_WRITE) - return NdbOperation::LM_Exclusive; - else if (uses_blob_value(m_retrieve_all_fields)) - return NdbOperation::LM_Read; + { + DBUG_PRINT("info", ("Using exclusive lock")); + DBUG_RETURN(NdbOperation::LM_Exclusive); + } + else if (type == TL_READ_WITH_SHARED_LOCKS || + uses_blob_value(m_retrieve_all_fields)) + { + DBUG_PRINT("info", ("Using read lock")); + DBUG_RETURN(NdbOperation::LM_Read); + } else - return NdbOperation::LM_CommittedRead; + { + DBUG_PRINT("info", ("Using committed read")); + DBUG_RETURN(NdbOperation::LM_CommittedRead); + } } static const ulong index_type_flags[]= @@ -1384,12 +1395,35 @@ inline int ha_ndbcluster::next_result(byte *buf) if (!cursor) DBUG_RETURN(HA_ERR_END_OF_FILE); + + if (m_lock_tuple) + { + /* + Lock level m_lock.type either TL_WRITE_ALLOW_WRITE + (SELECT FOR UPDATE) or TL_READ_WITH_SHARED_LOCKS (SELECT + LOCK WITH SHARE MODE) and row was not explictly unlocked + with unlock_row() call + */ + NdbConnection *trans= m_active_trans; + NdbOperation *op; + // Lock row + DBUG_PRINT("info", ("Keeping lock on scanned row")); + + if (!(op= m_active_cursor->lockTuple())) + { + m_lock_tuple= false; + ERR_RETURN(trans->getNdbError()); + } + m_ops_pending++; + } + m_lock_tuple= false; /* If this an update or delete, call nextResult with false to process any records already cached in NdbApi */ - bool contact_ndb= m_lock.type < TL_WRITE_ALLOW_WRITE; + bool contact_ndb= m_lock.type < TL_WRITE_ALLOW_WRITE && + m_lock.type != TL_READ_WITH_SHARED_LOCKS; do { DBUG_PRINT("info", ("Call nextResult, contact_ndb: %d", contact_ndb)); /* @@ -1407,9 +1441,16 @@ inline int ha_ndbcluster::next_result(byte *buf) { // One more record found DBUG_PRINT("info", ("One more record found")); - + unpack_record(buf); table->status= 0; + /* + Explicitly lock tuple if "select for update" or + "select lock in share mode" + */ + m_lock_tuple= (m_lock.type == TL_WRITE_ALLOW_WRITE + || + m_lock.type == TL_READ_WITH_SHARED_LOCKS); DBUG_RETURN(0); } else if (check == 1 || check == 2) @@ -1444,7 +1485,6 @@ inline int ha_ndbcluster::next_result(byte *buf) contact_ndb= (check == 2); } } while (check == 2); - table->status= STATUS_NOT_FOUND; if (check == -1) DBUG_RETURN(ndb_err(trans)); @@ -1679,10 +1719,11 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key, restart= false; NdbOperation::LockMode lm= (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type); + bool need_pk = (lm == NdbOperation::LM_Read); if (!(op= trans->getNdbIndexScanOperation((NDBINDEX *) m_index[active_index].index, (const NDBTAB *) m_table)) || - !(cursor= op->readTuples(lm, 0, parallelism, sorted))) + !(cursor= op->readTuples(lm, 0, parallelism, sorted, need_pk))) ERR_RETURN(trans->getNdbError()); m_active_cursor= cursor; } else { @@ -1817,8 +1858,9 @@ int ha_ndbcluster::full_table_scan(byte *buf) NdbOperation::LockMode lm= (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type); + bool need_pk = (lm == NdbOperation::LM_Read); if (!(op=trans->getNdbScanOperation((const NDBTAB *) m_table)) || - !(cursor= op->readTuples(lm, 0, parallelism))) + !(cursor= op->readTuples(lm, 0, parallelism, need_pk))) ERR_RETURN(trans->getNdbError()); m_active_cursor= cursor; DBUG_RETURN(define_read_attrs(buf, op)); @@ -2082,6 +2124,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data) DBUG_PRINT("info", ("Calling updateTuple on cursor")); if (!(op= cursor->updateTuple())) ERR_RETURN(trans->getNdbError()); + m_lock_tuple= false; m_ops_pending++; if (uses_blob_value(FALSE)) m_blobs_pending= TRUE; @@ -2157,6 +2200,7 @@ int ha_ndbcluster::delete_row(const byte *record) DBUG_PRINT("info", ("Calling deleteTuple on cursor")); if (cursor->deleteTuple() != 0) ERR_RETURN(trans->getNdbError()); + m_lock_tuple= false; m_ops_pending++; no_uncommitted_rows_update(-1); @@ -2439,6 +2483,12 @@ int ha_ndbcluster::index_init(uint index) { DBUG_ENTER("index_init"); DBUG_PRINT("enter", ("index: %u", index)); + /* + Locks are are explicitly released in scan + unless m_lock.type == TL_READ_HIGH_PRIORITY + and no sub-sequent call to unlock_row() + */ + m_lock_tuple= false; DBUG_RETURN(handler::index_init(index)); } @@ -2683,7 +2733,7 @@ int ha_ndbcluster::close_scan() if (!cursor) DBUG_RETURN(1); - + m_lock_tuple= false; if (m_ops_pending) { /* @@ -3383,6 +3433,15 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) since ndb does not currently does not support table locking */ +void ha_ndbcluster::unlock_row() +{ + DBUG_ENTER("unlock_row"); + + DBUG_PRINT("info", ("Unlocking row")); + m_lock_tuple= false; + DBUG_VOID_RETURN; +} + int ha_ndbcluster::start_stmt(THD *thd) { int error=0; diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 83d9d87777a..313e497f9b5 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -120,6 +120,7 @@ class ha_ndbcluster: public handler int extra_opt(enum ha_extra_function operation, ulong cache_size); int reset(); int external_lock(THD *thd, int lock_type); + void unlock_row(); int start_stmt(THD *thd); const char * table_type() const; const char ** bas_ext() const; @@ -223,6 +224,7 @@ class ha_ndbcluster: public handler char m_tabname[FN_HEADLEN]; ulong m_table_flags; THR_LOCK_DATA m_lock; + bool m_lock_tuple; NDB_SHARE *m_share; NDB_INDEX_DATA m_index[MAX_KEY]; // NdbRecAttr has no reference to blob From fc9da882276b996e4d258ee33fd70188eddbf0d4 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 12 Jun 2006 09:27:04 +0200 Subject: [PATCH 5/9] Moved back comment to correct method --- sql/ha_ndbcluster.cc | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 161b1ead2e0..1031c4f635c 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -3426,11 +3426,10 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) } /* - Start a transaction for running a statement if one is not - already running in a transaction. This will be the case in - a BEGIN; COMMIT; block - When using LOCK TABLE's external_lock will start a transaction - since ndb does not currently does not support table locking + Unlock the last row read in an open scan. + Rows are unlocked by default in ndb, but + for SELECT FOR UPDATE and SELECT LOCK WIT SHARE MODE + locks are kept if unlock_row() is not called. */ void ha_ndbcluster::unlock_row() @@ -3442,6 +3441,14 @@ void ha_ndbcluster::unlock_row() DBUG_VOID_RETURN; } +/* + Start a transaction for running a statement if one is not + already running in a transaction. This will be the case in + a BEGIN; COMMIT; block + When using LOCK TABLE's external_lock will start a transaction + since ndb does not currently does not support table locking +*/ + int ha_ndbcluster::start_stmt(THD *thd) { int error=0; From a3f3696697f1ef991ea856fc9dd7bb113309555a Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 12 Jun 2006 09:28:27 +0200 Subject: [PATCH 6/9] Added lock test on index scan --- mysql-test/r/ndb_lock.result | 77 ++++++++++++++++++++++++------------ mysql-test/t/ndb_lock.test | 43 ++++++++++++++++++-- 2 files changed, 91 insertions(+), 29 deletions(-) diff --git a/mysql-test/r/ndb_lock.result b/mysql-test/r/ndb_lock.result index 0267d092047..281b02b8228 100644 --- a/mysql-test/r/ndb_lock.result +++ b/mysql-test/r/ndb_lock.result @@ -63,62 +63,89 @@ pk u o 5 5 5 insert into t1 values (1,1,1); drop table t1; -create table t1 (x integer not null primary key, y varchar(32)) engine = ndb; -insert into t1 values (1,'one'), (2,'two'),(3,"three"); +create table t1 (x integer not null primary key, y varchar(32), z integer, key(z)) engine = ndb; +insert into t1 values (1,'one',1), (2,'two',2),(3,"three",3); begin; select * from t1 where x = 1 for update; -x y -1 one +x y z +1 one 1 begin; select * from t1 where x = 2 for update; -x y -2 two +x y z +2 two 2 select * from t1 where x = 1 for update; ERROR HY000: Lock wait timeout exceeded; try restarting transaction rollback; commit; begin; select * from t1 where y = 'one' or y = 'three' for update; -x y -3 three -1 one +x y z +3 three 3 +1 one 1 begin; select * from t1 where x = 2 for update; -x y -2 two +x y z +2 two 2 select * from t1 where x = 1 for update; ERROR HY000: Lock wait timeout exceeded; try restarting transaction rollback; commit; begin; -select * from t1 where x = 1 lock in share mode; -x y -1 one +select * from t1 where z > 1 and z < 3 for update; +x y z +2 two 2 +begin; +select * from t1 where x = 1 for update; +x y z +1 one 1 +select * from t1 where x = 2 for update; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +rollback; +commit; begin; select * from t1 where x = 1 lock in share mode; -x y -1 one +x y z +1 one 1 +begin; +select * from t1 where x = 1 lock in share mode; +x y z +1 one 1 select * from t1 where x = 2 for update; -x y -2 two +x y z +2 two 2 select * from t1 where x = 1 for update; ERROR HY000: Lock wait timeout exceeded; try restarting transaction rollback; commit; begin; select * from t1 where y = 'one' or y = 'three' lock in share mode; -x y -3 three -1 one +x y z +3 three 3 +1 one 1 begin; select * from t1 where y = 'one' lock in share mode; -x y -1 one +x y z +1 one 1 select * from t1 where x = 2 for update; -x y -2 two +x y z +2 two 2 select * from t1 where x = 1 for update; ERROR HY000: Lock wait timeout exceeded; try restarting transaction rollback; commit; +begin; +select * from t1 where z > 1 and z < 3 lock in share mode; +x y z +2 two 2 +begin; +select * from t1 where z = 1 lock in share mode; +x y z +1 one 1 +select * from t1 where x = 1 for update; +x y z +1 one 1 +select * from t1 where x = 2 for update; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +rollback; +commit; drop table t1; diff --git a/mysql-test/t/ndb_lock.test b/mysql-test/t/ndb_lock.test index 42721c7d3f5..db42b7ec2dd 100644 --- a/mysql-test/t/ndb_lock.test +++ b/mysql-test/t/ndb_lock.test @@ -71,9 +71,9 @@ drop table t1; # Lock for update -create table t1 (x integer not null primary key, y varchar(32)) engine = ndb; +create table t1 (x integer not null primary key, y varchar(32), z integer, key(z)) engine = ndb; -insert into t1 values (1,'one'), (2,'two'),(3,"three"); +insert into t1 values (1,'one',1), (2,'two',2),(3,"three",3); # PK access connection con1; @@ -90,7 +90,7 @@ rollback; connection con1; commit; -# scan +# table scan connection con1; begin; select * from t1 where y = 'one' or y = 'three' for update; @@ -107,6 +107,23 @@ rollback; connection con1; commit; +# index scan +connection con1; +begin; +select * from t1 where z > 1 and z < 3 for update; + +connection con2; +begin; +# Have to check with pk access here since scans take locks on +# all rows and then release them in chunks +select * from t1 where x = 1 for update; +--error 1205 +select * from t1 where x = 2 for update; +rollback; + +connection con1; +commit; + # share locking # PK access @@ -125,7 +142,7 @@ rollback; connection con1; commit; -# scan +# table scan connection con1; begin; select * from t1 where y = 'one' or y = 'three' lock in share mode; @@ -143,6 +160,24 @@ rollback; connection con1; commit; +# index scan +connection con1; +begin; +select * from t1 where z > 1 and z < 3 lock in share mode; + +connection con2; +begin; +select * from t1 where z = 1 lock in share mode; +# Have to check with pk access here since scans take locks on +# all rows and then release them in chunks +select * from t1 where x = 1 for update; +--error 1205 +select * from t1 where x = 2 for update; +rollback; + +connection con1; +commit; + drop table t1; # End of 4.1 tests From e3a975c5d6b92f951c2e2e811c2ae4f3e6fe61a3 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 12 Jun 2006 09:37:19 +0200 Subject: [PATCH 7/9] Fix for Bug #18184 SELECT ... FOR UPDATE does not work..: Adapted to 5.0 code changes --- ndb/include/ndbapi/NdbIndexScanOperation.hpp | 7 +- ndb/include/ndbapi/NdbScanOperation.hpp | 32 ++++++- ndb/src/ndbapi/NdbScanOperation.cpp | 2 +- sql/ha_ndbcluster.cc | 91 +++++++++++++++++--- 4 files changed, 117 insertions(+), 15 deletions(-) diff --git a/ndb/include/ndbapi/NdbIndexScanOperation.hpp b/ndb/include/ndbapi/NdbIndexScanOperation.hpp index e9f92d84d1c..638ecb17779 100644 --- a/ndb/include/ndbapi/NdbIndexScanOperation.hpp +++ b/ndb/include/ndbapi/NdbIndexScanOperation.hpp @@ -61,11 +61,14 @@ public: Uint32 parallel, bool order_by, bool order_desc = false, - bool read_range_no = false) { + bool read_range_no = false, + bool keyinfo = false) { Uint32 scan_flags = (SF_OrderBy & -(Int32)order_by) | (SF_Descending & -(Int32)order_desc) | - (SF_ReadRangeNo & -(Int32)read_range_no); + (SF_ReadRangeNo & -(Int32)read_range_no) | + (SF_KeyInfo & -(Int32)keyinfo); + return readTuples(lock_mode, scan_flags, parallel); } #endif diff --git a/ndb/include/ndbapi/NdbScanOperation.hpp b/ndb/include/ndbapi/NdbScanOperation.hpp index 6a393223c4c..4a8425852b9 100644 --- a/ndb/include/ndbapi/NdbScanOperation.hpp +++ b/ndb/include/ndbapi/NdbScanOperation.hpp @@ -44,7 +44,8 @@ public: SF_TupScan = (1 << 16), // scan TUP - only LM_CommittedRead SF_OrderBy = (1 << 24), // index scan in order SF_Descending = (2 << 24), // index scan in descending order - SF_ReadRangeNo = (4 << 24) // enable @ref get_range_no + SF_ReadRangeNo = (4 << 24), // enable @ref get_range_no + SF_KeyInfo = 1 // request KeyInfo to be sent back }; /** @@ -68,7 +69,7 @@ public: */ #ifdef ndb_readtuples_impossible_overload int readTuples(LockMode lock_mode = LM_Read, - Uint32 batch = 0, Uint32 parallel = 0); + Uint32 batch = 0, Uint32 parallel = 0, bool keyinfo = false); #endif inline int readTuples(int parallell){ @@ -140,6 +141,20 @@ public: */ void close(bool forceSend = false, bool releaseOp = false); + /** + * Lock current tuple + * + * @return an NdbOperation or NULL. + */ + NdbOperation* lockCurrentTuple(); + /** + * Lock current tuple + * + * @param lockTrans Transaction that should perform the lock + * + * @return an NdbOperation or NULL. + */ + NdbOperation* lockCurrentTuple(NdbTransaction* lockTrans); /** * Update current tuple * @@ -248,6 +263,19 @@ protected: NdbRecAttr *m_curr_row; // Pointer to last returned row }; +inline +NdbOperation* +NdbScanOperation::lockCurrentTuple(){ + return lockCurrentTuple(m_transConnection); +} + +inline +NdbOperation* +NdbScanOperation::lockCurrentTuple(NdbTransaction* takeOverTrans){ + return takeOverScanOp(NdbOperation::ReadRequest, + takeOverTrans); +} + inline NdbOperation* NdbScanOperation::updateCurrentTuple(){ diff --git a/ndb/src/ndbapi/NdbScanOperation.cpp b/ndb/src/ndbapi/NdbScanOperation.cpp index 8278264fca2..7d0712e117d 100644 --- a/ndb/src/ndbapi/NdbScanOperation.cpp +++ b/ndb/src/ndbapi/NdbScanOperation.cpp @@ -160,7 +160,7 @@ NdbScanOperation::readTuples(NdbScanOperation::LockMode lm, return -1; } - m_keyInfo = (keyinfo || lockExcl) ? 1 : 0; + m_keyInfo = ((scan_flags & SF_KeyInfo) || lockExcl) ? 1 : 0; bool rangeScan = false; if (m_accessTable->m_indexType == NdbDictionary::Index::OrderedIndex) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index dc04d60e868..31a33aab5c0 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -1174,12 +1174,23 @@ void ha_ndbcluster::release_metadata() int ha_ndbcluster::get_ndb_lock_type(enum thr_lock_type type) { + DBUG_ENTER("ha_ndbcluster::get_ndb_lock_type"); if (type >= TL_WRITE_ALLOW_WRITE) - return NdbOperation::LM_Exclusive; - else if (uses_blob_value(m_retrieve_all_fields)) - return NdbOperation::LM_Read; + { + DBUG_PRINT("info", ("Using exclusive lock")); + DBUG_RETURN(NdbOperation::LM_Exclusive); + } + else if (type == TL_READ_WITH_SHARED_LOCKS || + uses_blob_value(m_retrieve_all_fields)) + { + DBUG_PRINT("info", ("Using read lock")); + DBUG_RETURN(NdbOperation::LM_Read); + } else - return NdbOperation::LM_CommittedRead; + { + DBUG_PRINT("info", ("Using committed read")); + DBUG_RETURN(NdbOperation::LM_CommittedRead); + } } static const ulong index_type_flags[]= @@ -1679,7 +1690,30 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor) int check; NdbTransaction *trans= m_active_trans; - bool contact_ndb= m_lock.type < TL_WRITE_ALLOW_WRITE; + if (m_lock_tuple) + { + /* + Lock level m_lock.type either TL_WRITE_ALLOW_WRITE + (SELECT FOR UPDATE) or TL_READ_WITH_SHARED_LOCKS (SELECT + LOCK WITH SHARE MODE) and row was not explictly unlocked + with unlock_row() call + */ + NdbConnection *trans= m_active_trans; + NdbOperation *op; + // Lock row + DBUG_PRINT("info", ("Keeping lock on scanned row")); + + if (!(op= m_active_cursor->lockCurrentTuple())) + { + m_lock_tuple= false; + ERR_RETURN(trans->getNdbError()); + } + m_ops_pending++; + } + m_lock_tuple= false; + + bool contact_ndb= m_lock.type < TL_WRITE_ALLOW_WRITE && + m_lock.type != TL_READ_WITH_SHARED_LOCKS; do { DBUG_PRINT("info", ("Call nextResult, contact_ndb: %d", contact_ndb)); /* @@ -1695,6 +1729,13 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor) if ((check= cursor->nextResult(contact_ndb, m_force_send)) == 0) { + /* + Explicitly lock tuple if "select for update" or + "select lock in share mode" + */ + m_lock_tuple= (m_lock.type == TL_WRITE_ALLOW_WRITE + || + m_lock.type == TL_READ_WITH_SHARED_LOCKS); DBUG_RETURN(0); } else if (check == 1 || check == 2) @@ -1983,10 +2024,11 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key, restart= FALSE; NdbOperation::LockMode lm= (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type); + bool need_pk = (lm == NdbOperation::LM_Read); if (!(op= trans->getNdbIndexScanOperation((NDBINDEX *) m_index[active_index].index, (const NDBTAB *) m_table)) || - op->readTuples(lm, 0, parallelism, sorted, descending)) + op->readTuples(lm, 0, parallelism, sorted, descending, need_pk)) ERR_RETURN(trans->getNdbError()); m_active_cursor= op; } else { @@ -2036,8 +2078,11 @@ int ha_ndbcluster::full_table_scan(byte *buf) NdbOperation::LockMode lm= (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type); + bool need_pk = (lm == NdbOperation::LM_Read); if (!(op=trans->getNdbScanOperation((const NDBTAB *) m_table)) || - op->readTuples(lm, 0, parallelism)) + op->readTuples(lm, + (need_pk)?NdbScanOperation::SF_KeyInfo:0, + parallelism)) ERR_RETURN(trans->getNdbError()); m_active_cursor= op; if (generate_scan_filter(m_cond_stack, op)) @@ -2327,6 +2372,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data) DBUG_PRINT("info", ("Calling updateTuple on cursor")); if (!(op= cursor->updateCurrentTuple())) ERR_RETURN(trans->getNdbError()); + m_lock_tuple= false; m_ops_pending++; if (uses_blob_value(FALSE)) m_blobs_pending= TRUE; @@ -2406,6 +2452,7 @@ int ha_ndbcluster::delete_row(const byte *record) DBUG_PRINT("info", ("Calling deleteTuple on cursor")); if (cursor->deleteCurrentTuple() != 0) ERR_RETURN(trans->getNdbError()); + m_lock_tuple= false; m_ops_pending++; no_uncommitted_rows_update(-1); @@ -2529,9 +2576,9 @@ void ha_ndbcluster::unpack_record(byte* buf) const NdbRecAttr* rec= m_value[hidden_no].rec; DBUG_ASSERT(rec); DBUG_PRINT("hidden", ("%d: %s \"%llu\"", hidden_no, - hidden_col->getName(), rec->u_64_value())); + hidden_col->getName(), rec->u_64_value())); } - //print_results(); + print_results(); #endif DBUG_VOID_RETURN; } @@ -2605,6 +2652,12 @@ int ha_ndbcluster::index_init(uint index) { DBUG_ENTER("ha_ndbcluster::index_init"); DBUG_PRINT("enter", ("index: %u", index)); + /* + Locks are are explicitly released in scan + unless m_lock.type == TL_READ_HIGH_PRIORITY + and no sub-sequent call to unlock_row() + */ + m_lock_tuple= false; DBUG_RETURN(handler::index_init(index)); } @@ -3613,6 +3666,22 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) DBUG_RETURN(error); } +/* + Unlock the last row read in an open scan. + Rows are unlocked by default in ndb, but + for SELECT FOR UPDATE and SELECT LOCK WIT SHARE MODE + locks are kept if unlock_row() is not called. +*/ + +void ha_ndbcluster::unlock_row() +{ + DBUG_ENTER("unlock_row"); + + DBUG_PRINT("info", ("Unlocking row")); + m_lock_tuple= false; + DBUG_VOID_RETURN; +} + /* Start a transaction for running a statement if one is not already running in a transaction. This will be the case in @@ -5897,6 +5966,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, byte *end_of_buffer= (byte*)buffer->buffer_end; NdbOperation::LockMode lm= (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type); + bool need_pk = (lm == NdbOperation::LM_Read); const NDBTAB *tab= (const NDBTAB *) m_table; const NDBINDEX *unique_idx= (NDBINDEX *) m_index[active_index].unique_index; const NDBINDEX *idx= (NDBINDEX *) m_index[active_index].index; @@ -5963,7 +6033,8 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, end_of_buffer -= reclength; } else if ((scanOp= m_active_trans->getNdbIndexScanOperation(idx, tab)) - &&!scanOp->readTuples(lm, 0, parallelism, sorted, FALSE, TRUE) + &&!scanOp->readTuples(lm, 0, parallelism, sorted, + FALSE, TRUE, need_pk) &&!generate_scan_filter(m_cond_stack, scanOp) &&!define_read_attrs(end_of_buffer-reclength, scanOp)) { From d043b5ea399b0053d2e00b9bdeacdea4d54755e0 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 12 Jun 2006 10:22:32 +0200 Subject: [PATCH 8/9] Fix for Bug #18184 SELECT ... FOR UPDATE does not work..: Added missing parameter for readTuples in index scan --- sql/ha_ndbcluster.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 31a33aab5c0..e2d82d9f559 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -2028,7 +2028,7 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key, if (!(op= trans->getNdbIndexScanOperation((NDBINDEX *) m_index[active_index].index, (const NDBTAB *) m_table)) || - op->readTuples(lm, 0, parallelism, sorted, descending, need_pk)) + op->readTuples(lm, 0, parallelism, sorted, descending, false, need_pk)) ERR_RETURN(trans->getNdbError()); m_active_cursor= op; } else { From 55d554bd1d3a170a8b6d23fec95e1516bb8dc433 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 12 Jun 2006 10:40:56 +0200 Subject: [PATCH 9/9] Fix for Bug #18184 SELECT ... FOR UPDATE does not work..: Skipped lock check for full table scan due to bug #20390 SELECT FOR UPDATE does not release locks of untouched rows in full table scans --- mysql-test/r/ndb_lock.result | 6 ------ mysql-test/t/ndb_lock.test | 6 ++++-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/ndb_lock.result b/mysql-test/r/ndb_lock.result index 281b02b8228..92a73830662 100644 --- a/mysql-test/r/ndb_lock.result +++ b/mysql-test/r/ndb_lock.result @@ -83,9 +83,6 @@ x y z 3 three 3 1 one 1 begin; -select * from t1 where x = 2 for update; -x y z -2 two 2 select * from t1 where x = 1 for update; ERROR HY000: Lock wait timeout exceeded; try restarting transaction rollback; @@ -126,9 +123,6 @@ begin; select * from t1 where y = 'one' lock in share mode; x y z 1 one 1 -select * from t1 where x = 2 for update; -x y z -2 two 2 select * from t1 where x = 1 for update; ERROR HY000: Lock wait timeout exceeded; try restarting transaction rollback; diff --git a/mysql-test/t/ndb_lock.test b/mysql-test/t/ndb_lock.test index db42b7ec2dd..6d3257aeb68 100644 --- a/mysql-test/t/ndb_lock.test +++ b/mysql-test/t/ndb_lock.test @@ -99,7 +99,8 @@ connection con2; begin; # Have to check with pk access here since scans take locks on # all rows and then release them in chunks -select * from t1 where x = 2 for update; +# Bug #20390 SELECT FOR UPDATE does not release locks of untouched rows in full table scans +#select * from t1 where x = 2 for update; --error 1205 select * from t1 where x = 1 for update; rollback; @@ -152,7 +153,8 @@ begin; select * from t1 where y = 'one' lock in share mode; # Have to check with pk access here since scans take locks on # all rows and then release them in chunks -select * from t1 where x = 2 for update; +# Bug #20390 SELECT FOR UPDATE does not release locks of untouched rows in full table scans +#select * from t1 where x = 2 for update; --error 1205 select * from t1 where x = 1 for update; rollback;