From 5efff1feec8a84c53035fbfc793af72fa3049003 Mon Sep 17 00:00:00 2001 From: "pekka@mysql.com" <> Date: Mon, 8 May 2006 15:19:17 +0200 Subject: [PATCH 01/18] ndb - bug#14509, part 1: move autoincr pre-fetch from Ndb to local dict cache --- mysql-test/r/ndb_alter_table.result | 23 +++- mysql-test/t/ndb_alter_table.test | 17 ++- ndb/include/ndbapi/Ndb.hpp | 21 ++-- ndb/src/ndbapi/DictCache.cpp | 2 + ndb/src/ndbapi/DictCache.hpp | 5 + ndb/src/ndbapi/Ndb.cpp | 151 +++++++++++++++------------ ndb/src/ndbapi/NdbDictionaryImpl.cpp | 4 - ndb/src/ndbapi/Ndbinit.cpp | 4 - 8 files changed, 136 insertions(+), 91 deletions(-) diff --git a/mysql-test/r/ndb_alter_table.result b/mysql-test/r/ndb_alter_table.result index acb67250c26..89999eca051 100644 --- a/mysql-test/r/ndb_alter_table.result +++ b/mysql-test/r/ndb_alter_table.result @@ -1,4 +1,4 @@ -DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1, t2; drop database if exists mysqltest; CREATE TABLE t1 ( a INT NOT NULL, @@ -315,3 +315,24 @@ unique key tx1 (c002, c003, c004, c005)) engine=ndb; create index tx2 on t1 (c010, c011, c012, c013); drop table t1; +create table t1 (a int primary key auto_increment, b int) engine=ndb; +insert into t1 (b) values (101),(102),(103); +select * from t1 where a = 3; +a b +3 103 +alter table t1 rename t2; +insert into t2 (b) values (201),(202),(203); +select * from t2 where a = 6; +a b +6 203 +alter table t2 add c int; +insert into t2 (b) values (301),(302),(303); +select * from t2 where a = 9; +a b c +9 303 NULL +alter table t2 rename t1; +insert into t1 (b) values (401),(402),(403); +select * from t1 where a = 12; +a b c +12 403 NULL +drop table t1; diff --git a/mysql-test/t/ndb_alter_table.test b/mysql-test/t/ndb_alter_table.test index 0a0211c8c83..957b95c6fd9 100644 --- a/mysql-test/t/ndb_alter_table.test +++ b/mysql-test/t/ndb_alter_table.test @@ -3,7 +3,7 @@ -- source include/not_embedded.inc --disable_warnings -DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1, t2; drop database if exists mysqltest; --enable_warnings @@ -326,5 +326,20 @@ on t1 (c010, c011, c012, c013); drop table t1; +# simple test that auto incr is not lost at rename or alter +create table t1 (a int primary key auto_increment, b int) engine=ndb; +insert into t1 (b) values (101),(102),(103); +select * from t1 where a = 3; +alter table t1 rename t2; +insert into t2 (b) values (201),(202),(203); +select * from t2 where a = 6; +alter table t2 add c int; +insert into t2 (b) values (301),(302),(303); +select * from t2 where a = 9; +alter table t2 rename t1; +insert into t1 (b) values (401),(402),(403); +select * from t1 where a = 12; +drop table t1; + # End of 4.1 tests diff --git a/ndb/include/ndbapi/Ndb.hpp b/ndb/include/ndbapi/Ndb.hpp index 7e2e9037a34..b9f5aa123b8 100644 --- a/ndb/include/ndbapi/Ndb.hpp +++ b/ndb/include/ndbapi/Ndb.hpp @@ -984,6 +984,7 @@ class BaseString; class NdbEventOperation; class NdbBlob; class NdbReceiver; +class Ndb_local_table_info; template struct Ndb_free_list_t; typedef void (* NdbEventCallback)(NdbEventOperation*, Ndb*, void*); @@ -1443,15 +1444,12 @@ public: bool increase = false); bool setAutoIncrementValue(const NdbDictionary::Table * aTable, Uint64 val, bool increase = false); - Uint64 getTupleIdFromNdb(const char* aTableName, - Uint32 cacheSize = 1000); - Uint64 getTupleIdFromNdb(Uint32 aTableId, - Uint32 cacheSize = 1000); - Uint64 readTupleIdFromNdb(Uint32 aTableId); - bool setTupleIdInNdb(const char* aTableName, Uint64 val, - bool increase); - bool setTupleIdInNdb(Uint32 aTableId, Uint64 val, bool increase); - Uint64 opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op); +private: + Uint64 getTupleIdFromNdb(Ndb_local_table_info* info, Uint32 cacheSize); + Uint64 readTupleIdFromNdb(Ndb_local_table_info* info); + bool setTupleIdInNdb(Ndb_local_table_info* info, Uint64 val, bool increase); + Uint64 opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 opValue, Uint32 op); +public: /** */ @@ -1650,11 +1648,6 @@ private: Uint64 the_last_check_time; Uint64 theFirstTransId; - - // The tupleId is retreived from DB the - // tupleId is unique for each tableid. - Uint64 theFirstTupleId[2048]; - Uint64 theLastTupleId[2048]; Uint32 theRestartGCI; // the Restart GCI used by DIHNDBTAMPER diff --git a/ndb/src/ndbapi/DictCache.cpp b/ndb/src/ndbapi/DictCache.cpp index 57d9b361522..dd48ee504ed 100644 --- a/ndb/src/ndbapi/DictCache.cpp +++ b/ndb/src/ndbapi/DictCache.cpp @@ -45,6 +45,8 @@ void Ndb_local_table_info::destroy(Ndb_local_table_info *info) Ndb_local_table_info::Ndb_local_table_info(NdbTableImpl *table_impl) { m_table_impl= table_impl; + m_first_tuple_id = ~(Uint64)0; + m_last_tuple_id = ~(Uint64)0; } Ndb_local_table_info::~Ndb_local_table_info() diff --git a/ndb/src/ndbapi/DictCache.hpp b/ndb/src/ndbapi/DictCache.hpp index 2df6a139542..2d137fcd5a9 100644 --- a/ndb/src/ndbapi/DictCache.hpp +++ b/ndb/src/ndbapi/DictCache.hpp @@ -33,6 +33,11 @@ public: static Ndb_local_table_info *create(NdbTableImpl *table_impl, Uint32 sz=0); static void destroy(Ndb_local_table_info *); NdbTableImpl *m_table_impl; + + // range of cached tuple ids per thread + Uint64 m_first_tuple_id; + Uint64 m_last_tuple_id; + Uint64 m_local_data[1]; // Must be last member. Used to access extra space. private: Ndb_local_table_info(NdbTableImpl *table_impl); diff --git a/ndb/src/ndbapi/Ndb.cpp b/ndb/src/ndbapi/Ndb.cpp index 7893aaae15c..5793daf35b5 100644 --- a/ndb/src/ndbapi/Ndb.cpp +++ b/ndb/src/ndbapi/Ndb.cpp @@ -768,11 +768,12 @@ Ndb::getAutoIncrementValue(const char* aTableName, Uint32 cacheSize) Ndb_local_table_info *info= theDictionary->get_local_table_info(internal_tabname, false); - if (info == 0) + if (info == 0) { + theError.code = theDictionary->getNdbError().code; DBUG_RETURN(~(Uint64)0); - const NdbTableImpl *table= info->m_table_impl; - Uint64 tupleId = getTupleIdFromNdb(table->m_tableId, cacheSize); - DBUG_PRINT("info", ("value %ul", (ulong) tupleId)); + } + Uint64 tupleId = getTupleIdFromNdb(info, cacheSize); + DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId)); DBUG_RETURN(tupleId); } @@ -783,50 +784,54 @@ Ndb::getAutoIncrementValue(const NdbDictionary::Table * aTable, Uint32 cacheSize if (aTable == 0) DBUG_RETURN(~(Uint64)0); const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable); - Uint64 tupleId = getTupleIdFromNdb(table->m_tableId, cacheSize); - DBUG_PRINT("info", ("value %ul", (ulong) tupleId)); + const BaseString& internal_tabname = table->m_internalName; + + Ndb_local_table_info *info= + theDictionary->get_local_table_info(internal_tabname, false); + if (info == 0) { + theError.code = theDictionary->getNdbError().code; + DBUG_RETURN(~(Uint64)0); + } + Uint64 tupleId = getTupleIdFromNdb(info, cacheSize); + DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId)); DBUG_RETURN(tupleId); } -Uint64 -Ndb::getTupleIdFromNdb(const char* aTableName, Uint32 cacheSize) -{ - const NdbTableImpl* table = theDictionary->getTable(aTableName); - if (table == 0) - return ~(Uint64)0; - return getTupleIdFromNdb(table->m_tableId, cacheSize); -} - Uint64 -Ndb::getTupleIdFromNdb(Uint32 aTableId, Uint32 cacheSize) +Ndb::getTupleIdFromNdb(Ndb_local_table_info* info, Uint32 cacheSize) { DBUG_ENTER("getTupleIdFromNdb"); - if ( theFirstTupleId[aTableId] != theLastTupleId[aTableId] ) + Uint64 tupleId; + if (info->m_first_tuple_id != info->m_last_tuple_id) { - theFirstTupleId[aTableId]++; - DBUG_PRINT("info", ("next cached value %ul", - (ulong) theFirstTupleId[aTableId])); - DBUG_RETURN(theFirstTupleId[aTableId]); + assert(info->m_first_tuple_id < info->m_last_tuple_id); + tupleId = ++info->m_first_tuple_id; + DBUG_PRINT("info", ("next cached value %llu", (ulonglong)tupleId)); } - else // theFirstTupleId == theLastTupleId + else { - DBUG_PRINT("info",("reading %u values from database", - (cacheSize == 0) ? 1 : cacheSize)); - DBUG_RETURN(opTupleIdOnNdb(aTableId, (cacheSize == 0) ? 1 : cacheSize, 0)); + if (cacheSize == 0) + cacheSize = 1; + DBUG_PRINT("info", ("reading %u values from database", (uint)cacheSize)); + tupleId = opTupleIdOnNdb(info, cacheSize, 0); } + DBUG_RETURN(tupleId); } Uint64 Ndb::readAutoIncrementValue(const char* aTableName) { DBUG_ENTER("readAutoIncrementValue"); - const NdbTableImpl* table = theDictionary->getTable(aTableName); - if (table == 0) { - theError= theDictionary->getNdbError(); + BaseString internal_tabname(internalize_table_name(aTableName)); + + Ndb_local_table_info *info= + theDictionary->get_local_table_info(internal_tabname, false); + if (info == 0) { + theError.code = theDictionary->getNdbError().code; DBUG_RETURN(~(Uint64)0); } - Uint64 tupleId = readTupleIdFromNdb(table->m_tableId); - DBUG_PRINT("info", ("value %ul", (ulong) tupleId)); + Uint64 tupleId = readTupleIdFromNdb(info); + DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId)); DBUG_RETURN(tupleId); } @@ -837,19 +842,34 @@ Ndb::readAutoIncrementValue(const NdbDictionary::Table * aTable) if (aTable == 0) DBUG_RETURN(~(Uint64)0); const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable); - Uint64 tupleId = readTupleIdFromNdb(table->m_tableId); - DBUG_PRINT("info", ("value %ul", (ulong) tupleId)); + const BaseString& internal_tabname = table->m_internalName; + + Ndb_local_table_info *info= + theDictionary->get_local_table_info(internal_tabname, false); + if (info == 0) { + theError.code = theDictionary->getNdbError().code; + DBUG_RETURN(~(Uint64)0); + } + Uint64 tupleId = readTupleIdFromNdb(info); + DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId)); DBUG_RETURN(tupleId); } Uint64 -Ndb::readTupleIdFromNdb(Uint32 aTableId) +Ndb::readTupleIdFromNdb(Ndb_local_table_info* info) { - if ( theFirstTupleId[aTableId] == theLastTupleId[aTableId] ) - // Cache is empty, check next in database - return opTupleIdOnNdb(aTableId, 0, 3); - - return theFirstTupleId[aTableId] + 1; + DBUG_ENTER("Ndb::readTupleIdFromNdb"); + Uint64 tupleId; + if (info->m_first_tuple_id != info->m_last_tuple_id) + { + assert(info->m_first_tuple_id < info->m_last_tuple_id); + tupleId = info->m_first_tuple_id + 1; + } + else // Cache is empty, check next in database + { + tupleId = opTupleIdOnNdb(info, 0, 3); + } + DBUG_RETURN(tupleId); } bool @@ -861,11 +881,10 @@ Ndb::setAutoIncrementValue(const char* aTableName, Uint64 val, bool increase) Ndb_local_table_info *info= theDictionary->get_local_table_info(internal_tabname, false); if (info == 0) { - theError= theDictionary->getNdbError(); + theError.code = theDictionary->getNdbError().code; DBUG_RETURN(false); } - const NdbTableImpl* table= info->m_table_impl; - DBUG_RETURN(setTupleIdInNdb(table->m_tableId, val, increase)); + DBUG_RETURN(setTupleIdInNdb(info, val, increase)); } bool @@ -873,51 +892,49 @@ Ndb::setAutoIncrementValue(const NdbDictionary::Table * aTable, Uint64 val, bool { DBUG_ENTER("setAutoIncrementValue"); if (aTable == 0) - DBUG_RETURN(~(Uint64)0); + DBUG_RETURN(false); const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable); - DBUG_RETURN(setTupleIdInNdb(table->m_tableId, val, increase)); -} + const BaseString& internal_tabname = table->m_internalName; -bool -Ndb::setTupleIdInNdb(const char* aTableName, Uint64 val, bool increase ) -{ - DBUG_ENTER("setTupleIdInNdb(const char*, ...)"); - const NdbTableImpl* table = theDictionary->getTable(aTableName); - if (table == 0) { - theError= theDictionary->getNdbError(); + Ndb_local_table_info *info= + theDictionary->get_local_table_info(internal_tabname, false); + if (info == 0) { + theError.code = theDictionary->getNdbError().code; DBUG_RETURN(false); } - DBUG_RETURN(setTupleIdInNdb(table->m_tableId, val, increase)); + DBUG_RETURN(setTupleIdInNdb(info, val, increase)); } bool -Ndb::setTupleIdInNdb(Uint32 aTableId, Uint64 val, bool increase ) +Ndb::setTupleIdInNdb(Ndb_local_table_info* info, Uint64 val, bool increase) { - DBUG_ENTER("setTupleIdInNdb(Uint32, ...)"); + DBUG_ENTER("setTupleIdInNdb"); if (increase) { - if (theFirstTupleId[aTableId] != theLastTupleId[aTableId]) + if (info->m_first_tuple_id != info->m_last_tuple_id) { // We have a cache sequence - if (val <= theFirstTupleId[aTableId]+1) + assert(info->m_first_tuple_id < info->m_last_tuple_id); + if (val <= info->m_first_tuple_id + 1) DBUG_RETURN(false); - if (val <= theLastTupleId[aTableId]) + if (val <= info->m_last_tuple_id) { - theFirstTupleId[aTableId] = val - 1; + info->m_first_tuple_id = val - 1; DBUG_RETURN(true); } // else continue; } - DBUG_RETURN((opTupleIdOnNdb(aTableId, val, 2) == val)); + DBUG_RETURN((opTupleIdOnNdb(info, val, 2) == val)); } else - DBUG_RETURN((opTupleIdOnNdb(aTableId, val, 1) == val)); + DBUG_RETURN((opTupleIdOnNdb(info, val, 1) == val)); } Uint64 -Ndb::opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op) +Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 opValue, Uint32 op) { DBUG_ENTER("Ndb::opTupleIdOnNdb"); + Uint32 aTableId = info->m_table_impl->m_tableId; DBUG_PRINT("enter", ("table=%u value=%llu op=%u", aTableId, opValue, op)); NdbTransaction* tConnection; @@ -958,9 +975,9 @@ Ndb::opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op) tValue = tRecAttrResult->u_64_value(); - theFirstTupleId[aTableId] = tValue - opValue; - theLastTupleId[aTableId] = tValue - 1; - ret = theFirstTupleId[aTableId]; + info->m_first_tuple_id = tValue - opValue; + info->m_last_tuple_id = tValue - 1; + ret = info->m_first_tuple_id; break; case 1: tOperation->updateTuple(); @@ -970,8 +987,8 @@ Ndb::opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op) if (tConnection->execute( Commit ) == -1 ) goto error_handler; - theFirstTupleId[aTableId] = ~(Uint64)0; - theLastTupleId[aTableId] = ~(Uint64)0; + info->m_first_tuple_id = ~(Uint64)0; + info->m_last_tuple_id = ~(Uint64)0; ret = opValue; break; case 2: @@ -992,7 +1009,7 @@ Ndb::opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op) ret = ~(Uint64)0; else { - theFirstTupleId[aTableId] = theLastTupleId[aTableId] = opValue - 1; + info->m_first_tuple_id = info->m_last_tuple_id = opValue - 1; ret = opValue; } break; diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp index 6cb8e1f9a24..26517948f2d 100644 --- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -759,10 +759,6 @@ NdbDictionaryImpl::fetchGlobalTableImpl(const BaseString& internalTableName) Ndb_local_table_info::create(impl, m_local_table_data_size); m_localHash.put(internalTableName.c_str(), info); - - m_ndb.theFirstTupleId[impl->getTableId()] = ~0; - m_ndb.theLastTupleId[impl->getTableId()] = ~0; - return info; } diff --git a/ndb/src/ndbapi/Ndbinit.cpp b/ndb/src/ndbapi/Ndbinit.cpp index d4ab30aec4e..d5ad7066273 100644 --- a/ndb/src/ndbapi/Ndbinit.cpp +++ b/ndb/src/ndbapi/Ndbinit.cpp @@ -96,10 +96,6 @@ void Ndb::setup(Ndb_cluster_connection *ndb_cluster_connection, for (i = 0; i < MAX_NDB_NODES ; i++) { theConnectionArray[i] = NULL; }//forg - for (i = 0; i < 2048 ; i++) { - theFirstTupleId[i] = 0; - theLastTupleId[i] = 0; - }//for theImpl->m_dbname.assign(aDataBase); theImpl->m_schemaname.assign(aSchema); From e554f9b3d4555eaa3b4004a099ee595084610710 Mon Sep 17 00:00:00 2001 From: "pekka@mysql.com" <> Date: Thu, 11 May 2006 12:58:45 +0200 Subject: [PATCH 02/18] ndb - bug#14509 (5.0) part 2: create SYSTAB_0 row on first use --- ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp | 10 +++--- ndb/src/ndbapi/Ndb.cpp | 33 +++++++++++++++---- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp b/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp index c403aad5516..176bab0d4bf 100644 --- a/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp +++ b/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp @@ -1607,10 +1607,9 @@ void Ndbcntr::systemErrorLab(Signal* signal, int line) /* |-2048| # 1 00000001 | */ /* | : | : | */ /* | -1 | # 1 00000001 | */ -/* | 0 | 0 | */ -/* | 1 | 0 | */ -/* | : | : | */ -/* | 2047| 0 | */ +/* | 1 | 0 | tupleid sequence now created on first use */ +/* | : | : | v */ +/* | 2048| 0 | v */ /*---------------------------------------------------------------------------*/ void Ndbcntr::createSystableLab(Signal* signal, unsigned index) { @@ -1819,8 +1818,7 @@ void Ndbcntr::crSystab8Lab(Signal* signal) jam(); ckey = 1; ctransidPhase = ZFALSE; - crSystab7Lab(signal); - return; + // skip 2nd loop - tupleid sequence now created on first use }//if signal->theData[0] = ctcConnectionP; signal->theData[1] = reference(); diff --git a/ndb/src/ndbapi/Ndb.cpp b/ndb/src/ndbapi/Ndb.cpp index 5793daf35b5..c6b9f308fe8 100644 --- a/ndb/src/ndbapi/Ndb.cpp +++ b/ndb/src/ndbapi/Ndb.cpp @@ -813,6 +813,10 @@ Ndb::getTupleIdFromNdb(Ndb_local_table_info* info, Uint32 cacheSize) if (cacheSize == 0) cacheSize = 1; DBUG_PRINT("info", ("reading %u values from database", (uint)cacheSize)); + /* + * reserve next cacheSize entries in db. adds cacheSize to NEXTID + * and returns first tupleId in the new range. + */ tupleId = opTupleIdOnNdb(info, cacheSize, 0); } DBUG_RETURN(tupleId); @@ -865,8 +869,12 @@ Ndb::readTupleIdFromNdb(Ndb_local_table_info* info) assert(info->m_first_tuple_id < info->m_last_tuple_id); tupleId = info->m_first_tuple_id + 1; } - else // Cache is empty, check next in database + else { + /* + * peek at NEXTID. does not reserve it so the value is valid + * only if no other transactions are allowed. + */ tupleId = opTupleIdOnNdb(info, 0, 3); } DBUG_RETURN(tupleId); @@ -913,7 +921,6 @@ Ndb::setTupleIdInNdb(Ndb_local_table_info* info, Uint64 val, bool increase) { if (info->m_first_tuple_id != info->m_last_tuple_id) { - // We have a cache sequence assert(info->m_first_tuple_id < info->m_last_tuple_id); if (val <= info->m_first_tuple_id + 1) DBUG_RETURN(false); @@ -922,11 +929,17 @@ Ndb::setTupleIdInNdb(Ndb_local_table_info* info, Uint64 val, bool increase) info->m_first_tuple_id = val - 1; DBUG_RETURN(true); } - // else continue; } + /* + * if value <= NEXTID, do nothing. otherwise update NEXTID to + * value and set cached range to first = last = value - 1. + */ DBUG_RETURN((opTupleIdOnNdb(info, val, 2) == val)); } else + /* + * update NEXTID to given value. reset cached range. + */ DBUG_RETURN((opTupleIdOnNdb(info, val, 1) == val)); } @@ -980,7 +993,8 @@ Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 opValue, Uint32 op) ret = info->m_first_tuple_id; break; case 1: - tOperation->updateTuple(); + // create on first use + tOperation->writeTuple(); tOperation->equal("SYSKEY_0", aTableId ); tOperation->setValue("NEXTID", opValue); @@ -996,6 +1010,7 @@ Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 opValue, Uint32 op) tOperation->equal("SYSKEY_0", aTableId ); tOperation->load_const_u64(1, opValue); tOperation->read_attr("NEXTID", 2); + // compare NEXTID >= opValue tOperation->branch_le(2, 1, 0); tOperation->write_attr("NEXTID", 1); tOperation->interpret_exit_ok(); @@ -1003,10 +1018,14 @@ Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 opValue, Uint32 op) tOperation->interpret_exit_nok(9999); if ( (result = tConnection->execute( Commit )) == -1 ) - goto error_handler; - - if (result == 9999) + { + if (tConnection->theError.code != 9999) + goto error_handler; + + // NEXTID >= opValue, return ~(Uint64)0 for now since + // there is no error check... ret = ~(Uint64)0; + } else { info->m_first_tuple_id = info->m_last_tuple_id = opValue - 1; From dd58dd51a17b65f14690dd1e50865d45672a7c21 Mon Sep 17 00:00:00 2001 From: "pekka@mysql.com" <> Date: Tue, 16 May 2006 12:58:41 +0200 Subject: [PATCH 03/18] ndb - bug#14509 [related] setAutoIncrement: add error handling --- ndb/include/ndbapi/Ndb.hpp | 12 ++++---- ndb/src/ndbapi/Ndb.cpp | 39 +++++++++++++------------- ndb/src/ndbapi/NdbDictionaryImpl.cpp | 13 ++++----- ndb/tools/restore/consumer_restore.cpp | 2 +- sql/ha_ndbcluster.cc | 10 +++---- 5 files changed, 36 insertions(+), 40 deletions(-) diff --git a/ndb/include/ndbapi/Ndb.hpp b/ndb/include/ndbapi/Ndb.hpp index b9f5aa123b8..f6610b29ad4 100644 --- a/ndb/include/ndbapi/Ndb.hpp +++ b/ndb/include/ndbapi/Ndb.hpp @@ -1432,7 +1432,7 @@ public: * * @param cacheSize number of values to cache in this Ndb object * - * @return tuple id or 0 on error + * @return tuple id or ~(Uint64)0 on error. */ Uint64 getAutoIncrementValue(const char* aTableName, Uint32 cacheSize = 1); @@ -1440,14 +1440,14 @@ public: Uint32 cacheSize = 1); Uint64 readAutoIncrementValue(const char* aTableName); Uint64 readAutoIncrementValue(const NdbDictionary::Table * aTable); - bool setAutoIncrementValue(const char* aTableName, Uint64 val, - bool increase = false); - bool setAutoIncrementValue(const NdbDictionary::Table * aTable, Uint64 val, - bool increase = false); + Uint64 setAutoIncrementValue(const char* aTableName, Uint64 val, + bool increase = false); + Uint64 setAutoIncrementValue(const NdbDictionary::Table * aTable, Uint64 val, + bool increase = false); private: Uint64 getTupleIdFromNdb(Ndb_local_table_info* info, Uint32 cacheSize); Uint64 readTupleIdFromNdb(Ndb_local_table_info* info); - bool setTupleIdInNdb(Ndb_local_table_info* info, Uint64 val, bool increase); + Uint64 setTupleIdInNdb(Ndb_local_table_info* info, Uint64 val, bool increase); Uint64 opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 opValue, Uint32 op); public: diff --git a/ndb/src/ndbapi/Ndb.cpp b/ndb/src/ndbapi/Ndb.cpp index c6b9f308fe8..9c3ca5cd94a 100644 --- a/ndb/src/ndbapi/Ndb.cpp +++ b/ndb/src/ndbapi/Ndb.cpp @@ -781,8 +781,7 @@ Uint64 Ndb::getAutoIncrementValue(const NdbDictionary::Table * aTable, Uint32 cacheSize) { DBUG_ENTER("getAutoIncrementValue"); - if (aTable == 0) - DBUG_RETURN(~(Uint64)0); + assert(aTable != 0); const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable); const BaseString& internal_tabname = table->m_internalName; @@ -843,8 +842,7 @@ Uint64 Ndb::readAutoIncrementValue(const NdbDictionary::Table * aTable) { DBUG_ENTER("readAutoIncrementValue"); - if (aTable == 0) - DBUG_RETURN(~(Uint64)0); + assert(aTable != 0); const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable); const BaseString& internal_tabname = table->m_internalName; @@ -880,7 +878,7 @@ Ndb::readTupleIdFromNdb(Ndb_local_table_info* info) DBUG_RETURN(tupleId); } -bool +Uint64 Ndb::setAutoIncrementValue(const char* aTableName, Uint64 val, bool increase) { DBUG_ENTER("setAutoIncrementValue"); @@ -890,17 +888,16 @@ Ndb::setAutoIncrementValue(const char* aTableName, Uint64 val, bool increase) theDictionary->get_local_table_info(internal_tabname, false); if (info == 0) { theError.code = theDictionary->getNdbError().code; - DBUG_RETURN(false); + DBUG_RETURN(~(Uint64)0); } DBUG_RETURN(setTupleIdInNdb(info, val, increase)); } -bool +Uint64 Ndb::setAutoIncrementValue(const NdbDictionary::Table * aTable, Uint64 val, bool increase) { DBUG_ENTER("setAutoIncrementValue"); - if (aTable == 0) - DBUG_RETURN(false); + assert(aTable != 0); const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable); const BaseString& internal_tabname = table->m_internalName; @@ -908,12 +905,12 @@ Ndb::setAutoIncrementValue(const NdbDictionary::Table * aTable, Uint64 val, bool theDictionary->get_local_table_info(internal_tabname, false); if (info == 0) { theError.code = theDictionary->getNdbError().code; - DBUG_RETURN(false); + DBUG_RETURN(~(Uint64)0); } DBUG_RETURN(setTupleIdInNdb(info, val, increase)); } -bool +Uint64 Ndb::setTupleIdInNdb(Ndb_local_table_info* info, Uint64 val, bool increase) { DBUG_ENTER("setTupleIdInNdb"); @@ -923,11 +920,14 @@ Ndb::setTupleIdInNdb(Ndb_local_table_info* info, Uint64 val, bool increase) { assert(info->m_first_tuple_id < info->m_last_tuple_id); if (val <= info->m_first_tuple_id + 1) - DBUG_RETURN(false); + DBUG_RETURN(val); if (val <= info->m_last_tuple_id) { info->m_first_tuple_id = val - 1; - DBUG_RETURN(true); + DBUG_PRINT("info", + ("Setting next auto increment cached value to %llu", + (ulonglong)val)); + DBUG_RETURN(val); } } /* @@ -954,8 +954,7 @@ Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 opValue, Uint32 op) NdbOperation* tOperation= 0; // Compiler warning if not initialized Uint64 tValue; NdbRecAttr* tRecAttrResult; - int result; - Uint64 ret; + Uint64 ret = ~(Uint64)0; CHECK_STATUS_MACRO_ZERO; @@ -1017,17 +1016,17 @@ Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 opValue, Uint32 op) tOperation->def_label(0); tOperation->interpret_exit_nok(9999); - if ( (result = tConnection->execute( Commit )) == -1 ) + if (tConnection->execute( Commit ) == -1) { if (tConnection->theError.code != 9999) goto error_handler; - - // NEXTID >= opValue, return ~(Uint64)0 for now since - // there is no error check... - ret = ~(Uint64)0; + ret = opValue; } else { + DBUG_PRINT("info", + ("Setting next auto increment value (db) to %llu", + (ulonglong)opValue)); info->m_first_tuple_id = info->m_last_tuple_id = opValue - 1; ret = opValue; } diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp index 26517948f2d..b3824df48f4 100644 --- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -1742,14 +1742,11 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb, DBUG_RETURN(ret); if (haveAutoIncrement) { - if (!ndb.setAutoIncrementValue(impl.m_externalName.c_str(), - autoIncrementValue)) { - if (ndb.theError.code == 0) { - m_error.code= 4336; - ndb.theError = m_error; - } else - m_error= ndb.theError; - ret = -1; // errorcode set in initialize_autoincrement + if (ndb.setAutoIncrementValue(impl.m_externalName.c_str(), + autoIncrementValue) == ~(Uint64)0) { + DBUG_ASSERT(ndb.theError.code != 0); + m_error= ndb.theError; + ret = -1; } } } diff --git a/ndb/tools/restore/consumer_restore.cpp b/ndb/tools/restore/consumer_restore.cpp index 038d57daf97..5563c51365b 100644 --- a/ndb/tools/restore/consumer_restore.cpp +++ b/ndb/tools/restore/consumer_restore.cpp @@ -150,7 +150,7 @@ BackupRestore::finalize_table(const TableS & table){ Uint64 max_val= table.get_max_auto_val(); Uint64 auto_val= m_ndb->readAutoIncrementValue(get_table(table.m_dictTable)); if (max_val+1 > auto_val || auto_val == ~(Uint64)0) - ret= m_ndb->setAutoIncrementValue(get_table(table.m_dictTable), max_val+1, false); + ret= m_ndb->setAutoIncrementValue(get_table(table.m_dictTable), max_val+1, false) != ~(Uint64)0; } return ret; } diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 138e8c72e7a..a7f680ffc1c 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -2197,11 +2197,11 @@ int ha_ndbcluster::write_row(byte *record) Ndb *ndb= get_ndb(); Uint64 next_val= (Uint64) table->next_number_field->val_int() + 1; DBUG_PRINT("info", - ("Trying to set next auto increment value to %lu", - (ulong) next_val)); - if (ndb->setAutoIncrementValue((const NDBTAB *) m_table, next_val, TRUE)) - DBUG_PRINT("info", - ("Setting next auto increment value to %u", next_val)); + ("Trying to set next auto increment value to %llu", + (ulonglong) next_val)); + if (ndb->setAutoIncrementValue((const NDBTAB *) m_table, next_val, TRUE) + == ~(Uint64)0) + ERR_RETURN(ndb->getNdbError()); } m_skip_auto_increment= TRUE; From fc7320466a10380eb44123ad4dd60450467b4dcc Mon Sep 17 00:00:00 2001 From: "pekka@mysql.com" <> Date: Tue, 16 May 2006 16:17:30 +0200 Subject: [PATCH 04/18] ndb - bug#14509 [related] fix a return value --- ndb/src/ndbapi/Ndb.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ndb/src/ndbapi/Ndb.cpp b/ndb/src/ndbapi/Ndb.cpp index 9c3ca5cd94a..b290037a84b 100644 --- a/ndb/src/ndbapi/Ndb.cpp +++ b/ndb/src/ndbapi/Ndb.cpp @@ -934,13 +934,13 @@ Ndb::setTupleIdInNdb(Ndb_local_table_info* info, Uint64 val, bool increase) * if value <= NEXTID, do nothing. otherwise update NEXTID to * value and set cached range to first = last = value - 1. */ - DBUG_RETURN((opTupleIdOnNdb(info, val, 2) == val)); + DBUG_RETURN((opTupleIdOnNdb(info, val, 2))); } else /* * update NEXTID to given value. reset cached range. */ - DBUG_RETURN((opTupleIdOnNdb(info, val, 1) == val)); + DBUG_RETURN((opTupleIdOnNdb(info, val, 1))); } Uint64 From 54963c2e52543735734e176440c3eb141c057643 Mon Sep 17 00:00:00 2001 From: "pekka@mysql.com" <> Date: Wed, 17 May 2006 12:40:10 +0200 Subject: [PATCH 05/18] ndb - bug#14509 [related] re-do auto-incr error handling --- ndb/include/ndbapi/Ndb.hpp | 35 +++--- ndb/src/ndbapi/Ndb.cpp | 158 ++++++++++++++----------- ndb/src/ndbapi/NdbDictionaryImpl.cpp | 2 +- ndb/test/ndbapi/testDict.cpp | 10 +- ndb/tools/restore/consumer_restore.cpp | 9 +- sql/ha_ndbcluster.cc | 36 +++--- 6 files changed, 145 insertions(+), 105 deletions(-) diff --git a/ndb/include/ndbapi/Ndb.hpp b/ndb/include/ndbapi/Ndb.hpp index f6610b29ad4..f128a45f5bf 100644 --- a/ndb/include/ndbapi/Ndb.hpp +++ b/ndb/include/ndbapi/Ndb.hpp @@ -1432,23 +1432,28 @@ public: * * @param cacheSize number of values to cache in this Ndb object * - * @return tuple id or ~(Uint64)0 on error. + * @return 0 or -1 on error, and tupleId in out parameter */ - Uint64 getAutoIncrementValue(const char* aTableName, - Uint32 cacheSize = 1); - Uint64 getAutoIncrementValue(const NdbDictionary::Table * aTable, - Uint32 cacheSize = 1); - Uint64 readAutoIncrementValue(const char* aTableName); - Uint64 readAutoIncrementValue(const NdbDictionary::Table * aTable); - Uint64 setAutoIncrementValue(const char* aTableName, Uint64 val, - bool increase = false); - Uint64 setAutoIncrementValue(const NdbDictionary::Table * aTable, Uint64 val, - bool increase = false); + int getAutoIncrementValue(const char* aTableName, + Uint64 & tupleId, Uint32 cacheSize); + int getAutoIncrementValue(const NdbDictionary::Table * aTable, + Uint64 & tupleId, Uint32 cacheSize); + int readAutoIncrementValue(const char* aTableName, + Uint64 & tupleId); + int readAutoIncrementValue(const NdbDictionary::Table * aTable, + Uint64 & tupleId); + int setAutoIncrementValue(const char* aTableName, + Uint64 tupleId, bool increase); + int setAutoIncrementValue(const NdbDictionary::Table * aTable, + Uint64 tupleId, bool increase); private: - Uint64 getTupleIdFromNdb(Ndb_local_table_info* info, Uint32 cacheSize); - Uint64 readTupleIdFromNdb(Ndb_local_table_info* info); - Uint64 setTupleIdInNdb(Ndb_local_table_info* info, Uint64 val, bool increase); - Uint64 opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 opValue, Uint32 op); + int getTupleIdFromNdb(Ndb_local_table_info* info, + Uint64 & tupleId, Uint32 cacheSize); + int readTupleIdFromNdb(Ndb_local_table_info* info, + Uint64 & tupleId); + int setTupleIdInNdb(Ndb_local_table_info* info, + Uint64 tupleId, bool increase); + int opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 & opValue, Uint32 op); public: /** diff --git a/ndb/src/ndbapi/Ndb.cpp b/ndb/src/ndbapi/Ndb.cpp index b290037a84b..56d68503825 100644 --- a/ndb/src/ndbapi/Ndb.cpp +++ b/ndb/src/ndbapi/Ndb.cpp @@ -760,27 +760,30 @@ Remark: Returns a new TupleId to the application. The TupleId comes from SYSTAB_0 where SYSKEY_0 = TableId. It is initialized to (TableId << 48) + 1 in NdbcntrMain.cpp. ****************************************************************************/ -Uint64 -Ndb::getAutoIncrementValue(const char* aTableName, Uint32 cacheSize) +int +Ndb::getAutoIncrementValue(const char* aTableName, + Uint64 & tupleId, Uint32 cacheSize) { - DBUG_ENTER("getAutoIncrementValue"); + DBUG_ENTER("Ndb::getAutoIncrementValue"); BaseString internal_tabname(internalize_table_name(aTableName)); Ndb_local_table_info *info= theDictionary->get_local_table_info(internal_tabname, false); if (info == 0) { theError.code = theDictionary->getNdbError().code; - DBUG_RETURN(~(Uint64)0); + DBUG_RETURN(-1); } - Uint64 tupleId = getTupleIdFromNdb(info, cacheSize); + if (getTupleIdFromNdb(info, tupleId, cacheSize) == -1) + DBUG_RETURN(-1); DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId)); - DBUG_RETURN(tupleId); + DBUG_RETURN(0); } -Uint64 -Ndb::getAutoIncrementValue(const NdbDictionary::Table * aTable, Uint32 cacheSize) +int +Ndb::getAutoIncrementValue(const NdbDictionary::Table * aTable, + Uint64 & tupleId, Uint32 cacheSize) { - DBUG_ENTER("getAutoIncrementValue"); + DBUG_ENTER("Ndb::getAutoIncrementValue"); assert(aTable != 0); const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable); const BaseString& internal_tabname = table->m_internalName; @@ -789,18 +792,19 @@ Ndb::getAutoIncrementValue(const NdbDictionary::Table * aTable, Uint32 cacheSize theDictionary->get_local_table_info(internal_tabname, false); if (info == 0) { theError.code = theDictionary->getNdbError().code; - DBUG_RETURN(~(Uint64)0); + DBUG_RETURN(-1); } - Uint64 tupleId = getTupleIdFromNdb(info, cacheSize); + if (getTupleIdFromNdb(info, tupleId, cacheSize) == -1) + DBUG_RETURN(-1); DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId)); - DBUG_RETURN(tupleId); + DBUG_RETURN(0); } -Uint64 -Ndb::getTupleIdFromNdb(Ndb_local_table_info* info, Uint32 cacheSize) +int +Ndb::getTupleIdFromNdb(Ndb_local_table_info* info, + Uint64 & tupleId, Uint32 cacheSize) { - DBUG_ENTER("getTupleIdFromNdb"); - Uint64 tupleId; + DBUG_ENTER("Ndb::getTupleIdFromNdb"); if (info->m_first_tuple_id != info->m_last_tuple_id) { assert(info->m_first_tuple_id < info->m_last_tuple_id); @@ -816,32 +820,38 @@ Ndb::getTupleIdFromNdb(Ndb_local_table_info* info, Uint32 cacheSize) * reserve next cacheSize entries in db. adds cacheSize to NEXTID * and returns first tupleId in the new range. */ - tupleId = opTupleIdOnNdb(info, cacheSize, 0); + Uint64 opValue = cacheSize; + if (opTupleIdOnNdb(info, opValue, 0) == -1) + DBUG_RETURN(-1); + tupleId = opValue; } - DBUG_RETURN(tupleId); + DBUG_RETURN(0); } -Uint64 -Ndb::readAutoIncrementValue(const char* aTableName) +int +Ndb::readAutoIncrementValue(const char* aTableName, + Uint64 & tupleId) { - DBUG_ENTER("readAutoIncrementValue"); + DBUG_ENTER("Ndb::readAutoIncrementValue"); BaseString internal_tabname(internalize_table_name(aTableName)); Ndb_local_table_info *info= theDictionary->get_local_table_info(internal_tabname, false); if (info == 0) { theError.code = theDictionary->getNdbError().code; - DBUG_RETURN(~(Uint64)0); + DBUG_RETURN(-1); } - Uint64 tupleId = readTupleIdFromNdb(info); + if (readTupleIdFromNdb(info, tupleId) == -1) + DBUG_RETURN(-1); DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId)); - DBUG_RETURN(tupleId); + DBUG_RETURN(0); } -Uint64 -Ndb::readAutoIncrementValue(const NdbDictionary::Table * aTable) +int +Ndb::readAutoIncrementValue(const NdbDictionary::Table * aTable, + Uint64 & tupleId) { - DBUG_ENTER("readAutoIncrementValue"); + DBUG_ENTER("Ndb::readAutoIncrementValue"); assert(aTable != 0); const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable); const BaseString& internal_tabname = table->m_internalName; @@ -850,18 +860,19 @@ Ndb::readAutoIncrementValue(const NdbDictionary::Table * aTable) theDictionary->get_local_table_info(internal_tabname, false); if (info == 0) { theError.code = theDictionary->getNdbError().code; - DBUG_RETURN(~(Uint64)0); + DBUG_RETURN(-1); } - Uint64 tupleId = readTupleIdFromNdb(info); + if (readTupleIdFromNdb(info, tupleId) == -1) + DBUG_RETURN(-1); DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId)); - DBUG_RETURN(tupleId); + DBUG_RETURN(0); } -Uint64 -Ndb::readTupleIdFromNdb(Ndb_local_table_info* info) +int +Ndb::readTupleIdFromNdb(Ndb_local_table_info* info, + Uint64 & tupleId) { DBUG_ENTER("Ndb::readTupleIdFromNdb"); - Uint64 tupleId; if (info->m_first_tuple_id != info->m_last_tuple_id) { assert(info->m_first_tuple_id < info->m_last_tuple_id); @@ -873,30 +884,37 @@ Ndb::readTupleIdFromNdb(Ndb_local_table_info* info) * peek at NEXTID. does not reserve it so the value is valid * only if no other transactions are allowed. */ - tupleId = opTupleIdOnNdb(info, 0, 3); + Uint64 opValue = 0; + if (opTupleIdOnNdb(info, opValue, 3) == -1) + DBUG_RETURN(-1); + tupleId = opValue; } - DBUG_RETURN(tupleId); + DBUG_RETURN(0); } -Uint64 -Ndb::setAutoIncrementValue(const char* aTableName, Uint64 val, bool increase) +int +Ndb::setAutoIncrementValue(const char* aTableName, + Uint64 tupleId, bool increase) { - DBUG_ENTER("setAutoIncrementValue"); + DBUG_ENTER("Ndb::setAutoIncrementValue"); BaseString internal_tabname(internalize_table_name(aTableName)); Ndb_local_table_info *info= theDictionary->get_local_table_info(internal_tabname, false); if (info == 0) { theError.code = theDictionary->getNdbError().code; - DBUG_RETURN(~(Uint64)0); + DBUG_RETURN(-1); } - DBUG_RETURN(setTupleIdInNdb(info, val, increase)); + if (setTupleIdInNdb(info, tupleId, increase) == -1) + DBUG_RETURN(-1); + DBUG_RETURN(0); } -Uint64 -Ndb::setAutoIncrementValue(const NdbDictionary::Table * aTable, Uint64 val, bool increase) +int +Ndb::setAutoIncrementValue(const NdbDictionary::Table * aTable, + Uint64 tupleId, bool increase) { - DBUG_ENTER("setAutoIncrementValue"); + DBUG_ENTER("Ndb::setAutoIncrementValue"); assert(aTable != 0); const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable); const BaseString& internal_tabname = table->m_internalName; @@ -905,46 +923,54 @@ Ndb::setAutoIncrementValue(const NdbDictionary::Table * aTable, Uint64 val, bool theDictionary->get_local_table_info(internal_tabname, false); if (info == 0) { theError.code = theDictionary->getNdbError().code; - DBUG_RETURN(~(Uint64)0); + DBUG_RETURN(-1); } - DBUG_RETURN(setTupleIdInNdb(info, val, increase)); + if (setTupleIdInNdb(info, tupleId, increase) == -1) + DBUG_RETURN(-1); + DBUG_RETURN(0); } -Uint64 -Ndb::setTupleIdInNdb(Ndb_local_table_info* info, Uint64 val, bool increase) +int +Ndb::setTupleIdInNdb(Ndb_local_table_info* info, + Uint64 tupleId, bool increase) { - DBUG_ENTER("setTupleIdInNdb"); + DBUG_ENTER("Ndb::setTupleIdInNdb"); if (increase) { if (info->m_first_tuple_id != info->m_last_tuple_id) { assert(info->m_first_tuple_id < info->m_last_tuple_id); - if (val <= info->m_first_tuple_id + 1) - DBUG_RETURN(val); - if (val <= info->m_last_tuple_id) + if (tupleId <= info->m_first_tuple_id + 1) + DBUG_RETURN(0); + if (tupleId <= info->m_last_tuple_id) { - info->m_first_tuple_id = val - 1; + info->m_first_tuple_id = tupleId - 1; DBUG_PRINT("info", ("Setting next auto increment cached value to %llu", - (ulonglong)val)); - DBUG_RETURN(val); + (ulonglong)tupleId)); + DBUG_RETURN(0); } } /* - * if value <= NEXTID, do nothing. otherwise update NEXTID to - * value and set cached range to first = last = value - 1. + * if tupleId <= NEXTID, do nothing. otherwise update NEXTID to + * tupleId and set cached range to first = last = tupleId - 1. */ - DBUG_RETURN((opTupleIdOnNdb(info, val, 2))); + if (opTupleIdOnNdb(info, tupleId, 2) == -1) + DBUG_RETURN(-1); } else + { /* * update NEXTID to given value. reset cached range. */ - DBUG_RETURN((opTupleIdOnNdb(info, val, 1))); + if (opTupleIdOnNdb(info, tupleId, 1) == -1) + DBUG_RETURN(-1); + } + DBUG_RETURN(0); } -Uint64 -Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 opValue, Uint32 op) +int +Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 & opValue, Uint32 op) { DBUG_ENTER("Ndb::opTupleIdOnNdb"); Uint32 aTableId = info->m_table_impl->m_tableId; @@ -954,7 +980,6 @@ Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 opValue, Uint32 op) NdbOperation* tOperation= 0; // Compiler warning if not initialized Uint64 tValue; NdbRecAttr* tRecAttrResult; - Uint64 ret = ~(Uint64)0; CHECK_STATUS_MACRO_ZERO; @@ -989,7 +1014,7 @@ Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 opValue, Uint32 op) info->m_first_tuple_id = tValue - opValue; info->m_last_tuple_id = tValue - 1; - ret = info->m_first_tuple_id; + opValue = info->m_first_tuple_id; // out break; case 1: // create on first use @@ -1002,7 +1027,6 @@ Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 opValue, Uint32 op) info->m_first_tuple_id = ~(Uint64)0; info->m_last_tuple_id = ~(Uint64)0; - ret = opValue; break; case 2: tOperation->interpretedUpdateTuple(); @@ -1020,7 +1044,6 @@ Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 opValue, Uint32 op) { if (tConnection->theError.code != 9999) goto error_handler; - ret = opValue; } else { @@ -1028,7 +1051,6 @@ Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 opValue, Uint32 op) ("Setting next auto increment value (db) to %llu", (ulonglong)opValue)); info->m_first_tuple_id = info->m_last_tuple_id = opValue - 1; - ret = opValue; } break; case 3: @@ -1037,7 +1059,7 @@ Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 opValue, Uint32 op) tRecAttrResult = tOperation->getValue("NEXTID"); if (tConnection->execute( Commit ) == -1 ) goto error_handler; - ret = tRecAttrResult->u_64_value(); + opValue = tRecAttrResult->u_64_value(); // out break; default: goto error_handler; @@ -1049,7 +1071,7 @@ Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 opValue, Uint32 op) setDatabaseName(currentDb.c_str()); setDatabaseSchemaName(currentSchema.c_str()); - DBUG_RETURN(ret); + DBUG_RETURN(0); error_handler: theError.code = tConnection->theError.code; @@ -1063,7 +1085,7 @@ Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 opValue, Uint32 op) theError.code, tConnection ? tConnection->theError.code : -1, tOperation ? tOperation->theError.code : -1)); - DBUG_RETURN(~(Uint64)0); + DBUG_RETURN(-1); } Uint32 diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp index b3824df48f4..58452152dd9 100644 --- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -1743,7 +1743,7 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb, if (haveAutoIncrement) { if (ndb.setAutoIncrementValue(impl.m_externalName.c_str(), - autoIncrementValue) == ~(Uint64)0) { + autoIncrementValue, false) == -1) { DBUG_ASSERT(ndb.theError.code != 0); m_error= ndb.theError; ret = -1; diff --git a/ndb/test/ndbapi/testDict.cpp b/ndb/test/ndbapi/testDict.cpp index dd5846f0d62..710a47bf3dc 100644 --- a/ndb/test/ndbapi/testDict.cpp +++ b/ndb/test/ndbapi/testDict.cpp @@ -1139,9 +1139,13 @@ runCreateAutoincrementTable(NDBT_Context* ctx, NDBT_Step* step){ for (int i = 0; i < 16; i++) { - Uint64 value = myNdb->getAutoIncrementValue(tabname, 1); - - if (value != (startvalue+i)) { + Uint64 value; + if (myNdb->getAutoIncrementValue(tabname, value, 1) == -1) { + g_err << "getAutoIncrementValue failed on " << tabname << endl; + APIERROR(myNdb->getNdbError()); + return NDBT_FAILED; + } + else if (value != (startvalue+i)) { g_err << "value = " << value << " expected " << startvalue+i << endl;; APIERROR(myNdb->getNdbError()); // ret = NDBT_FAILED; diff --git a/ndb/tools/restore/consumer_restore.cpp b/ndb/tools/restore/consumer_restore.cpp index 5563c51365b..d62ca3f610a 100644 --- a/ndb/tools/restore/consumer_restore.cpp +++ b/ndb/tools/restore/consumer_restore.cpp @@ -148,9 +148,12 @@ BackupRestore::finalize_table(const TableS & table){ if (table.have_auto_inc()) { Uint64 max_val= table.get_max_auto_val(); - Uint64 auto_val= m_ndb->readAutoIncrementValue(get_table(table.m_dictTable)); - if (max_val+1 > auto_val || auto_val == ~(Uint64)0) - ret= m_ndb->setAutoIncrementValue(get_table(table.m_dictTable), max_val+1, false) != ~(Uint64)0; + Uint64 auto_val; + int r= m_ndb->readAutoIncrementValue(get_table(table.m_dictTable), auto_val); + if (r == -1 && m_ndb->getNdbError().code != 626) + ret= false; + else if (r == -1 || max_val+1 > auto_val) + ret= m_ndb->setAutoIncrementValue(get_table(table.m_dictTable), max_val+1, false) != -1; } return ret; } diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index a7f680ffc1c..3937e9b24d0 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -73,7 +73,6 @@ handlerton ndbcluster_hton = { HTON_NO_FLAGS }; -#define NDB_FAILED_AUTO_INCREMENT ~(Uint64)0 #define NDB_AUTO_INCREMENT_RETRIES 10 #define NDB_INVALID_SCHEMA_OBJECT 241 @@ -2112,14 +2111,15 @@ int ha_ndbcluster::write_row(byte *record) { // Table has hidden primary key Ndb *ndb= get_ndb(); - Uint64 auto_value= NDB_FAILED_AUTO_INCREMENT; + int ret; + Uint64 auto_value; uint retries= NDB_AUTO_INCREMENT_RETRIES; do { - auto_value= ndb->getAutoIncrementValue((const NDBTAB *) m_table); - } while (auto_value == NDB_FAILED_AUTO_INCREMENT && + ret= ndb->getAutoIncrementValue((const NDBTAB *) m_table, auto_value, 1); + } while (ret == -1 && --retries && ndb->getNdbError().status == NdbError::TemporaryError); - if (auto_value == NDB_FAILED_AUTO_INCREMENT) + if (ret == -1) ERR_RETURN(ndb->getNdbError()); if (set_hidden_key(op, table->s->fields, (const byte*)&auto_value)) ERR_RETURN(op->getNdbError()); @@ -2200,7 +2200,7 @@ int ha_ndbcluster::write_row(byte *record) ("Trying to set next auto increment value to %llu", (ulonglong) next_val)); if (ndb->setAutoIncrementValue((const NDBTAB *) m_table, next_val, TRUE) - == ~(Uint64)0) + == -1) ERR_RETURN(ndb->getNdbError()); } m_skip_auto_increment= TRUE; @@ -3047,8 +3047,14 @@ void ha_ndbcluster::info(uint flag) { Ndb *ndb= get_ndb(); - auto_increment_value= - ndb->readAutoIncrementValue((const NDBTAB *) m_table); + if (ndb->readAutoIncrementValue((const NDBTAB *) m_table, + auto_increment_value) == -1) + { + const NdbError err= ndb->getNdbError(); + sql_print_error("Error %lu in readAutoIncrementValue(): %s", + (ulong) err.code, err.message); + auto_increment_value= ~(Uint64)0; + } } } DBUG_VOID_RETURN; @@ -4360,17 +4366,17 @@ ulonglong ha_ndbcluster::get_auto_increment() m_rows_to_insert - m_rows_inserted : ((m_rows_to_insert > m_autoincrement_prefetch) ? m_rows_to_insert : m_autoincrement_prefetch)); - auto_value= NDB_FAILED_AUTO_INCREMENT; + int ret; uint retries= NDB_AUTO_INCREMENT_RETRIES; do { - auto_value= - (m_skip_auto_increment) ? - ndb->readAutoIncrementValue((const NDBTAB *) m_table) - : ndb->getAutoIncrementValue((const NDBTAB *) m_table, cache_size); - } while (auto_value == NDB_FAILED_AUTO_INCREMENT && + ret= + m_skip_auto_increment ? + ndb->readAutoIncrementValue((const NDBTAB *) m_table, auto_value) : + ndb->getAutoIncrementValue((const NDBTAB *) m_table, auto_value, cache_size); + } while (ret == -1 && --retries && ndb->getNdbError().status == NdbError::TemporaryError); - if (auto_value == NDB_FAILED_AUTO_INCREMENT) + if (ret == -1) { const NdbError err= ndb->getNdbError(); sql_print_error("Error %lu in ::get_auto_increment(): %s", From 12e53358f0845de0e31313b285653e7d75c575de Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Sat, 20 May 2006 18:54:43 -0700 Subject: [PATCH 06/18] Fixed bug #19089. When a CREATE TABLE command created a table from a materialized view id does not inherit default values from the underlying table. Moreover the temporary table used for the view materialization does not inherit those default values. In the case when the underlying table contained ENUM fields it caused misleading error messages. In other cases the created table contained wrong default values. The code was modified to ensure inheritance of default values for materialized views. --- mysql-test/r/view.result | 42 ++++++++++++++++++++++++++++++++++++++++ mysql-test/t/view.test | 31 +++++++++++++++++++++++++++++ sql/field.cc | 1 + sql/field.h | 1 + sql/sql_select.cc | 38 ++++++++++++++++++++++++++++++------ 5 files changed, 107 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 667d10cd145..4edee82029d 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2649,3 +2649,45 @@ ldt 2006-01-01 03:00:00 drop view v1, v2; drop table t1; +CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, a char(6) DEFAULT 'xxx'); +INSERT INTO t1(id) VALUES (1), (2), (3), (4); +INSERT INTO t1 VALUES (5,'yyy'), (6,'yyy'); +SELECT * FROM t1; +id a +1 xxx +2 xxx +3 xxx +4 xxx +5 yyy +6 yyy +CREATE VIEW v1(a, m) AS SELECT a, MIN(id) FROM t1 GROUP BY a; +SELECT * FROM v1; +a m +xxx 1 +yyy 5 +CREATE TABLE t2 SELECT * FROM v1; +INSERT INTO t2(m) VALUES (0); +SELECT * FROM t2; +a m +xxx 1 +yyy 5 +NULL 0 +DROP VIEW v1; +DROP TABLE t1,t2; +CREATE TABLE t1 (id int PRIMARY KEY, e ENUM('a','b') NOT NULL DEFAULT 'b'); +INSERT INTO t1(id) VALUES (1), (2), (3); +INSERT INTO t1 VALUES (4,'a'); +SELECT * FROM t1; +id e +1 b +2 b +3 b +4 a +CREATE VIEW v1(m, e) AS SELECT MIN(id), e FROM t1 GROUP BY e; +CREATE TABLE t2 SELECT * FROM v1; +SELECT * FROM t2; +m e +4 a +1 b +DROP VIEW v1; +DROP TABLE IF EXISTS t1,t2; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 8f759c2d43e..d4f7876d75f 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2512,3 +2512,34 @@ create view v2 as select convert_tz(dt, 'UTC', 'Europe/Moscow') as ldt from v1; select * from v2; drop view v1, v2; drop table t1; + +# +# Bug #19089: wrong inherited dafault values in temp table views +# + +CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, a char(6) DEFAULT 'xxx'); +INSERT INTO t1(id) VALUES (1), (2), (3), (4); +INSERT INTO t1 VALUES (5,'yyy'), (6,'yyy'); +SELECT * FROM t1; + +CREATE VIEW v1(a, m) AS SELECT a, MIN(id) FROM t1 GROUP BY a; +SELECT * FROM v1; + +CREATE TABLE t2 SELECT * FROM v1; +INSERT INTO t2(m) VALUES (0); +SELECT * FROM t2; + +DROP VIEW v1; +DROP TABLE t1,t2; + +CREATE TABLE t1 (id int PRIMARY KEY, e ENUM('a','b') NOT NULL DEFAULT 'b'); +INSERT INTO t1(id) VALUES (1), (2), (3); +INSERT INTO t1 VALUES (4,'a'); +SELECT * FROM t1; + +CREATE VIEW v1(m, e) AS SELECT MIN(id), e FROM t1 GROUP BY e; +CREATE TABLE t2 SELECT * FROM v1; +SELECT * FROM t2; + +DROP VIEW v1; +DROP TABLE IF EXISTS t1,t2; diff --git a/sql/field.cc b/sql/field.cc index bdf84c588e1..18105b31f97 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1233,6 +1233,7 @@ Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg, flags=null_ptr ? 0: NOT_NULL_FLAG; comment.str= (char*) ""; comment.length=0; + dflt_field= 0; } uint Field::offset() diff --git a/sql/field.h b/sql/field.h index f4d27e46877..1801f0d0f86 100644 --- a/sql/field.h +++ b/sql/field.h @@ -53,6 +53,7 @@ public: char *ptr; // Position to field in record uchar *null_ptr; // Byte where null_bit is + Field *dflt_field; // Field to copy default value from /* Note that you can use table->in_use as replacement for current_thd member only inside of val_*() and store() members (e.g. you can't use it in cons) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 465f41fa8de..576f4f1cb7a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8378,6 +8378,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, bool make_copy_field, uint convert_blob_length) { + Field *result; Item::Type orig_type= type; Item *orig_item= 0; @@ -8394,7 +8395,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, case Item::SUM_FUNC_ITEM: { Item_sum *item_sum=(Item_sum*) item; - Field *result= item_sum->create_tmp_field(group, table, convert_blob_length); + result= item_sum->create_tmp_field(group, table, convert_blob_length); if (!result) thd->fatal_error(); return result; @@ -8404,7 +8405,6 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, { Item_field *field= (Item_field*) item; bool orig_modify= modify_item; - Field *result; if (orig_type == Item::REF_ITEM) modify_item= 0; /* @@ -8438,6 +8438,8 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, convert_blob_length); if (orig_type == Item::REF_ITEM && orig_modify) ((Item_ref*)orig_item)->set_result_field(result); + if (field->field->eq_def(result)) + result->dflt_field= field->field; return result; } /* Fall through */ @@ -8460,10 +8462,10 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, DBUG_ASSERT(((Item_result_field*)item)->result_field); *from_field= ((Item_result_field*)item)->result_field; } - return create_tmp_field_from_item(thd, item, table, (make_copy_field ? 0 : - copy_func), modify_item, - convert_blob_length); - case Item::TYPE_HOLDER: + return create_tmp_field_from_item(thd, item, table, + (make_copy_field ? 0 : copy_func), + modify_item, convert_blob_length); + case Item::TYPE_HOLDER: return ((Item_type_holder *)item)->make_field_by_type(table); default: // Dosen't have to be stored return 0; @@ -8914,6 +8916,30 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, null_count+= (field->field_length & 7); } field->reset(); + + if (field->dflt_field && field->dflt_field->ptr) + { + /* + field->dflt_field is set only in the cases when 'field' can + inherit the default value that is defined for the field referred + by the Item_field object from which 'field' has been created. + For a field created not from a Item_field item dflt_field == 0. + */ + my_ptrdiff_t diff; + Field *orig_field= field->dflt_field; + /* Get the value from default_values */ + diff= (my_ptrdiff_t) (orig_field->table->s->default_values- + orig_field->table->record[0]); + orig_field->move_field(diff); // Points now at default_values + bool is_null= orig_field->is_real_null(); + char *from= orig_field->ptr; + orig_field->move_field(-diff); // Back to record[0] + if (is_null) + field->set_null(); + else + memcpy(field->ptr, from, field->pack_length()); + } + if (from_field[i]) { /* Not a table Item */ copy->set(field,from_field[i],save_sum_fields); From a6aaca7d6a8d56e075033e4f39c484b8bf81f46f Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Mon, 22 May 2006 07:57:46 -0700 Subject: [PATCH 07/18] Post-review fixes for bug #19089 --- mysql-test/r/view.result | 2 +- sql/field.cc | 3 +-- sql/field.h | 5 +++++ sql/sql_select.cc | 3 +++ 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 6c2db5962dd..2aab169ba76 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2716,7 +2716,7 @@ SELECT * FROM t2; a m xxx 1 yyy 5 -NULL 0 +xxx 0 DROP VIEW v1; DROP TABLE t1,t2; CREATE TABLE t1 (id int PRIMARY KEY, e ENUM('a','b') NOT NULL DEFAULT 'b'); diff --git a/sql/field.cc b/sql/field.cc index 18105b31f97..c31fbacc25e 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1228,12 +1228,11 @@ Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg, field_name(field_name_arg), query_id(0), key_start(0), part_of_key(0), part_of_sortkey(0), unireg_check(unireg_check_arg), - field_length(length_arg),null_bit(null_bit_arg) + field_length(length_arg), null_bit(null_bit_arg), dflt_field(0) { flags=null_ptr ? 0: NOT_NULL_FLAG; comment.str= (char*) ""; comment.length=0; - dflt_field= 0; } uint Field::offset() diff --git a/sql/field.h b/sql/field.h index 1801f0d0f86..4c3f6cd0709 100644 --- a/sql/field.h +++ b/sql/field.h @@ -53,6 +53,11 @@ public: char *ptr; // Position to field in record uchar *null_ptr; // Byte where null_bit is + /* + dflt_field is used only for the fields of temporary tables. + It points to the default value of the field in another table + from which this field has been created. + */ Field *dflt_field; // Field to copy default value from /* Note that you can use table->in_use as replacement for current_thd member diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b278b4ac167..1fe1747c44f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8697,7 +8697,10 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, if (is_null) field->set_null(); else + { + field->set_notnull(); memcpy(field->ptr, from, field->pack_length()); + } } if (from_field[i]) From 457aea43fcdc6cf55ec5352d7c901f7f0ff72c13 Mon Sep 17 00:00:00 2001 From: "gluh@eagle.intranet.mysql.r18.ru" <> Date: Tue, 23 May 2006 12:45:25 +0500 Subject: [PATCH 08/18] Bug#16681 information_schema shows forbidden VIEW details show view definition to users that have the needed privilleges --- mysql-test/r/information_schema.result | 13 ++++++++++++ mysql-test/t/information_schema.test | 19 +++++++++++++++++ sql/sql_show.cc | 28 +++++++++++++++++++++++--- 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 633b11e1f1b..e2d265d7ab9 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1108,3 +1108,16 @@ routine_name delete from proc where name=''; use test; +grant select on test.* to mysqltest_1@localhost; +create table t1 (id int); +create view v1 as select * from t1; +create definer = mysqltest_1@localhost +sql security definer view v2 as select 1; +select * from information_schema.views +where table_name='v1' or table_name='v2'; +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE DEFINER SECURITY_TYPE +NULL test v1 NONE YES root@localhost DEFINER +NULL test v2 select 1 AS `1` NONE NO mysqltest_1@localhost DEFINER +drop view v1, v2; +drop table t1; +drop user mysqltest_1@localhost; diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index e96f1ef4bbd..2cf7a810cdb 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -822,3 +822,22 @@ INSERT INTO `proc` VALUES ('test','','PROCEDURE','','SQL','CONTAINS_SQL', select routine_name from information_schema.routines; delete from proc where name=''; use test; + +# +# Bug#16681 information_schema shows forbidden VIEW details +# +grant select on test.* to mysqltest_1@localhost; +create table t1 (id int); +create view v1 as select * from t1; +create definer = mysqltest_1@localhost +sql security definer view v2 as select 1; + +connect (con16681,localhost,mysqltest_1,,test); +connection con16681; + +select * from information_schema.views +where table_name='v1' or table_name='v2'; +connection default; +drop view v1, v2; +drop table t1; +drop user mysqltest_1@localhost; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 70bdef302df..9018b364ec9 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3076,11 +3076,33 @@ static int get_schema_views_record(THD *thd, struct st_table_list *tables, if (tables->view) { + Security_context *sctx= thd->security_ctx; + ulong grant= SHOW_VIEW_ACL; +#ifndef NO_EMBEDDED_ACCESS_CHECKS + char *save_table_name= tables->table_name; + if (!my_strcasecmp(system_charset_info, tables->definer.user.str, + sctx->priv_user) && + !my_strcasecmp(system_charset_info, tables->definer.host.str, + sctx->priv_host)) + grant= SHOW_VIEW_ACL; + else + { + tables->table_name= tables->view_name.str; + if (check_access(thd, SHOW_VIEW_ACL , base_name, + &tables->grant.privilege, 0, 1, + test(tables->schema_table))) + grant= get_table_grant(thd, tables); + else + grant= tables->grant.privilege; + } + tables->table_name= save_table_name; +#endif + restore_record(table, s->default_values); table->field[1]->store(tables->view_db.str, tables->view_db.length, cs); - table->field[2]->store(tables->view_name.str, tables->view_name.length, - cs); - table->field[3]->store(tables->query.str, tables->query.length, cs); + table->field[2]->store(tables->view_name.str, tables->view_name.length, cs); + if (grant & SHOW_VIEW_ACL) + table->field[3]->store(tables->query.str, tables->query.length, cs); if (tables->with_check != VIEW_CHECK_NONE) { From 474ef8ed43c5f87da6a3c85e9cbc3e8fc18b47d0 Mon Sep 17 00:00:00 2001 From: "gluh@eagle.intranet.mysql.r18.ru" <> Date: Tue, 23 May 2006 13:27:45 +0500 Subject: [PATCH 09/18] Fix for bug#17626 CREATE TABLE ... SELECT failure with TRADITIONAL SQL mode transfer NO_DEFAULT_VALUE_FLAG flag to new field --- mysql-test/r/strict.result | 10 ++++++++++ mysql-test/r/type_ranges.result | 4 ++-- mysql-test/t/strict.test | 10 ++++++++++ sql/sql_select.cc | 1 + 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/strict.result b/mysql-test/r/strict.result index 2b1a47ed337..271cd7bf486 100644 --- a/mysql-test/r/strict.result +++ b/mysql-test/r/strict.result @@ -1288,3 +1288,13 @@ ERROR 22001: Data too long for column 'a' at row 1 select * from t1; a drop table t1; +set sql_mode='traditional'; +create table t1 (date date not null); +create table t2 select date from t1; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `date` date NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t2,t1; +set @@sql_mode= @org_mode; diff --git a/mysql-test/r/type_ranges.result b/mysql-test/r/type_ranges.result index bcdba3dca76..bd89c09e94d 100644 --- a/mysql-test/r/type_ranges.result +++ b/mysql-test/r/type_ranges.result @@ -241,7 +241,7 @@ Field Type Collation Null Key Default Extra Privileges Comment auto int(5) unsigned NULL NO 0 # string char(10) latin1_swedish_ci YES newdefault # tiny tinyint(4) NULL NO 0 # -short smallint(6) NULL NO 0 # +short smallint(6) NULL NO # medium mediumint(8) NULL NO 0 # long_int int(11) NULL NO 0 # longlong bigint(13) NULL NO 0 # @@ -259,7 +259,7 @@ date_time datetime NULL YES NULL # new_blob_col varchar(20) latin1_swedish_ci YES NULL # tinyblob_col tinyblob NULL YES NULL # mediumblob_col mediumblob NULL NO # -options enum('one','two','tree') latin1_swedish_ci NO one # +options enum('one','two','tree') latin1_swedish_ci NO # flags set('one','two','tree') latin1_swedish_ci NO # new_field char(10) latin1_swedish_ci NO new # select t1.auto,t2.auto from t1,t2 where t1.auto=t2.auto and ((t1.string<>t2.string and (t1.string is not null or t2.string is not null)) or (t1.tiny<>t2.tiny and (t1.tiny is not null or t2.tiny is not null)) or (t1.short<>t2.short and (t1.short is not null or t2.short is not null)) or (t1.medium<>t2.medium and (t1.medium is not null or t2.medium is not null)) or (t1.long_int<>t2.long_int and (t1.long_int is not null or t2.long_int is not null)) or (t1.longlong<>t2.longlong and (t1.longlong is not null or t2.longlong is not null)) or (t1.real_float<>t2.real_float and (t1.real_float is not null or t2.real_float is not null)) or (t1.real_double<>t2.real_double and (t1.real_double is not null or t2.real_double is not null)) or (t1.utiny<>t2.utiny and (t1.utiny is not null or t2.utiny is not null)) or (t1.ushort<>t2.ushort and (t1.ushort is not null or t2.ushort is not null)) or (t1.umedium<>t2.umedium and (t1.umedium is not null or t2.umedium is not null)) or (t1.ulong<>t2.ulong and (t1.ulong is not null or t2.ulong is not null)) or (t1.ulonglong<>t2.ulonglong and (t1.ulonglong is not null or t2.ulonglong is not null)) or (t1.time_stamp<>t2.time_stamp and (t1.time_stamp is not null or t2.time_stamp is not null)) or (t1.date_field<>t2.date_field and (t1.date_field is not null or t2.date_field is not null)) or (t1.time_field<>t2.time_field and (t1.time_field is not null or t2.time_field is not null)) or (t1.date_time<>t2.date_time and (t1.date_time is not null or t2.date_time is not null)) or (t1.new_blob_col<>t2.new_blob_col and (t1.new_blob_col is not null or t2.new_blob_col is not null)) or (t1.tinyblob_col<>t2.tinyblob_col and (t1.tinyblob_col is not null or t2.tinyblob_col is not null)) or (t1.mediumblob_col<>t2.mediumblob_col and (t1.mediumblob_col is not null or t2.mediumblob_col is not null)) or (t1.options<>t2.options and (t1.options is not null or t2.options is not null)) or (t1.flags<>t2.flags and (t1.flags is not null or t2.flags is not null)) or (t1.new_field<>t2.new_field and (t1.new_field is not null or t2.new_field is not null))); diff --git a/mysql-test/t/strict.test b/mysql-test/t/strict.test index d3b36cbc2a8..5044a20ae9f 100644 --- a/mysql-test/t/strict.test +++ b/mysql-test/t/strict.test @@ -1145,3 +1145,13 @@ create table t1(a bit(2)); insert into t1 values(b'101'); select * from t1; drop table t1; + +# +# Bug#17626 CREATE TABLE ... SELECT failure with TRADITIONAL SQL mode +# +set sql_mode='traditional'; +create table t1 (date date not null); +create table t2 select date from t1; +show create table t2; +drop table t2,t1; +set @@sql_mode= @org_mode; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1fe1747c44f..d6e1650ba83 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7984,6 +7984,7 @@ Field* create_tmp_field_from_field(THD *thd, Field* org_field, item->result_field= new_field; else new_field->field_name= name; + new_field->flags|= (org_field->flags & NO_DEFAULT_VALUE_FLAG); if (org_field->maybe_null() || (item && item->maybe_null)) new_field->flags&= ~NOT_NULL_FLAG; // Because of outer join if (org_field->type() == MYSQL_TYPE_VAR_STRING || From 0bd08dd4b620614321c12b52454db140129439fa Mon Sep 17 00:00:00 2001 From: "mikael@c-870ae253.1238-1-64736c10.cust.bredbandsbolaget.se" <> Date: Tue, 23 May 2006 07:37:03 -0400 Subject: [PATCH 10/18] BUG#19304: Merge handler allowed in partitioned tables --- mysql-test/r/partition.result | 4 ++++ mysql-test/t/partition.test | 8 ++++++++ sql/partition_info.cc | 15 ++++++++------- sql/share/errmsg.txt | 3 +++ 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index 0da071374ea..707c5981b2d 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -886,4 +886,8 @@ s1 2 3 drop table t1; +create table t1 (a int) +partition by key (a) +(partition p0 engine = MERGE); +ERROR HY000: MyISAM Merge handler cannot be used in partitioned tables End of 5.1 tests diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test index 272cdc27af6..1bf4ba9613c 100644 --- a/mysql-test/t/partition.test +++ b/mysql-test/t/partition.test @@ -1009,4 +1009,12 @@ select auto_increment from information_schema.tables where table_name='t1'; select * from t1; drop table t1; +# +# BUG 19304 Partitions: MERGE handler not allowed in partitioned tables +# +--error ER_PARTITION_MERGE_ERROR +create table t1 (a int) +partition by key (a) +(partition p0 engine = MERGE); + --echo End of 5.1 tests diff --git a/sql/partition_info.cc b/sql/partition_info.cc index dfc5dd2989b..83d2a436be3 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -431,18 +431,22 @@ char *partition_info::has_unique_names() bool partition_info::check_engine_mix(handlerton **engine_array, uint no_parts) { uint i= 0; - bool result= FALSE; DBUG_ENTER("partition_info::check_engine_mix"); do { if (engine_array[i] != engine_array[0]) { - result= TRUE; - break; + my_error(ER_MIX_HANDLER_ERROR, MYF(0)); + DBUG_RETURN(TRUE); } } while (++i < no_parts); - DBUG_RETURN(result); + if (!strcmp(engine_array[0]->name,"MRG_MYISAM")) + { + my_error(ER_PARTITION_MERGE_ERROR, MYF(0)); + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); } @@ -756,10 +760,7 @@ bool partition_info::check_partition_info(handlerton **eng_type, } while (++i < no_parts); } if (unlikely(partition_info::check_engine_mix(engine_array, part_count))) - { - my_error(ER_MIX_HANDLER_ERROR, MYF(0)); goto end; - } if (eng_type) *eng_type= (handlerton*)engine_array[0]; diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 01e66b35c0f..a601300ed5c 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5840,3 +5840,6 @@ ER_NULL_IN_VALUES_LESS_THAN ER_WRONG_PARTITION_NAME eng "Incorrect partition name" swe "Felaktigt partitionsnamn" +ER_PARTITION_MERGE_ERROR + eng "MyISAM Merge handler cannot be used in partitioned tables" + swe "MyISAM Merge kan inte anändas i en partitionerad tabell" From b756f55af03bf116e9c55715f2fefe0ea81467cc Mon Sep 17 00:00:00 2001 From: "mikael@c-870ae253.1238-1-64736c10.cust.bredbandsbolaget.se" <> Date: Tue, 23 May 2006 07:39:35 -0400 Subject: [PATCH 11/18] BUG#17455: Wrong results from Repair/Optimize .. table for partitioned tables --- mysql-test/r/partition.result | 10 ++++++++++ mysql-test/t/partition.test | 13 +++++++++++++ sql/ha_partition.cc | 6 ++---- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index 0da071374ea..fbcd688798f 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -886,4 +886,14 @@ s1 2 3 drop table t1; +create table t1 (a int) +engine=MEMORY +partition by key (a); +REPAIR TABLE t1; +Table Op Msg_type Msg_text +test.t1 repair note The storage engine for the table doesn't support repair +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize note The storage engine for the table doesn't support optimize +drop table t1; End of 5.1 tests diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test index 272cdc27af6..6461f24ffd2 100644 --- a/mysql-test/t/partition.test +++ b/mysql-test/t/partition.test @@ -1009,4 +1009,17 @@ select auto_increment from information_schema.tables where table_name='t1'; select * from t1; drop table t1; +# +# Bug 17455 Partitions: Wrong message and error when using Repair/Optimize +# table on partitioned table +# +create table t1 (a int) +engine=MEMORY +partition by key (a); + +REPAIR TABLE t1; +OPTIMIZE TABLE t1; + +drop table t1; + --echo End of 5.1 tests diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index b1a5a447b6f..abe79fb131d 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -1108,8 +1108,7 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, part)); if ((error= handle_opt_part(thd, check_opt, m_file[part], flag))) { - my_error(ER_GET_ERRNO, MYF(0), error); - DBUG_RETURN(TRUE); + DBUG_RETURN(error); } } while (++j < no_subparts); } @@ -1118,8 +1117,7 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, DBUG_PRINT("info", ("Optimize partition %u", i)); if ((error= handle_opt_part(thd, check_opt, m_file[i], flag))) { - my_error(ER_GET_ERRNO, MYF(0), error); - DBUG_RETURN(TRUE); + DBUG_RETURN(error); } } } From cb0a4f74236ded612654935d023586429bf1f82c Mon Sep 17 00:00:00 2001 From: "mikael@c-870ae253.1238-1-64736c10.cust.bredbandsbolaget.se" <> Date: Wed, 24 May 2006 13:35:52 -0400 Subject: [PATCH 12/18] BUG#19304: Merge handler not part of partitioned tables Review fix --- sql/partition_info.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 83d2a436be3..50a3409ef26 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -441,7 +441,7 @@ bool partition_info::check_engine_mix(handlerton **engine_array, uint no_parts) DBUG_RETURN(TRUE); } } while (++i < no_parts); - if (!strcmp(engine_array[0]->name,"MRG_MYISAM")) + if (ha_legacy_type(engine_array[0]) == DB_TYPE_MRG_MYISAM) { my_error(ER_PARTITION_MERGE_ERROR, MYF(0)); DBUG_RETURN(TRUE); From a95f31bd4e0ab3368afe4d73ef3d506acbb74d55 Mon Sep 17 00:00:00 2001 From: "mikael@c-870ae253.1238-1-64736c10.cust.bredbandsbolaget.se" <> Date: Wed, 24 May 2006 13:57:21 -0400 Subject: [PATCH 13/18] manual merge --- mysql-test/t/partition.test | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test index f7ce146c109..f697005d6bd 100644 --- a/mysql-test/t/partition.test +++ b/mysql-test/t/partition.test @@ -1064,4 +1064,18 @@ ALTER TABLE t1 DISABLE KEYS; ALTER TABLE t1 ENABLE KEYS; DROP TABLE t1; +# +# Bug 17455 Partitions: Wrong message and error when using Repair/Optimize +# table on partitioned table +# +create table t1 (a int) +engine=MEMORY +partition by key (a); + +REPAIR TABLE t1; +OPTIMIZE TABLE t1; + +drop table t1; +>>>>>>> + --echo End of 5.1 tests From 701007fe30e63882fefa8859a778c45f7832eec6 Mon Sep 17 00:00:00 2001 From: "mikael@c-870ae253.1238-1-64736c10.cust.bredbandsbolaget.se" <> Date: Wed, 24 May 2006 15:01:03 -0400 Subject: [PATCH 14/18] review fix --- sql/partition_info.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 0635c80296f..0924a8adf6e 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -442,7 +442,7 @@ bool partition_info::check_engine_mix(handlerton **engine_array, uint no_parts) DBUG_RETURN(TRUE); } } while (++i < no_parts); - if (ha_legacy_type(engine_array[0]) == DB_TYPE_MRG_MYISAM) + if (engine_array[0] == &myisammrg_hton) { my_error(ER_PARTITION_MERGE_ERROR, MYF(0)); DBUG_RETURN(TRUE); From d7e831ac6266fcfca45147b1e26ffc897ccc0ea7 Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Thu, 25 May 2006 00:03:35 +0400 Subject: [PATCH 15/18] sql_select.cc: After merge fix --- sql/sql_select.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b0505e26ce3..965afbe5b3c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8754,10 +8754,10 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, /* Get the value from default_values */ diff= (my_ptrdiff_t) (orig_field->table->s->default_values- orig_field->table->record[0]); - orig_field->move_field(diff); // Points now at default_values + orig_field->move_field_offset(diff); // Points now at default_values bool is_null= orig_field->is_real_null(); char *from= orig_field->ptr; - orig_field->move_field(-diff); // Back to record[0] + orig_field->move_field_offset(-diff); // Back to record[0] if (is_null) field->set_null(); else From 577246509f8d674d5a78dd631f91c6aab5759524 Mon Sep 17 00:00:00 2001 From: "pekka@mysql.com" <> Date: Thu, 25 May 2006 12:03:02 +0200 Subject: [PATCH 16/18] ndb - bug#14509 v5.1 part 1/2 : ndb api level [requires part 2/2] --- storage/ndb/include/ndbapi/Ndb.hpp | 37 +++-- storage/ndb/src/ndbapi/DictCache.cpp | 3 +- storage/ndb/src/ndbapi/DictCache.hpp | 3 +- storage/ndb/src/ndbapi/Ndb.cpp | 136 +++++++++++++------ storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp | 13 +- storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp | 2 - storage/ndb/src/ndbapi/ndberror.c | 1 - 7 files changed, 133 insertions(+), 62 deletions(-) diff --git a/storage/ndb/include/ndbapi/Ndb.hpp b/storage/ndb/include/ndbapi/Ndb.hpp index 8174bca0a5f..536f94a885a 100644 --- a/storage/ndb/include/ndbapi/Ndb.hpp +++ b/storage/ndb/include/ndbapi/Ndb.hpp @@ -1463,7 +1463,9 @@ public: /** * Return a unique tuple id for a table. The id sequence is - * ascending but may contain gaps. + * ascending but may contain gaps. Methods which have no + * TupleIdRange argument use NDB API dict cache. They may + * not be called from mysqld. * * @param aTableName table name * @@ -1471,28 +1473,47 @@ public: * * @return 0 or -1 on error, and tupleId in out parameter */ + struct TupleIdRange { + Uint64 m_first_tuple_id; + Uint64 m_last_tuple_id; + void reset() { + m_first_tuple_id = ~(Uint64)0; + m_last_tuple_id = ~(Uint64)0; + }; + }; + int initAutoIncrement(); int getAutoIncrementValue(const char* aTableName, Uint64 & tupleId, Uint32 cacheSize); int getAutoIncrementValue(const NdbDictionary::Table * aTable, Uint64 & tupleId, Uint32 cacheSize); + int getAutoIncrementValue(const NdbDictionary::Table * aTable, + TupleIdRange & range, Uint64 & tupleId, + Uint32 cacheSize); int readAutoIncrementValue(const char* aTableName, Uint64 & tupleId); int readAutoIncrementValue(const NdbDictionary::Table * aTable, Uint64 & tupleId); + int readAutoIncrementValue(const NdbDictionary::Table * aTable, + TupleIdRange & range, Uint64 & tupleId); int setAutoIncrementValue(const char* aTableName, Uint64 tupleId, bool increase); int setAutoIncrementValue(const NdbDictionary::Table * aTable, Uint64 tupleId, bool increase); + int setAutoIncrementValue(const NdbDictionary::Table * aTable, + TupleIdRange & range, Uint64 tupleId, + bool increase); private: - int getTupleIdFromNdb(Ndb_local_table_info* info, - Uint64 & tupleId, Uint32 cacheSize); - int readTupleIdFromNdb(Ndb_local_table_info* info, - Uint64 & tupleId); - int setTupleIdInNdb(Ndb_local_table_info* info, - Uint64 tupleId, bool increase); - int opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 & opValue, Uint32 op); + int getTupleIdFromNdb(const NdbTableImpl* table, + TupleIdRange & range, Uint64 & tupleId, + Uint32 cacheSize); + int readTupleIdFromNdb(const NdbTableImpl* table, + TupleIdRange & range, Uint64 & tupleId); + int setTupleIdInNdb(const NdbTableImpl* table, + TupleIdRange & range, Uint64 tupleId, bool increase); + int opTupleIdOnNdb(const NdbTableImpl* table, + TupleIdRange & range, Uint64 & opValue, Uint32 op); public: /** diff --git a/storage/ndb/src/ndbapi/DictCache.cpp b/storage/ndb/src/ndbapi/DictCache.cpp index 280b4210feb..5ed827b1b6d 100644 --- a/storage/ndb/src/ndbapi/DictCache.cpp +++ b/storage/ndb/src/ndbapi/DictCache.cpp @@ -47,8 +47,7 @@ Ndb_local_table_info::Ndb_local_table_info(NdbTableImpl *table_impl) { assert(! is_ndb_blob_table(table_impl)); m_table_impl= table_impl; - m_first_tuple_id = ~(Uint64)0; - m_last_tuple_id = ~(Uint64)0; + m_tuple_id_range.reset(); } Ndb_local_table_info::~Ndb_local_table_info() diff --git a/storage/ndb/src/ndbapi/DictCache.hpp b/storage/ndb/src/ndbapi/DictCache.hpp index 5bdaef88b94..b511387503a 100644 --- a/storage/ndb/src/ndbapi/DictCache.hpp +++ b/storage/ndb/src/ndbapi/DictCache.hpp @@ -35,8 +35,7 @@ public: NdbTableImpl *m_table_impl; // range of cached tuple ids per thread - Uint64 m_first_tuple_id; - Uint64 m_last_tuple_id; + Ndb::TupleIdRange m_tuple_id_range; Uint64 m_local_data[1]; // Must be last member. Used to access extra space. private: diff --git a/storage/ndb/src/ndbapi/Ndb.cpp b/storage/ndb/src/ndbapi/Ndb.cpp index 61c2dc725cf..3e4e66362c3 100644 --- a/storage/ndb/src/ndbapi/Ndb.cpp +++ b/storage/ndb/src/ndbapi/Ndb.cpp @@ -752,6 +752,7 @@ Ndb::getAutoIncrementValue(const char* aTableName, Uint64 & tupleId, Uint32 cacheSize) { DBUG_ENTER("Ndb::getAutoIncrementValue"); + ASSERT_NOT_MYSQLD; BaseString internal_tabname(internalize_table_name(aTableName)); Ndb_local_table_info *info= @@ -760,7 +761,9 @@ Ndb::getAutoIncrementValue(const char* aTableName, theError.code = theDictionary->getNdbError().code; DBUG_RETURN(-1); } - if (getTupleIdFromNdb(info, tupleId, cacheSize) == -1) + const NdbTableImpl* table = info->m_table_impl; + TupleIdRange & range = info->m_tuple_id_range; + if (getTupleIdFromNdb(table, range, tupleId, cacheSize) == -1) DBUG_RETURN(-1); DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId)); DBUG_RETURN(0); @@ -771,31 +774,48 @@ Ndb::getAutoIncrementValue(const NdbDictionary::Table * aTable, Uint64 & tupleId, Uint32 cacheSize) { DBUG_ENTER("Ndb::getAutoIncrementValue"); + ASSERT_NOT_MYSQLD; assert(aTable != 0); const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable); const BaseString& internal_tabname = table->m_internalName; Ndb_local_table_info *info= - theDictionary->get_local_table_info(internal_tabname, false); + theDictionary->get_local_table_info(internal_tabname); if (info == 0) { theError.code = theDictionary->getNdbError().code; DBUG_RETURN(-1); } - if (getTupleIdFromNdb(info, tupleId, cacheSize) == -1) + TupleIdRange & range = info->m_tuple_id_range; + if (getTupleIdFromNdb(table, range, tupleId, cacheSize) == -1) DBUG_RETURN(-1); DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId)); DBUG_RETURN(0); } int -Ndb::getTupleIdFromNdb(Ndb_local_table_info* info, - Uint64 & tupleId, Uint32 cacheSize) +Ndb::getAutoIncrementValue(const NdbDictionary::Table * aTable, + TupleIdRange & range, Uint64 & tupleId, + Uint32 cacheSize) +{ + DBUG_ENTER("Ndb::getAutoIncrementValue"); + assert(aTable != 0); + const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable); + + if (getTupleIdFromNdb(table, range, tupleId, cacheSize) == -1) + DBUG_RETURN(-1); + DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId)); + DBUG_RETURN(0); +} + +int +Ndb::getTupleIdFromNdb(const NdbTableImpl* table, + TupleIdRange & range, Uint64 & tupleId, Uint32 cacheSize) { DBUG_ENTER("Ndb::getTupleIdFromNdb"); - if (info->m_first_tuple_id != info->m_last_tuple_id) + if (range.m_first_tuple_id != range.m_last_tuple_id) { - assert(info->m_first_tuple_id < info->m_last_tuple_id); - tupleId = ++info->m_first_tuple_id; + assert(range.m_first_tuple_id < range.m_last_tuple_id); + tupleId = ++range.m_first_tuple_id; DBUG_PRINT("info", ("next cached value %llu", (ulonglong)tupleId)); } else @@ -808,7 +828,7 @@ Ndb::getTupleIdFromNdb(Ndb_local_table_info* info, * and returns first tupleId in the new range. */ Uint64 opValue = cacheSize; - if (opTupleIdOnNdb(info, opValue, 0) == -1) + if (opTupleIdOnNdb(table, range, opValue, 0) == -1) DBUG_RETURN(-1); tupleId = opValue; } @@ -820,15 +840,18 @@ Ndb::readAutoIncrementValue(const char* aTableName, Uint64 & tupleId) { DBUG_ENTER("Ndb::readAutoIncrementValue"); + ASSERT_NOT_MYSQLD; BaseString internal_tabname(internalize_table_name(aTableName)); Ndb_local_table_info *info= - theDictionary->get_local_table_info(internal_tabname, false); + theDictionary->get_local_table_info(internal_tabname); if (info == 0) { theError.code = theDictionary->getNdbError().code; DBUG_RETURN(-1); } - if (readTupleIdFromNdb(info, tupleId) == -1) + const NdbTableImpl* table = info->m_table_impl; + TupleIdRange & range = info->m_tuple_id_range; + if (readTupleIdFromNdb(table, range, tupleId) == -1) DBUG_RETURN(-1); DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId)); DBUG_RETURN(0); @@ -839,31 +862,47 @@ Ndb::readAutoIncrementValue(const NdbDictionary::Table * aTable, Uint64 & tupleId) { DBUG_ENTER("Ndb::readAutoIncrementValue"); + ASSERT_NOT_MYSQLD; assert(aTable != 0); const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable); const BaseString& internal_tabname = table->m_internalName; Ndb_local_table_info *info= - theDictionary->get_local_table_info(internal_tabname, false); + theDictionary->get_local_table_info(internal_tabname); if (info == 0) { theError.code = theDictionary->getNdbError().code; DBUG_RETURN(-1); } - if (readTupleIdFromNdb(info, tupleId) == -1) + TupleIdRange & range = info->m_tuple_id_range; + if (readTupleIdFromNdb(table, range, tupleId) == -1) DBUG_RETURN(-1); DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId)); DBUG_RETURN(0); } int -Ndb::readTupleIdFromNdb(Ndb_local_table_info* info, - Uint64 & tupleId) +Ndb::readAutoIncrementValue(const NdbDictionary::Table * aTable, + TupleIdRange & range, Uint64 & tupleId) +{ + DBUG_ENTER("Ndb::readAutoIncrementValue"); + assert(aTable != 0); + const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable); + + if (readTupleIdFromNdb(table, range, tupleId) == -1) + DBUG_RETURN(-1); + DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId)); + DBUG_RETURN(0); +} + +int +Ndb::readTupleIdFromNdb(const NdbTableImpl* table, + TupleIdRange & range, Uint64 & tupleId) { DBUG_ENTER("Ndb::readTupleIdFromNdb"); - if (info->m_first_tuple_id != info->m_last_tuple_id) + if (range.m_first_tuple_id != range.m_last_tuple_id) { - assert(info->m_first_tuple_id < info->m_last_tuple_id); - tupleId = info->m_first_tuple_id + 1; + assert(range.m_first_tuple_id < range.m_last_tuple_id); + tupleId = range.m_first_tuple_id + 1; } else { @@ -872,7 +911,7 @@ Ndb::readTupleIdFromNdb(Ndb_local_table_info* info, * only if no other transactions are allowed. */ Uint64 opValue = 0; - if (opTupleIdOnNdb(info, opValue, 3) == -1) + if (opTupleIdOnNdb(table, range, opValue, 3) == -1) DBUG_RETURN(-1); tupleId = opValue; } @@ -884,6 +923,7 @@ Ndb::setAutoIncrementValue(const char* aTableName, Uint64 tupleId, bool increase) { DBUG_ENTER("Ndb::setAutoIncrementValue"); + ASSERT_NOT_MYSQLD; BaseString internal_tabname(internalize_table_name(aTableName)); Ndb_local_table_info *info= @@ -892,7 +932,9 @@ Ndb::setAutoIncrementValue(const char* aTableName, theError.code = theDictionary->getNdbError().code; DBUG_RETURN(-1); } - if (setTupleIdInNdb(info, tupleId, increase) == -1) + const NdbTableImpl* table = info->m_table_impl; + TupleIdRange & range = info->m_tuple_id_range; + if (setTupleIdInNdb(table, range, tupleId, increase) == -1) DBUG_RETURN(-1); DBUG_RETURN(0); } @@ -902,36 +944,52 @@ Ndb::setAutoIncrementValue(const NdbDictionary::Table * aTable, Uint64 tupleId, bool increase) { DBUG_ENTER("Ndb::setAutoIncrementValue"); + ASSERT_NOT_MYSQLD; assert(aTable != 0); const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable); const BaseString& internal_tabname = table->m_internalName; Ndb_local_table_info *info= - theDictionary->get_local_table_info(internal_tabname, false); + theDictionary->get_local_table_info(internal_tabname); if (info == 0) { theError.code = theDictionary->getNdbError().code; DBUG_RETURN(-1); } - if (setTupleIdInNdb(info, tupleId, increase) == -1) + TupleIdRange & range = info->m_tuple_id_range; + if (setTupleIdInNdb(table, range, tupleId, increase) == -1) DBUG_RETURN(-1); DBUG_RETURN(0); } int -Ndb::setTupleIdInNdb(Ndb_local_table_info* info, - Uint64 tupleId, bool increase) +Ndb::setAutoIncrementValue(const NdbDictionary::Table * aTable, + TupleIdRange & range, Uint64 tupleId, + bool increase) +{ + DBUG_ENTER("Ndb::setAutoIncrementValue"); + assert(aTable != 0); + const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable); + + if (setTupleIdInNdb(table, range, tupleId, increase) == -1) + DBUG_RETURN(-1); + DBUG_RETURN(0); +} + +int +Ndb::setTupleIdInNdb(const NdbTableImpl* table, + TupleIdRange & range, Uint64 tupleId, bool increase) { DBUG_ENTER("Ndb::setTupleIdInNdb"); if (increase) { - if (info->m_first_tuple_id != info->m_last_tuple_id) + if (range.m_first_tuple_id != range.m_last_tuple_id) { - assert(info->m_first_tuple_id < info->m_last_tuple_id); - if (tupleId <= info->m_first_tuple_id + 1) + assert(range.m_first_tuple_id < range.m_last_tuple_id); + if (tupleId <= range.m_first_tuple_id + 1) DBUG_RETURN(0); - if (tupleId <= info->m_last_tuple_id) + if (tupleId <= range.m_last_tuple_id) { - info->m_first_tuple_id = tupleId - 1; + range.m_first_tuple_id = tupleId - 1; DBUG_PRINT("info", ("Setting next auto increment cached value to %llu", (ulonglong)tupleId)); @@ -942,7 +1000,7 @@ Ndb::setTupleIdInNdb(Ndb_local_table_info* info, * if tupleId <= NEXTID, do nothing. otherwise update NEXTID to * tupleId and set cached range to first = last = tupleId - 1. */ - if (opTupleIdOnNdb(info, tupleId, 2) == -1) + if (opTupleIdOnNdb(table, range, tupleId, 2) == -1) DBUG_RETURN(-1); } else @@ -950,7 +1008,7 @@ Ndb::setTupleIdInNdb(Ndb_local_table_info* info, /* * update NEXTID to given value. reset cached range. */ - if (opTupleIdOnNdb(info, tupleId, 1) == -1) + if (opTupleIdOnNdb(table, range, tupleId, 1) == -1) DBUG_RETURN(-1); } DBUG_RETURN(0); @@ -978,10 +1036,11 @@ int Ndb::initAutoIncrement() } int -Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 & opValue, Uint32 op) +Ndb::opTupleIdOnNdb(const NdbTableImpl* table, + TupleIdRange & range, Uint64 & opValue, Uint32 op) { DBUG_ENTER("Ndb::opTupleIdOnNdb"); - Uint32 aTableId = info->m_table_impl->m_tableId; + Uint32 aTableId = table->m_id; DBUG_PRINT("enter", ("table=%u value=%llu op=%u", aTableId, opValue, op)); NdbTransaction* tConnection; @@ -1015,9 +1074,9 @@ Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 & opValue, Uint32 op) tValue = tRecAttrResult->u_64_value(); - info->m_first_tuple_id = tValue - opValue; - info->m_last_tuple_id = tValue - 1; - opValue = info->m_first_tuple_id; // out + range.m_first_tuple_id = tValue - opValue; + range.m_last_tuple_id = tValue - 1; + opValue = range.m_first_tuple_id; // out break; case 1: // create on first use @@ -1028,8 +1087,7 @@ Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 & opValue, Uint32 op) if (tConnection->execute( Commit ) == -1 ) goto error_handler; - info->m_first_tuple_id = ~(Uint64)0; - info->m_last_tuple_id = ~(Uint64)0; + range.reset(); break; case 2: tOperation->interpretedUpdateTuple(); @@ -1053,7 +1111,7 @@ Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 & opValue, Uint32 op) DBUG_PRINT("info", ("Setting next auto increment value (db) to %llu", (ulonglong)opValue)); - info->m_first_tuple_id = info->m_last_tuple_id = opValue - 1; + range.m_first_tuple_id = range.m_last_tuple_id = opValue - 1; } break; case 3: diff --git a/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp index 8eb0b37120d..5d78472cef6 100644 --- a/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -1343,9 +1343,6 @@ NdbDictionaryImpl::putTable(NdbTableImpl *impl) Ndb_local_table_info::create(impl, m_local_table_data_size); m_localHash.put(impl->m_internalName.c_str(), info); - - m_ndb.theFirstTupleId[impl->getTableId()] = ~0; - m_ndb.theLastTupleId[impl->getTableId()] = ~0; } int @@ -2205,11 +2202,11 @@ NdbDictionaryImpl::createTable(NdbTableImpl &t) } if (autoIncrement) { // XXX unlikely race condition - t.m_id may no longer be same table - if (! m_ndb.setTupleIdInNdb(t.m_id, initialValue, false)) { - if (m_ndb.theError.code) - m_error.code = m_ndb.theError.code; - else - m_error.code = 4336; + // the tuple id range is not used on input + Ndb::TupleIdRange range; + if (m_ndb.setTupleIdInNdb(&t, range, initialValue, false) == -1) { + assert(m_ndb.theError.code != 0); + m_error.code = m_ndb.theError.code; delete t2; DBUG_RETURN(-1); } diff --git a/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp b/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp index 5a7a1ebb0ab..9df52e1fda6 100644 --- a/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp +++ b/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp @@ -950,8 +950,6 @@ NdbDictionaryImpl::get_local_table_info(const BaseString& internalTableName) if (info) { m_localHash.put(internalTableName.c_str(), info); - m_ndb.theFirstTupleId[tab->getTableId()] = ~0; - m_ndb.theLastTupleId[tab->getTableId()] = ~0; } } } diff --git a/storage/ndb/src/ndbapi/ndberror.c b/storage/ndb/src/ndbapi/ndberror.c index 8185bf38c3e..c05924dacf8 100644 --- a/storage/ndb/src/ndbapi/ndberror.c +++ b/storage/ndb/src/ndbapi/ndberror.c @@ -600,7 +600,6 @@ ErrorBundle ErrorCodes[] = { { 4269, DMEC, IE, "No connection to ndb management server" }, { 4270, DMEC, IE, "Unknown blob error" }, { 4335, DMEC, AE, "Only one autoincrement column allowed per table. Having a table without primary key uses an autoincremented hidden key, i.e. a table without a primary key can not have an autoincremented column" }, - { 4336, DMEC, AE, "Auto-increment value set below current value" }, { 4271, DMEC, AE, "Invalid index object, not retrieved via getIndex()" }, { 4272, DMEC, AE, "Table definition has undefined column" }, { 4273, DMEC, IE, "No blob table in dict cache" }, From 7fcc77f49cf8e3a69583449005751ad5db0708d7 Mon Sep 17 00:00:00 2001 From: "pekka@mysql.com" <> Date: Thu, 25 May 2006 12:13:47 +0200 Subject: [PATCH 17/18] ndb - bug#14509 v5.1 part 2/2 : handler level --- mysql-test/r/ndb_basic.result | 48 +++++++++++++++---------------- mysql-test/t/ndb_alter_table.test | 30 +++++++++---------- sql/ha_ndbcluster.cc | 14 +++++---- sql/ha_ndbcluster.h | 15 +++++++++- 4 files changed, 62 insertions(+), 45 deletions(-) diff --git a/mysql-test/r/ndb_basic.result b/mysql-test/r/ndb_basic.result index 9477caf97ab..997a94d0afa 100644 --- a/mysql-test/r/ndb_basic.result +++ b/mysql-test/r/ndb_basic.result @@ -649,30 +649,30 @@ counter datavalue 6 newval 7 newval 8 newval -35 newval -36 newval -37 newval -38 newval -39 newval -40 newval -41 newval -42 newval -43 newval -44 newval -45 newval -46 newval -47 newval -48 newval -49 newval -50 newval -51 newval -52 newval -53 newval -54 newval -55 newval -56 newval -57 newval -58 newval +9 newval +10 newval +11 newval +12 newval +13 newval +14 newval +15 newval +16 newval +17 newval +18 newval +19 newval +20 newval +21 newval +22 newval +23 newval +24 newval +25 newval +26 newval +27 newval +28 newval +29 newval +30 newval +31 newval +32 newval drop table t1; CREATE TABLE t1 ( b INT ) PACK_KEYS = 0 ENGINE = ndb; select * from t1; diff --git a/mysql-test/t/ndb_alter_table.test b/mysql-test/t/ndb_alter_table.test index cd5c4819c51..8e3b4a6ca89 100644 --- a/mysql-test/t/ndb_alter_table.test +++ b/mysql-test/t/ndb_alter_table.test @@ -325,21 +325,6 @@ on t1 (c010, c011, c012, c013); drop table t1; -# simple test that auto incr is not lost at rename or alter -create table t1 (a int primary key auto_increment, b int) engine=ndb; -insert into t1 (b) values (101),(102),(103); -select * from t1 where a = 3; -alter table t1 rename t2; -insert into t2 (b) values (201),(202),(203); -select * from t2 where a = 6; -alter table t2 add c int; -insert into t2 (b) values (301),(302),(303); -select * from t2 where a = 9; -alter table t2 rename t1; -insert into t1 (b) values (401),(402),(403); -select * from t1 where a = 12; -drop table t1; - # End of 4.1 tests # On-line alter table @@ -398,3 +383,18 @@ LOAD DATA INFILE 'tmp.dat' INTO TABLE ndb_show_tables; select 'no_copy' from ndb_show_tables where id = @t1_id and name like '%t1%'; DROP TABLE t1, ndb_show_tables; + +# simple test that auto incr is not lost at rename or alter +create table t1 (a int primary key auto_increment, b int) engine=ndb; +insert into t1 (b) values (101),(102),(103); +select * from t1 where a = 3; +alter table t1 rename t2; +insert into t2 (b) values (201),(202),(203); +select * from t2 where a = 6; +alter table t2 add c int; +insert into t2 (b) values (301),(302),(303); +select * from t2 where a = 9; +alter table t2 rename t1; +insert into t1 (b) values (401),(402),(403); +select * from t1 where a = 12; +drop table t1; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index a17416e006d..0baf2e09473 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -2464,7 +2464,8 @@ int ha_ndbcluster::write_row(byte *record) Uint64 auto_value; uint retries= NDB_AUTO_INCREMENT_RETRIES; do { - ret= ndb->getAutoIncrementValue(m_table, auto_value, 1); + Ndb_tuple_id_range_guard g(m_share); + ret= ndb->getAutoIncrementValue(m_table, g.range, auto_value, 1); } while (ret == -1 && --retries && ndb->getNdbError().status == NdbError::TemporaryError); @@ -2565,7 +2566,8 @@ int ha_ndbcluster::write_row(byte *record) DBUG_PRINT("info", ("Trying to set next auto increment value to %llu", (ulonglong) next_val)); - if (ndb->setAutoIncrementValue(m_table, next_val, TRUE) + Ndb_tuple_id_range_guard g(m_share); + if (ndb->setAutoIncrementValue(m_table, g.range, next_val, TRUE) == -1) ERR_RETURN(ndb->getNdbError()); } @@ -3528,8 +3530,9 @@ void ha_ndbcluster::info(uint flag) if (m_table) { Ndb *ndb= get_ndb(); + Ndb_tuple_id_range_guard g(m_share); - if (ndb->readAutoIncrementValue(m_table, + if (ndb->readAutoIncrementValue(m_table, g.range, auto_increment_value) == -1) { const NdbError err= ndb->getNdbError(); @@ -5231,10 +5234,11 @@ ulonglong ha_ndbcluster::get_auto_increment() int ret; uint retries= NDB_AUTO_INCREMENT_RETRIES; do { + Ndb_tuple_id_range_guard g(m_share); ret= m_skip_auto_increment ? - ndb->readAutoIncrementValue(m_table, auto_value) : - ndb->getAutoIncrementValue(m_table, auto_value, cache_size); + ndb->readAutoIncrementValue(m_table, g.range, auto_value) : + ndb->getAutoIncrementValue(m_table, g.range, auto_value, cache_size); } while (ret == -1 && --retries && ndb->getNdbError().status == NdbError::TemporaryError); diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index f407cb0090f..f113994f3b2 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -106,6 +106,7 @@ typedef struct st_ndbcluster_share { ulonglong commit_count; char *db; char *table_name; + Ndb::TupleIdRange tuple_id_range; #ifdef HAVE_NDB_BINLOG uint32 flags; NdbEventOperation *op; @@ -138,6 +139,19 @@ set_ndb_share_state(NDB_SHARE *share, NDB_SHARE_STATE state) pthread_mutex_unlock(&share->mutex); } +struct Ndb_tuple_id_range_guard { + Ndb_tuple_id_range_guard(NDB_SHARE* _share) : + share(_share), + range(share->tuple_id_range) { + pthread_mutex_lock(&share->mutex); + } + ~Ndb_tuple_id_range_guard() { + pthread_mutex_unlock(&share->mutex); + } + NDB_SHARE* share; + Ndb::TupleIdRange& range; +}; + #ifdef HAVE_NDB_BINLOG /* NDB_SHARE.flags */ #define NSF_HIDDEN_PK 1 /* table has hidden primary key */ @@ -725,7 +739,6 @@ private: int drop_indexes(Ndb *ndb, TABLE *tab); int add_index_handle(THD *thd, NdbDictionary::Dictionary *dict, KEY *key_info, const char *index_name, uint index_no); - int initialize_autoincrement(const void *table); int get_metadata(const char* path); void release_metadata(THD *thd, Ndb *ndb); NDB_INDEX_TYPE get_index_type(uint idx_no) const; From 31a54240e7cc89b6f8ae97b4cd51a8b377f95b91 Mon Sep 17 00:00:00 2001 From: "gluh@eagle.intranet.mysql.r18.ru" <> Date: Thu, 25 May 2006 19:20:35 +0500 Subject: [PATCH 18/18] test fix --- mysql-test/r/partition.result | 8 ++++---- mysql-test/t/partition.test | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index 71d4f1bb376..3be9f3edee2 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -890,15 +890,15 @@ s1 2 3 drop table t1; -create table t1 (a int) -partition by key (a) -(partition p0 engine = MERGE); -ERROR HY000: MyISAM Merge handler cannot be used in partitioned tables create table t1 (a int) engine=memory partition by key(a); insert into t1 values (1); create index inx1 on t1(a); drop table t1; +create table t1 (a int) +partition by key (a) +(partition p0 engine = MERGE); +ERROR HY000: MyISAM Merge handler cannot be used in partitioned tables create table t1 (a varchar(1)) partition by key (a) as select 'a'; diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test index f697005d6bd..a24124d3fb5 100644 --- a/mysql-test/t/partition.test +++ b/mysql-test/t/partition.test @@ -1076,6 +1076,5 @@ REPAIR TABLE t1; OPTIMIZE TABLE t1; drop table t1; ->>>>>>> --echo End of 5.1 tests