diff --git a/mysql-test/r/ndb_lock.result b/mysql-test/r/ndb_lock.result index 3b433023843..2c212b9cfef 100644 --- a/mysql-test/r/ndb_lock.result +++ b/mysql-test/r/ndb_lock.result @@ -64,17 +64,26 @@ pk u o insert into t1 values (1,1,1); drop table t1; 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); +insert into t1 values (1,'one',1); begin; select * from t1 where x = 1 for update; x y z 1 one 1 begin; +select * from t1 where x = 1 for update; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +rollback; +rollback; +insert into t1 values (2,'two',2),(3,"three",3); +begin; +select * from t1 where x = 1 for update; +x y z +1 one 1 +select * from t1 where x = 1 for update; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction 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; commit; begin; diff --git a/mysql-test/t/ndb_lock.test b/mysql-test/t/ndb_lock.test index 54214ee72ec..48a8b77dcd7 100644 --- a/mysql-test/t/ndb_lock.test +++ b/mysql-test/t/ndb_lock.test @@ -73,7 +73,7 @@ drop table t1; 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); +insert into t1 values (1,'one',1); # PK access connection con1; @@ -82,11 +82,22 @@ 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; +rollback; +insert into t1 values (2,'two',2),(3,"three",3); +begin; +select * from t1 where x = 1 for update; + +connection con2; +--error 1205 +select * from t1 where x = 1 for update; +select * from t1 where x = 2 for update; +rollback; + connection con1; commit; diff --git a/ndb/include/ndbapi/NdbTransaction.hpp b/ndb/include/ndbapi/NdbTransaction.hpp index a6ba6a11c4d..6a80d6bf22c 100644 --- a/ndb/include/ndbapi/NdbTransaction.hpp +++ b/ndb/include/ndbapi/NdbTransaction.hpp @@ -140,6 +140,7 @@ class NdbTransaction friend class NdbIndexOperation; friend class NdbIndexScanOperation; friend class NdbBlob; + friend class ha_ndbcluster; #endif public: @@ -791,6 +792,7 @@ private: // optim: any blobs bool theBlobFlag; Uint8 thePendingBlobOps; + inline bool hasBlobOperation() { return theBlobFlag; } static void sendTC_COMMIT_ACK(NdbApiSignal *, Uint32 transId1, Uint32 transId2, diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 1af677fa754..74cdd9bee6d 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -235,6 +235,7 @@ int execute_no_commit(ha_ndbcluster *h, NdbTransaction *trans) if (m_batch_execute) return 0; #endif + h->release_completed_operations(trans); return trans->execute(NdbTransaction::NoCommit, NdbTransaction::AbortOnError, h->m_force_send); @@ -274,6 +275,7 @@ int execute_no_commit_ie(ha_ndbcluster *h, NdbTransaction *trans) if (m_batch_execute) return 0; #endif + h->release_completed_operations(trans); return trans->execute(NdbTransaction::NoCommit, NdbTransaction::AO_IgnoreError, h->m_force_send); @@ -2928,6 +2930,26 @@ int ha_ndbcluster::close_scan() NdbScanOperation *cursor= m_active_cursor ? m_active_cursor : m_multi_cursor; + 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 + */ + NdbOperation *op; + // Lock row + DBUG_PRINT("info", ("Keeping lock on scanned row")); + + if (!(op= cursor->lockTuple())) + { + m_lock_tuple= false; + ERR_RETURN(trans->getNdbError()); + } + m_ops_pending++; + } + m_lock_tuple= false; if (m_ops_pending) { /* @@ -5986,6 +6008,17 @@ int ha_ndbcluster::write_ndb_file() DBUG_RETURN(error); } +void +ha_ndbcluster::release_completed_operations(NdbConnection *trans) +{ + if (trans->hasBlobOperation()) + { + /* We are reading/writing BLOB fields, + releasing operation records is unsafe + */ + return; + } + trans->releaseCompletedOperations(); int ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, KEY_MULTI_RANGE *ranges, diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 01950c2b00f..4505c7a6e0e 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -716,6 +716,8 @@ private: bool m_force_send; ha_rows m_autoincrement_prefetch; bool m_transaction_on; + void release_completed_operations(NdbConnection*); + Ndb_cond_stack *m_cond_stack; bool m_disable_multi_read; byte *m_multi_range_result_ptr;