From: Date: July 3 2009 1:41pm Subject: bzr commit into mysql-6.0-falcon branch (john.embretsen:2732) List-Archive: http://lists.mysql.com/commits/77956 Message-Id: <20090703114152.19864.qmail@khepri20> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============0405483135==" --===============0405483135== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///export/home/tmp/je159969/mysql-dev/bzr-repos/mysql-6.0-falcon-to-merge/ based on revid:john.embretsen@stripped 2732 John H. Embretsen 2009-07-03 [merge] Merge mysql-6.0-falcon-team --> mysql-6.0-falcon. added: mysql-test/suite/falcon/r/falcon_bug_45775.result mysql-test/suite/falcon/t/falcon_bug_45775.test modified: storage/falcon/IO.cpp storage/falcon/IOx.h storage/falcon/IndexRootPage.cpp storage/falcon/IndexRootPage.h storage/falcon/StorageTable.cpp storage/falcon/StorageTableShare.cpp storage/falcon/StorageTableShare.h storage/falcon/StorageVersion.h storage/falcon/Table.cpp storage/falcon/Table.h storage/falcon/ha_falcon.cpp storage/falcon/ha_falcon.h === added file 'mysql-test/suite/falcon/r/falcon_bug_45775.result' --- a/mysql-test/suite/falcon/r/falcon_bug_45775.result 1970-01-01 00:00:00 +0000 +++ b/mysql-test/suite/falcon/r/falcon_bug_45775.result 2009-06-28 18:58:38 +0000 @@ -0,0 +1,31 @@ +*** Bug #45775 *** +SET @@storage_engine = 'Falcon'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a int NOT NULL UNIQUE, b int, c int); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + UNIQUE KEY `a` (`a`) +) ENGINE=Falcon DEFAULT CHARSET=latin1 +ALTER TABLE t1 ADD PRIMARY KEY (b); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` int(11) NOT NULL DEFAULT '0', + `c` int(11) DEFAULT NULL, + PRIMARY KEY (`b`), + UNIQUE KEY `a` (`a`) +) ENGINE=Falcon DEFAULT CHARSET=latin1 +INSERT INTO t1 VALUES (1,1,1); +INSERT INTO t1 VALUES (1,1,2); +ERROR 23000: Duplicate entry '1' for key 'a' +INSERT INTO t1 VALUES (1,2,2); +ERROR 23000: Duplicate entry '1' for key 'a' +INSERT INTO t1 VALUES (2,1,2); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +INSERT INTO t1 VALUES (2,2,2); +DROP TABLE t1; === added file 'mysql-test/suite/falcon/t/falcon_bug_45775.test' --- a/mysql-test/suite/falcon/t/falcon_bug_45775.test 1970-01-01 00:00:00 +0000 +++ b/mysql-test/suite/falcon/t/falcon_bug_45775.test 2009-06-28 18:58:38 +0000 @@ -0,0 +1,50 @@ +# +# Bug #45775: Crash when adding primary key to Falcon table with unique constraint +# +# The server treats a primary key and a unique key with non-null columns as +# effectively the same. This test confirms that the storage engine makes the +# correct distinction between the two. +# +--echo *** Bug #45775 *** + +--source include/have_falcon.inc + +# ----------------------------------------------------- # +# --- Initialisation --- # +# ----------------------------------------------------- # +let $engine = 'Falcon'; +eval SET @@storage_engine = $engine; + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +# ----------------------------------------------------- # +# --- Test --- # +# ----------------------------------------------------- # +CREATE TABLE t1 (a int NOT NULL UNIQUE, b int, c int); +SHOW CREATE TABLE t1; +ALTER TABLE t1 ADD PRIMARY KEY (b); +SHOW CREATE TABLE t1; + +INSERT INTO t1 VALUES (1,1,1); + +## Should fail with key conflict +--error ER_DUP_ENTRY +INSERT INTO t1 VALUES (1,1,2); + +## Should fail with unique key conflict +--error ER_DUP_ENTRY +INSERT INTO t1 VALUES (1,2,2); + +## Should fail with primary key conflict +--error ER_DUP_ENTRY +INSERT INTO t1 VALUES (2,1,2); + +INSERT INTO t1 VALUES (2,2,2); + +# ----------------------------------------------------- # +# --- Final cleanup --- # +# ----------------------------------------------------- # +DROP TABLE t1; + === modified file 'storage/falcon/IO.cpp' --- a/storage/falcon/IO.cpp 2009-04-07 20:16:05 +0000 +++ b/storage/falcon/IO.cpp 2009-06-26 11:13:44 +0000 @@ -109,6 +109,8 @@ static const int TRACE_SYNC_END = -2; static const uint16 NON_ZERO_CHECKSUM_MAGIC = 0xAFFE; +static const int NO_VALID_PAGE_NUMBER = -2; + #ifdef SIMULATE_DISK_FULL static int simulateDiskFull = SIMULATE_DISK_FULL; #endif @@ -289,7 +291,7 @@ void IO::readPage(Bdb * bdb) if (length != pageSize) { - declareFatalError(); + declareFatalError("IO::readPage", bdb->pageNumber, errno); if (length == -1) { throw SQLError(IO_ERROR, "read error on page %d of \"%s\": %s (%d)", @@ -390,7 +392,7 @@ void IO::writePages(int32 pageNumber, in if (errno == ENOSPC) throw SQLError(DEVICE_FULL, "device full error on %s, page %d\n", (const char*) fileName, pageNumber); - declareFatalError(); + declareFatalError("IO::writePages", pageNumber, errno); throw SQLError(IO_ERROR, "write error on page %d (%d/%d/%d) of \"%s\": %s (%d)", pageNumber, length, pageSize, fileId, @@ -452,9 +454,27 @@ void IO::longSeek(int64 offset) Error::error ("long seek failed on \"%s\"", (const char*) fileName); } -void IO::declareFatalError() +void IO::declareFatalError(const char *methodName, int pageNumber, int errorNumber) { + // Update status about that a fatal IO error has occured + fatalError = true; + + // Convert the page number to a string. Note that we use + // NO_VALID_PAGE_NUMBER to indicate that this error is not related + // to a specific page. + + char pageNumberStr[40]; + pageNumberStr[0] = 0; + + if (pageNumber != NO_VALID_PAGE_NUMBER) + { + sprintf(pageNumberStr, ", page %d", pageNumber); + } + + Log::fatal("Falcon: Fatal IO error occurred in \"%s\": file \"%s\"%s: %s (%d)\n", + methodName, (const char*) fileName, pageNumberStr, + strerror(errorNumber), errorNumber); } @@ -705,7 +725,7 @@ void IO::sync(void) #ifdef _WIN32 if (_commit(fileId)) { - declareFatalError(); + declareFatalError("IO::sync", NO_VALID_PAGE_NUMBER, errno); throw SQLError(IO_ERROR, "_commit failed on \"%s\": %s (%d)", (const char*) fileName, strerror (errno), errno); } === modified file 'storage/falcon/IOx.h' --- a/storage/falcon/IOx.h 2008-09-11 10:56:00 +0000 +++ b/storage/falcon/IOx.h 2009-06-26 11:13:44 +0000 @@ -56,7 +56,6 @@ public: void write(uint32 length, const UCHAR *data); static bool doesFileExist(const char *fileName); static int fileStat(const char *fileName, struct stat *stats = NULL, int *errnum = NULL); - void declareFatalError(); void seek (int pageNumber); void closeFile(); void readHeader (Hdr *header); @@ -88,6 +87,10 @@ public: static void deleteFile(const char* fileName); static int getWriteMode(int attempt); +private: + void declareFatalError(const char *methodName, int PageNumber, int errorNumber); + +public: JString fileName; SyncObject syncObject; int fileId; === modified file 'storage/falcon/IndexRootPage.cpp' --- a/storage/falcon/IndexRootPage.cpp 2009-04-14 19:14:20 +0000 +++ b/storage/falcon/IndexRootPage.cpp 2009-07-01 09:02:00 +0000 @@ -182,10 +182,9 @@ bool IndexRootPage::addIndexEntry(Dbb * /* Node didn't fit. Split the page and propagate the split upward. Sooner or later we'll go back and re-try the original insertion */ - - if (splitIndexPage (dbb, indexId, bdb, transId, result, key, recordNumber, isRoot)) - return true; - + + splitIndexPage (dbb, indexId, bdb, transId, result, key, recordNumber, isRoot); + #ifdef _DEBUG if (n) { @@ -483,7 +482,7 @@ void IndexRootPage::scanIndex (Dbb *dbb } } -bool IndexRootPage::splitIndexPage(Dbb * dbb, int32 indexId, Bdb * bdb, TransId transId, +void IndexRootPage::splitIndexPage(Dbb * dbb, int32 indexId, Bdb * bdb, TransId transId, AddNodeResult addResult, IndexKey *indexKey, int recordNumber, bool isRoot) { @@ -557,7 +556,7 @@ bool IndexRootPage::splitIndexPage(Dbb * leftBdb->release(REL_HISTORY); bdb->release(REL_HISTORY); - return false; + return; } @@ -596,15 +595,15 @@ bool IndexRootPage::splitIndexPage(Dbb * } parentBdb->release(REL_HISTORY); - return false; + return; } // Parent page needs to be split.Recurse ASSERT(result == SplitMiddle || result == SplitEnd || result == NextPage); - if (splitIndexPage (dbb, indexId, parentBdb, transId, result, &splitKey, - splitPageNumber, (parentBdb->pageNumber == rootPageNumber))) - return true; + splitIndexPage (dbb, indexId, parentBdb, transId, result, &splitKey, + splitPageNumber, (parentBdb->pageNumber == rootPageNumber)); + } } === modified file 'storage/falcon/IndexRootPage.h' --- a/storage/falcon/IndexRootPage.h 2009-03-02 18:36:32 +0000 +++ b/storage/falcon/IndexRootPage.h 2009-07-01 09:02:00 +0000 @@ -43,7 +43,7 @@ public: static void debugBucket (Dbb *dbb, int indexId, int recordNumber, TransId transactionId); static void deleteIndex (Dbb *dbb, int32 indexId, TransId transId); static bool deleteIndexEntry (Dbb *dbb, int32 indexId, IndexKey *key, int32 recordNumber, TransId transId); - static bool splitIndexPage (Dbb *dbb, int32 indexId, Bdb *bdb, TransId transId, + static void splitIndexPage (Dbb *dbb, int32 indexId, Bdb *bdb, TransId transId, AddNodeResult addResult, IndexKey *indexKey, int recordNumber, bool isRootPage); static void scanIndex (Dbb *dbb, int32 indexId, int32 rootPage, IndexKey *low, IndexKey *high, int searchFlags, TransId transId, Bitmap *bitmap); static void positionIndex(Dbb* dbb, int indexId, int32 rootPage, WalkIndex* walkIndex); === modified file 'storage/falcon/StorageTable.cpp' --- a/storage/falcon/StorageTable.cpp 2009-05-14 05:16:08 +0000 +++ b/storage/falcon/StorageTable.cpp 2009-06-25 22:48:40 +0000 @@ -643,7 +643,7 @@ void StorageTable::clearAlter(void) bool StorageTable::setAlter(void) { - return share->table->setAlter(); + return share->table->setAlter(storageConnection->connection); } int StorageTable::alterCheck(void) === modified file 'storage/falcon/StorageTableShare.cpp' --- a/storage/falcon/StorageTableShare.cpp 2009-04-27 16:43:53 +0000 +++ b/storage/falcon/StorageTableShare.cpp 2009-06-28 18:58:38 +0000 @@ -219,11 +219,11 @@ int StorageTableShare::create(StorageCon case TABLESPACE_NOT_EXIST_ERROR: return StorageErrorTableSpaceNotExist; default: - return StorageErrorTableExits; + return StorageErrorTableExists; } } if (!table) - return StorageErrorTableExits; + return StorageErrorTableExists; format = table->getCurrentFormat(); @@ -235,8 +235,12 @@ int StorageTableShare::create(StorageCon int StorageTableShare::upgrade(StorageConnection *storageConnection, const char* sql, int64 autoIncrementValue) { - if (!(table = storageDatabase->upgradeTable(storageConnection, name, schemaName, sql, autoIncrementValue))) - return StorageErrorTableExits; + Table* tableUpgrade = storageDatabase->upgradeTable(storageConnection, name, schemaName, sql, autoIncrementValue); + + if (tableUpgrade) + table = tableUpgrade; + else + return StorageErrorTableExists; format = table->getCurrentFormat(); === modified file 'storage/falcon/StorageTableShare.h' --- a/storage/falcon/StorageTableShare.h 2009-06-24 22:17:25 +0000 +++ b/storage/falcon/StorageTableShare.h 2009-06-28 18:58:38 +0000 @@ -100,7 +100,7 @@ enum StorageError { StorageErrorTableNotFound = -3, StorageErrorNoIndex = -4, StorageErrorBadKey = -5, - StorageErrorTableExits = -6, + StorageErrorTableExists = -6, StorageErrorNoSequence = -7, StorageErrorUpdateConflict = -8, StorageErrorUncommittedUpdates = -9, // specific for drop table === modified file 'storage/falcon/StorageVersion.h' --- a/storage/falcon/StorageVersion.h 2009-04-30 10:06:12 +0000 +++ b/storage/falcon/StorageVersion.h 2009-07-03 11:14:02 +0000 @@ -14,5 +14,5 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define FALCON_VERSION "T1.6-0" -#define FALCON_DATE "30 April, 2009" +#define FALCON_VERSION "T1.6-1" +#define FALCON_DATE "03 July, 2009" === modified file 'storage/falcon/Table.cpp' --- a/storage/falcon/Table.cpp 2009-06-23 21:16:25 +0000 +++ b/storage/falcon/Table.cpp 2009-06-25 22:48:40 +0000 @@ -917,7 +917,8 @@ void Table::init(int id, const char *sch debugThawedBytes = 0; cardinality = 0; priorCardinality = 0; - alterIsActive = false; + alterIsActive = 0; + alterConnection = NULL; syncObject.setName("Table::syncObject"); syncTriggers.setName("Table::syncTriggers"); syncAlter.setName("Table::syncAlter"); @@ -1774,7 +1775,8 @@ void Table::truncate(Transaction *transa ageGroup = database->currentGeneration; debugThawedRecords = 0; debugThawedBytes = 0; - alterIsActive = false; + alterIsActive = 0; + alterConnection = NULL; deleting = false; } @@ -3695,19 +3697,21 @@ void Table::clearAlter(void) { Sync sync(&syncAlter, "Table::clearAlter"); sync.lock(Exclusive); - alterIsActive = false; + if (--alterIsActive == 0) + alterConnection = NULL; } } -bool Table::setAlter(void) +bool Table::setAlter(Connection* connection) { Sync sync(&syncAlter, "Table::setAlter"); sync.lock(Exclusive); - if (alterIsActive) + if (alterIsActive && (connection != alterConnection)) return false; - alterIsActive = true; + alterIsActive++; + alterConnection = connection; return true; } === modified file 'storage/falcon/Table.h' --- a/storage/falcon/Table.h 2009-06-02 15:25:59 +0000 +++ b/storage/falcon/Table.h 2009-06-25 22:48:40 +0000 @@ -127,7 +127,7 @@ public: int nextColumnId (int previous); void loadStuff(); void clearAlter(void); - bool setAlter(void); + bool setAlter(Connection* connection); void addTrigger (Trigger *trigger); void dropTrigger (Trigger *trigger); @@ -271,7 +271,8 @@ public: bool changed; bool eof; bool markedForDelete; - bool alterIsActive; + int alterIsActive; + Connection* alterConnection; // The connection currintly doing an alter. bool deleting; // dropping or truncating. int32 recordBitmapHighWater; int32 ageGroup; === modified file 'storage/falcon/ha_falcon.cpp' --- a/storage/falcon/ha_falcon.cpp 2009-06-24 22:17:25 +0000 +++ b/storage/falcon/ha_falcon.cpp 2009-06-28 18:58:38 +0000 @@ -91,6 +91,10 @@ extern StorageHandler *storageHandler; #undef PARAMETER_UINT #undef PARAMETER_BOOL +// Unique name assigned by server to the primary key + +extern const char *primary_key_name; + ulonglong falcon_record_memory_max; ulonglong falcon_serial_log_file_size; uint falcon_allocation_extent; @@ -909,16 +913,14 @@ int StorageInterface::create(const char if ((ret = storageTable->create(gen.getString(), incrementValue))) { storageTable->deleteTable(); - DBUG_RETURN(error(ret)); } for (n = 0; n < form->s->keys; ++n) - if (n != form->s->primary_key) + if (!isPrimaryKey(form, n)) if ((ret = createIndex(schemaName, tableName, form, n))) { storageTable->deleteTable(); - DBUG_RETURN(error(ret)); } @@ -1586,6 +1588,19 @@ ha_rows StorageInterface::records_in_ran DBUG_RETURN(MAX(guestimate, 2)); } +bool StorageInterface::isPrimaryKey(TABLE *srvTable, uint indexId) +{ + uint primaryKey = srvTable->s->primary_key; + + // If primary_key != MAX_KEY, then the key is either a primary key or + // a unique key with all non-NULL columns. Check the key name to + // distinguish between them. The primary key is always "PRIMARY". + + return (indexId == primaryKey && + primaryKey != MAX_KEY && + !strcmp(srvTable->s->key_info[primaryKey].name, primary_key_name)); +} + void StorageInterface::getKeyDesc(TABLE *srvTable, int indexId, StorageIndexDesc *indexDesc) { KEY *keyInfo = srvTable->key_info + indexId; @@ -1594,7 +1609,7 @@ void StorageInterface::getKeyDesc(TABLE indexDesc->id = indexId; indexDesc->numberSegments = numberKeys; indexDesc->unique = (keyInfo->flags & HA_NOSAME); - indexDesc->primaryKey = (srvTable->s->primary_key == (uint)indexId); + indexDesc->primaryKey = isPrimaryKey(srvTable, indexId); // Clean up the index name for internal use @@ -2151,7 +2166,7 @@ int StorageInterface::getMySqlError(int DBUG_PRINT("info", ("StorageErrorBadKey")); return (HA_ERR_WRONG_INDEX); - case StorageErrorTableExits: + case StorageErrorTableExists: DBUG_PRINT("info", ("StorageErrorTableExits")); return (HA_ERR_TABLE_EXIST); @@ -2557,10 +2572,6 @@ int StorageInterface::addColumn(THD* thd { int ret; int64 incrementValue = 0; - /*** - const char *tableName = storageTable->getName(); - const char *schemaName = storageTable->getSchemaName(); - ***/ CmdGen gen; genTable(alteredTable, &gen); @@ -2815,7 +2826,9 @@ int StorageInterface::genTable(TABLE* sr sep = ",\n"; } - if (srvTable->s->primary_key < srvTable->s->keys) + // Confirm that primary_key is actually a primary key + + if (isPrimaryKey(srvTable, srvTable->s->primary_key)) { KEY *key = srvTable->key_info + srvTable->s->primary_key; gen->gen(",\n primary key "); === modified file 'storage/falcon/ha_falcon.h' --- a/storage/falcon/ha_falcon.h 2009-06-24 21:28:30 +0000 +++ b/storage/falcon/ha_falcon.h 2009-06-28 18:58:38 +0000 @@ -146,6 +146,7 @@ public: int createIndex(const char *schemaName, const char *tableName, TABLE *srvTable, int indexId); int dropIndex(const char *schemaName, const char *tableName, TABLE *srvTable, int indexId, bool online); void getKeyDesc(TABLE *srvTable, int indexId, StorageIndexDesc *indexInfo); + bool isPrimaryKey(TABLE *srvTable, uint indexId); void startTransaction(void); bool threadSwitch(THD *newThread); int threadSwitchError(void); --===============0405483135== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/john.embretsen@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: john.embretsen@stripped # target_branch: file:///export/home/tmp/je159969/mysql-dev/bzr-\ # repos/mysql-6.0-falcon-to-merge/ # testament_sha1: 9c573ac072b8c964994a33c7b871cb9524b1d4b7 # timestamp: 2009-07-03 13:41:52 +0200 # source_branch: file:///export/home/tmp/je159969/mysql-dev/bzr-\ # repos/mysql-6.0/ # base_revision_id: john.embretsen@stripped\ # ddms9bozoln3qlkz # # Begin bundle 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 tocrpdiboevfEf/F3JFOFCQp9mwkgA== --===============0405483135==--