Description:
Droppping an ndb table does not get rid of auto_increment data. When the table is dropped and recreated without an autoincrement column, the autoincrement column for that table can still be accessed by the NDB API.
When the database is dropped, the auto_increment does go away.
How to repeat:
first -
drop database TEST_DB_1;
create database TEST_DB_1;
CREATE TABLE `MYTABLENAME` (
`ATTR1` int(10) unsigned NOT NULL DEFAULT '0',
`ATTR2` int(10) unsigned NOT NULL,
PRIMARY KEY (`ATTR1`)
) ENGINE=ndbcluster ;
run the following snippet. You should get an error. This is expected.
Then:
drop table MYTABLENAME;
CREATE TABLE `MYTABLENAME` (
`ATTR1` int(10) unsigned NOT NULL auto_increment,
`ATTR2` int(10) unsigned NOT NULL,
PRIMARY KEY (`ATTR1`)
) ENGINE=ndbcluster ;
run the snippet. It should run successfully. This is expected.
Then:
drop table MYTABLENAME;
CREATE TABLE `MYTABLENAME` (
`ATTR1` int(10) unsigned NOT NULL DEFAULT '0',
`ATTR2` int(10) unsigned NOT NULL,
PRIMARY KEY (`ATTR1`)
) ENGINE=ndbcluster ;
run the snippet. It will run successfully. This is the error.
Then:
drop database TEST_DB_1;
CREATE TABLE `MYTABLENAME` (
`ATTR1` int(10) unsigned NOT NULL DEFAULT '0',
`ATTR2` int(10) unsigned NOT NULL,
PRIMARY KEY (`ATTR1`)
) ENGINE=ndbcluster ;
run the snippet. It will error. This is correct.
/**************************************************************
* Connect to ndb cluster *
**************************************************************/
Ndb_cluster_connection *cluster_connection=
new Ndb_cluster_connection(); // Object representing the cluster
if (cluster_connection->connect(5,3,1))
{
std::cout << "Connect to cluster management server failed.\n";
exit(-1);
}
if (cluster_connection->wait_until_ready(30,30))
{
std::cout << "Cluster was not ready within 30 secs.\n";
exit(-1);
}
Ndb* myNdb = new Ndb( cluster_connection,
"TEST_DB_1" ); // Object representing the database
if (myNdb->init() == -1) {
APIERROR(myNdb->getNdbError());
exit(-1);
}
const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
if (myTable == NULL)
APIERROR(myDict->getNdbError());
/**************************************************************************
* Fill table with tuples, using auto_increment IDs *
**************************************************************************/
{
std::time_t before_t = std::time(0);
for (int i = 0; i < INSERT_NUM; i++) {
NdbTransaction *myTransaction= myNdb->startTransaction();
if (myTransaction == NULL) APIERROR(myNdb->getNdbError());
NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
myOperation->insertTuple();
if (myNdb->initAutoIncrement() == -1)
APIERROR(myNdb->getNdbError());
Uint64 auto_id = 0;
if (myNdb->getAutoIncrementValue(myTable,auto_id,0) == -1)
APIERROR(myNdb->getNdbError());
if (myOperation->equal("ATTR1",(int)auto_id)==-1)
APIERROR(myTransaction->getNdbError());
if (myOperation->setValue("ATTR2", i)==-1)
APIERROR(myTransaction->getNdbError());
if (myTransaction->execute( NdbTransaction::Commit ) == -1)
APIERROR(myTransaction->getNdbError());
myNdb->closeTransaction(myTransaction);
}
std::time_t after_t = std::time(0);
std::cout << "Insert time for " << INSERT_NUM << " ";
std::cout << after_t << " -- " << before_t;
std::cout << " = " << after_t - before_t << std::endl;
}
Suggested fix:
Drop the auto_increment information when a table is dropped, otherwise the cluster metadata will be inconsistent with expectations.