diff --git a/Interfaces/DBView.xib b/Interfaces/DBView.xib index 9a281c0b5..bd90e3f4e 100644 --- a/Interfaces/DBView.xib +++ b/Interfaces/DBView.xib @@ -46,7 +46,6 @@ - @@ -1731,7 +1730,7 @@ Gw - + @@ -2737,7 +2736,7 @@ Gw - + @@ -3064,9 +3063,45 @@ Gw + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -4089,9 +4124,6 @@ Gw - - - @@ -4340,7 +4372,6 @@ Gw - @@ -4382,6 +4413,7 @@ Gw + @@ -4389,6 +4421,7 @@ Gw + @@ -4411,7 +4444,6 @@ Gw - @@ -4563,12 +4595,6 @@ Gw - - - - - - @@ -4858,7 +4884,7 @@ Gw - + @@ -4907,7 +4933,7 @@ Gw - + diff --git a/Resources/Localization/en.lproj/Localizable.strings b/Resources/Localization/en.lproj/Localizable.strings index f790d7e30..55fb3906d 100644 --- a/Resources/Localization/en.lproj/Localizable.strings +++ b/Resources/Localization/en.lproj/Localizable.strings @@ -2803,7 +2803,10 @@ "Themes Installation Error" = "Themes Installation Error"; /* message of panel when table content cannot be copied */ -"There have been errors while copying table content. Please control the new table." = "There have been errors while copying table content. Please control the new table."; +"There have been errors while copying table content. Please check the new table." = "There have been errors while copying table content. Please check the new table."; + +/* Cannot duplicate a table with triggers to a different database */ +"Cannot duplicate a table with triggers to a different database." = "Cannot duplicate a table with triggers to a different database."; /* text shown when query was successfull */ "There were no errors." = "There were no errors."; diff --git a/Source/Controllers/DataControllers/SPTableData.m b/Source/Controllers/DataControllers/SPTableData.m index 830ae2616..4f716d81e 100644 --- a/Source/Controllers/DataControllers/SPTableData.m +++ b/Source/Controllers/DataControllers/SPTableData.m @@ -473,9 +473,9 @@ - (NSDictionary *) informationForTable:(NSString *)tableName [tableListInstance deselectAllTables]; [tableListInstance updateTables:self]; } - - [NSAlert createWarningAlertWithTitle:NSLocalizedString(@"Error retrieving table information", @"error retrieving table information message") message:errorMessage callback:nil]; - + SPMainQSync(^{ + [NSAlert createWarningAlertWithTitle:NSLocalizedString(@"Error retrieving table information", @"error retrieving table information message") message:errorMessage callback:nil]; + }); if (changeEncoding) [mySQLConnection restoreStoredEncoding]; } @@ -971,7 +971,9 @@ - (BOOL)updateStatusInformationForCurrentTable // Check for any errors, only displaying them if the connection hasn't been terminated if ([mySQLConnection queryErrored]) { if ([mySQLConnection isConnected]) { - [NSAlert createWarningAlertWithTitle:NSLocalizedString(@"Error", @"error") message:[NSString stringWithFormat:NSLocalizedString(@"An error occurred while retrieving status data.\n\nMySQL said: %@", @"message of panel when retrieving view information failed"), [mySQLConnection lastErrorMessage]] callback:nil]; + SPMainQSync(^{ + [NSAlert createWarningAlertWithTitle:NSLocalizedString(@"Error", @"error") message:[NSString stringWithFormat:NSLocalizedString(@"An error occurred while retrieving status data.\n\nMySQL said: %@", @"message of panel when retrieving view information failed"), [self->mySQLConnection lastErrorMessage]] callback:nil]; + }); if (changeEncoding) [mySQLConnection restoreStoredEncoding]; } pthread_mutex_unlock(&dataProcessingLock); diff --git a/Source/Controllers/MainViewControllers/ConnectionView/SPConnectionController.m b/Source/Controllers/MainViewControllers/ConnectionView/SPConnectionController.m index f6178beb3..3dec03df9 100644 --- a/Source/Controllers/MainViewControllers/ConnectionView/SPConnectionController.m +++ b/Source/Controllers/MainViewControllers/ConnectionView/SPConnectionController.m @@ -803,11 +803,6 @@ - (void)updateFavoriteSelection:(id)sender // Update key-value properties from the selected favourite, using empty strings where not found NSDictionary *fav = [[node representedObject] nodeFavorite]; - // Don't prefill anything if we are not using favorite - if (!fav) { - return; - } - // Keep a copy of the favorite as it currently stands currentFavorite = [fav copy]; @@ -885,12 +880,14 @@ - (void)updateFavoriteSelection:(id)sender // Check whether the password exists in the keychain, and if so add it; also record the // keychain details so we can pass around only those details if the password doesn't change - connectionKeychainItemName = [keychain nameForFavoriteName:[fav objectForKey:SPFavoriteNameKey] id:[fav objectForKey:SPFavoriteIDKey]]; - connectionKeychainItemAccount = [keychain accountForUser:[fav objectForKey:SPFavoriteUserKey] host:(([self type] == SPSocketConnection) ? @"localhost" : [fav objectForKey:SPFavoriteHostKey]) database:[fav objectForKey:SPFavoriteDatabaseKey]]; + connectionKeychainItemName = !fav ? nil : [keychain nameForFavoriteName:[fav objectForKey:SPFavoriteNameKey] id:[fav objectForKey:SPFavoriteIDKey]]; + connectionKeychainItemAccount = !fav ? nil : [keychain accountForUser:[fav objectForKey:SPFavoriteUserKey] host:(([self type] == SPSocketConnection) ? @"localhost" : [fav objectForKey:SPFavoriteHostKey]) database:[fav objectForKey:SPFavoriteDatabaseKey]]; - [self setPassword:[keychain getPasswordForName:connectionKeychainItemName account:connectionKeychainItemAccount]]; + if(fav) { + [self setPassword:[keychain getPasswordForName:connectionKeychainItemName account:connectionKeychainItemAccount]]; + } - if (![[self password] length]) { + if (!fav || ![[self password] length]) { [self setPassword:nil]; } @@ -898,12 +895,14 @@ - (void)updateFavoriteSelection:(id)sender if ([fav objectForKey:SPFavoriteIDKey]) [self setConnectionKeychainID:[[fav objectForKey:SPFavoriteIDKey] stringValue]]; // And the same for the SSH password - connectionSSHKeychainItemName = [keychain nameForSSHForFavoriteName:[fav objectForKey:SPFavoriteNameKey] id:[fav objectForKey:SPFavoriteIDKey]]; - connectionSSHKeychainItemAccount = [keychain accountForSSHUser:[fav objectForKey:SPFavoriteSSHUserKey] sshHost:[fav objectForKey:SPFavoriteSSHHostKey]]; + connectionSSHKeychainItemName = !fav ? nil : [keychain nameForSSHForFavoriteName:[fav objectForKey:SPFavoriteNameKey] id:[fav objectForKey:SPFavoriteIDKey]]; + connectionSSHKeychainItemAccount = !fav ? nil : [keychain accountForSSHUser:[fav objectForKey:SPFavoriteSSHUserKey] sshHost:[fav objectForKey:SPFavoriteSSHHostKey]]; - [self setSshPassword:[keychain getPasswordForName:connectionSSHKeychainItemName account:connectionSSHKeychainItemAccount]]; + if(fav) { + [self setSshPassword:[keychain getPasswordForName:connectionSSHKeychainItemName account:connectionSSHKeychainItemAccount]]; + } - if (![[self sshPassword] length]) { + if (!fav || ![[self sshPassword] length]) { [self setSshPassword:nil]; } diff --git a/Source/Controllers/MainViewControllers/TableContent/SPTableContent.m b/Source/Controllers/MainViewControllers/TableContent/SPTableContent.m index 466a21409..470acd285 100644 --- a/Source/Controllers/MainViewControllers/TableContent/SPTableContent.m +++ b/Source/Controllers/MainViewControllers/TableContent/SPTableContent.m @@ -881,12 +881,15 @@ - (void) loadTableValues if ([mySQLConnection queryErrored] && ![mySQLConnection lastQueryWasCancelled]) { if(activeFilter == SPTableContentFilterSourceRuleFilter || activeFilter == SPTableContentFilterSourceNone) { NSString *errorDetail; - if([filterString length]) + if([filterString length]){ errorDetail = [NSString stringWithFormat:NSLocalizedString(@"The table data couldn't be loaded presumably due to used filter clause. \n\nMySQL said: %@", @"message of panel when loading of table failed and presumably due to used filter argument"), [mySQLConnection lastErrorMessage]]; - else + } + else{ errorDetail = [NSString stringWithFormat:NSLocalizedString(@"The table data couldn't be loaded.\n\nMySQL said: %@", @"message of panel when loading of table failed"), [mySQLConnection lastErrorMessage]]; - - [NSAlert createWarningAlertWithTitle:NSLocalizedString(@"Error", @"error") message:errorDetail callback:nil]; + SPMainQSync(^{ + [NSAlert createWarningAlertWithTitle:NSLocalizedString(@"Error", @"error") message:errorDetail callback:nil]; + }); + } } // Filter task came from filter table else if(activeFilter == SPTableContentFilterSourceTableFilter) { diff --git a/Source/Controllers/SubviewControllers/SPTablesList.h b/Source/Controllers/SubviewControllers/SPTablesList.h index 018e630cb..3996f183a 100644 --- a/Source/Controllers/SubviewControllers/SPTablesList.h +++ b/Source/Controllers/SubviewControllers/SPTablesList.h @@ -72,6 +72,9 @@ IBOutlet NSPopUpButton *tableTypeButton; IBOutlet NSButton *toolbarAddButton; + __weak IBOutlet NSPopUpButton *chooseDatabaseButton; + __weak IBOutlet NSTextField *copyTableToNewDatabaseField; + __weak IBOutlet NSTextField *copyTableToNewDatabaseMessageField; IBOutlet NSPopUpButton *toolbarActionsButton; IBOutlet NSButton *toolbarReloadButton; IBOutlet NSButton *addTableButton; diff --git a/Source/Controllers/SubviewControllers/SPTablesList.m b/Source/Controllers/SubviewControllers/SPTablesList.m index d5a8618bf..79b8fa43b 100644 --- a/Source/Controllers/SubviewControllers/SPTablesList.m +++ b/Source/Controllers/SubviewControllers/SPTablesList.m @@ -591,6 +591,8 @@ - (IBAction)copyTable:(id)sender if ([tablesListView numberOfSelectedRows] != 1) return; if (![tableSourceInstance saveRowOnDeselect] || ![tableContentInstance saveRowOnDeselect]) return; + [[self onMainThread] setDatabases:nil]; + [[tableDocumentInstance parentWindow] endEditingFor:nil]; NSInteger objectType = [[filteredTableTypes objectAtIndex:[tablesListView selectedRow]] integerValue]; @@ -629,6 +631,37 @@ - (IBAction)copyTable:(id)sender }]; } + +- (IBAction)setDatabases:(id)sender; +{ + if (!chooseDatabaseButton) return; + + [chooseDatabaseButton removeAllItems]; + + [chooseDatabaseButton addItemWithTitle:NSLocalizedString(@"Choose Database...", @"menu item for choose db")]; + [[chooseDatabaseButton menu] addItem:[NSMenuItem separatorItem]]; + [[chooseDatabaseButton menu] addItemWithTitle:NSLocalizedString(@"Refresh Databases", @"menu item to refresh databases") action:@selector(setDatabases:) keyEquivalent:@""]; + [[chooseDatabaseButton menu] addItem:[NSMenuItem separatorItem]]; + + NSArray *theDatabaseList = [mySQLConnection databases]; + + NSMutableArray *allDatabases = [[NSMutableArray alloc] initWithCapacity:[theDatabaseList count]]; + + for (NSString *databaseName in theDatabaseList) + { + [allDatabases addObject:databaseName]; + } + + // Add user databases + for (NSString *database in allDatabases) + { + [chooseDatabaseButton addItemWithTitle:database]; + } + + [chooseDatabaseButton itemAtIndex:1].enabled = YES; + + (![mySQLConnection database]) ? [chooseDatabaseButton selectItemAtIndex:0] : [chooseDatabaseButton selectItemWithTitle:[mySQLConnection database]]; +} /** * This action starts editing the table name in the table list */ @@ -2330,14 +2363,25 @@ - (void)_addTableWithDetails:(NSDictionary *)tableDetails - (void)_copyTable { NSString *tableType = @""; + NSString *tempTableName = nil; + NSString *tableName = [copyTableNameField stringValue]; - if ([[copyTableNameField stringValue] isEqualToString:@""]) { + if ([tableName isEqualToString:@""]) { [NSAlert createWarningAlertWithTitle:NSLocalizedString(@"Error", @"error") message:NSLocalizedString(@"Table must have a name.", @"message of panel when no name is given for table") callback:nil]; return; } BOOL copyTableContent = ([copyTableContentSwitch state] == NSOnState); + NSString *targetDatabaseName = [chooseDatabaseButton titleOfSelectedItem]; + + BOOL moveToDifferentDB = NO; + + if (![targetDatabaseName isEqualToString:mySQLConnection.database]){ + moveToDifferentDB = YES; + tempTableName = [NSString stringWithNewUUID]; + } + SPTableType tblType = (SPTableType)[[filteredTableTypes objectAtIndex:[tablesListView selectedRow]] integerValue]; // Set up the table type and whether content can be duplicated. The table type is used @@ -2385,9 +2429,18 @@ - (void)_copyTable scanner = [[NSScanner alloc] initWithString:[[queryResult getRowAsDictionary] objectForKey:@"Create View"]]; [scanner scanUpToString:@"AS" intoString:nil]; [scanner scanUpToString:@"" intoString:&scanString]; - [mySQLConnection queryString:[NSString stringWithFormat:@"CREATE VIEW %@ %@", [[copyTableNameField stringValue] backtickQuotedString], scanString]]; + [mySQLConnection queryString:[NSString stringWithFormat:@"CREATE VIEW %@ %@", [tableName backtickQuotedString], scanString]]; } else if(tblType == SPTableTypeTable){ + + // check for triggers: https://dev.mysql.com/doc/refman/5.7/en/rename-table.html + NSArray *triggers = [self->tableDataInstance triggers]; + + if (moveToDifferentDB == YES && triggers.count > 0){ + [NSAlert createWarningAlertWithTitle:NSLocalizedString(@"Warning", @"warning") message:NSLocalizedString(@"Cannot duplicate a table with triggers to a different database.", @"Cannot duplicate a table with triggers to a different database") callback:nil]; + return; + } + scanner = [[NSScanner alloc] initWithString:[[queryResult getRowAsDictionary] objectForKey:@"Create Table"]]; [scanner scanUpToString:@"(" intoString:nil]; [scanner scanUpToString:@"" intoString:&scanString]; @@ -2401,7 +2454,11 @@ - (void)_copyTable scanString = [scanString stringByReplacingOccurrencesOfRegex:[NSString stringWithFormat:@"AUTO_INCREMENT=[0-9]+ "] withString:@""]; } - [mySQLConnection queryString:[NSString stringWithFormat:@"CREATE TABLE %@ %@", [[copyTableNameField stringValue] backtickQuotedString], scanString]]; + NSString *queryStr = [NSString stringWithFormat:@"CREATE TABLE %@ %@", (moveToDifferentDB == NO) ? [tableName backtickQuotedString] : [tempTableName backtickQuotedString], scanString]; + + SPLog("queryStr = %@", queryStr); + + [mySQLConnection queryString:queryStr]; } else if(tblType == SPTableTypeFunc || tblType == SPTableTypeProc) { @@ -2427,17 +2484,17 @@ - (void)_copyTable NSString *tableSyntax = [[theResult getRowAsArray] objectAtIndex:2]; // replace the old name by the new one and drop the old one - [mySQLConnection queryString:[tableSyntax stringByReplacingOccurrencesOfRegex:[NSString stringWithFormat:@"(?<=%@ )(`[^`]+?`)", [tableType uppercaseString]] withString:[[copyTableNameField stringValue] backtickQuotedString]]]; + [mySQLConnection queryString:[tableSyntax stringByReplacingOccurrencesOfRegex:[NSString stringWithFormat:@"(?<=%@ )(`[^`]+?`)", [tableType uppercaseString]] withString:[tableName backtickQuotedString]]]; if ([mySQLConnection queryErrored]) { - [NSAlert createWarningAlertWithTitle:NSLocalizedString(@"Error", @"error") message:[NSString stringWithFormat:NSLocalizedString(@"Couldn't duplicate '%@'.\nMySQL said: %@", @"message of panel when an item cannot be renamed"), [copyTableNameField stringValue], [mySQLConnection lastErrorMessage]] callback:nil]; + [NSAlert createWarningAlertWithTitle:NSLocalizedString(@"Error", @"error") message:[NSString stringWithFormat:NSLocalizedString(@"Couldn't duplicate '%@'.\nMySQL said: %@", @"message of panel when an item cannot be renamed"), tableName, [mySQLConnection lastErrorMessage]] callback:nil]; } } if ([mySQLConnection queryErrored]) { //error while creating new table - [NSAlert createWarningAlertWithTitle:NSLocalizedString(@"Error", @"error") message:[NSString stringWithFormat:NSLocalizedString(@"Couldn't create '%@'.\nMySQL said: %@", @"message of panel when table cannot be created"), [copyTableNameField stringValue], [mySQLConnection lastErrorMessage]] callback:nil]; + [NSAlert createWarningAlertWithTitle:NSLocalizedString(@"Error", @"error") message:[NSString stringWithFormat:NSLocalizedString(@"Couldn't create '%@'.\nMySQL said: %@", @"message of panel when table cannot be created"), tableName, [mySQLConnection lastErrorMessage]] callback:nil]; return; } @@ -2445,54 +2502,89 @@ - (void)_copyTable //copy table content [mySQLConnection queryString:[NSString stringWithFormat: @"INSERT INTO %@ SELECT * FROM %@", - [[copyTableNameField stringValue] backtickQuotedString], + (moveToDifferentDB == NO) ? [tableName backtickQuotedString] : [tempTableName backtickQuotedString], [selectedTableName backtickQuotedString] ]]; if ([mySQLConnection queryErrored]) { - [NSAlert createWarningAlertWithTitle:NSLocalizedString(@"Warning", @"warning") message:NSLocalizedString(@"There have been errors while copying table content. Please control the new table.", @"message of panel when table content cannot be copied") callback:nil]; + [NSAlert createWarningAlertWithTitle:NSLocalizedString(@"Warning", @"warning") message:NSLocalizedString(@"There have been errors while copying table content. Please check the new table.", @"message of panel when table content cannot be copied") callback:nil]; } } - // Insert the new item into the tables list and select it. - NSInteger addItemAtIndex = NSNotFound; - for (NSUInteger i = 0; i < [tables count]; i++) { - NSInteger theTableType = [[tableTypes objectAtIndex:i] integerValue]; - if (theTableType == SPTableTypeNone) continue; - if ((theTableType == SPTableTypeView || theTableType == SPTableTypeTable) - && (tblType == SPTableTypeProc || tblType == SPTableTypeFunc)) { - continue; - } - if ((theTableType == SPTableTypeProc || theTableType == SPTableTypeFunc) - && (tblType == SPTableTypeView || tblType == SPTableTypeTable)) { - addItemAtIndex = i - 1; - break; + if (moveToDifferentDB == YES){ + SPLog(@"Copying table to new database, targetDatabaseName = %@", targetDatabaseName); + [self _moveTable:tableName from:mySQLConnection.database to:targetDatabaseName tempTable:tempTableName]; + + SPMainQSync(^{ + [self->mySQLConnection selectDatabase:targetDatabaseName]; + [self->tableDocumentInstance selectDatabase:targetDatabaseName item:nil]; + [self _renameTableOfType:SPTableTypeTableNewDB from:tempTableName to:tableName]; + }); + } + else{ + // Insert the new item into the tables list and select it. + NSInteger addItemAtIndex = NSNotFound; + for (NSUInteger i = 0; i < [tables count]; i++) { + NSInteger theTableType = [[tableTypes objectAtIndex:i] integerValue]; + if (theTableType == SPTableTypeNone) continue; + if ((theTableType == SPTableTypeView || theTableType == SPTableTypeTable) + && (tblType == SPTableTypeProc || tblType == SPTableTypeFunc)) { + continue; + } + if ((theTableType == SPTableTypeProc || theTableType == SPTableTypeFunc) + && (tblType == SPTableTypeView || tblType == SPTableTypeTable)) { + addItemAtIndex = i - 1; + break; + } + if ([tableName localizedCompare:[tables objectAtIndex:i]] == NSOrderedAscending) { + addItemAtIndex = i; + break; + } } - if ([[copyTableNameField stringValue] localizedCompare:[tables objectAtIndex:i]] == NSOrderedAscending) { - addItemAtIndex = i; - break; + if (addItemAtIndex == NSNotFound) { + [tables addObject:tableName]; + [tableTypes addObject:[NSNumber numberWithInteger:tblType]]; + } else { + [tables insertObject:tableName atIndex:addItemAtIndex]; + [tableTypes insertObject:[NSNumber numberWithInteger:tblType] atIndex:addItemAtIndex]; } + + // Set the selected table name and type, and use updateFilter to update the filter list and selection + + selectedTableName = [[NSString alloc] initWithString:tableName]; + selectedTableType = tblType; + + [self updateFilter:self]; + + [tablesListView scrollRowToVisible:[tablesListView selectedRow]]; + [tableDocumentInstance loadTable:selectedTableName ofType:selectedTableType]; + + // Query the structure of all databases in the background (mainly for completion) + [[tableDocumentInstance databaseStructureRetrieval] queryDbStructureInBackgroundWithUserInfo:@{@"forceUpdate" : @YES}]; } - if (addItemAtIndex == NSNotFound) { - [tables addObject:[copyTableNameField stringValue]]; - [tableTypes addObject:[NSNumber numberWithInteger:tblType]]; - } else { - [tables insertObject:[copyTableNameField stringValue] atIndex:addItemAtIndex]; - [tableTypes insertObject:[NSNumber numberWithInteger:tblType] atIndex:addItemAtIndex]; - } +} - // Set the selected table name and type, and use updateFilter to update the filter list and selection - selectedTableName = [[NSString alloc] initWithString:[copyTableNameField stringValue]]; - selectedTableType = tblType; +- (void)_moveTable:(NSString *)newTableName from:(NSString *)sourceDatabaseName to:(NSString *)destinationDatabaseName tempTable:(NSString *)tempTableName{ - [self updateFilter:self]; + // check if the name really changed + if ([sourceDatabaseName isEqualToString:destinationDatabaseName]) return; - [tablesListView scrollRowToVisible:[tablesListView selectedRow]]; - [tableDocumentInstance loadTable:selectedTableName ofType:selectedTableType]; + if(destinationDatabaseName && [destinationDatabaseName length]) { + NSString *query = [NSString stringWithFormat: @"ALTER TABLE %@.%@ RENAME %@.%@", [sourceDatabaseName backtickQuotedString], [tempTableName backtickQuotedString], [destinationDatabaseName backtickQuotedString], [tempTableName backtickQuotedString]]; - // Query the structure of all databases in the background (mainly for completion) - [[tableDocumentInstance databaseStructureRetrieval] queryDbStructureInBackgroundWithUserInfo:@{@"forceUpdate" : @YES}]; + SPLog(@"QUERY is %@", query); + + [mySQLConnection queryString:query]; + + SPMainQSync(^{ + if ([self->mySQLConnection queryErrored]) { + [NSAlert createWarningAlertWithTitle:NSLocalizedString(@"Warning", @"warning") message:NSLocalizedString(@"There have been errors while copying table content. Please check the new table.", @"message of panel when table content cannot be copied") callback:nil]; + + SPLog(@"ERROR: %@", [self->mySQLConnection lastErrorMessage]); + } + }); + } } /** @@ -2531,14 +2623,24 @@ - (void)_renameTableOfType:(SPTableType)tableType from:(NSString *)oldTableName } //check if we are trying to rename a TABLE or a VIEW - if (tableType == SPTableTypeView || tableType == SPTableTypeTable) { + if (tableType == SPTableTypeView || tableType == SPTableTypeTable || tableType == SPTableTypeTableNewDB) { // we can use the rename table statement [mySQLConnection queryString:[NSString stringWithFormat:@"RENAME TABLE %@ TO %@", [oldTableName backtickQuotedString], [newTableName backtickQuotedString]]]; // check for errors if ([mySQLConnection queryErrored]) { - [NSException raise:@"MySQL Error" format:NSLocalizedString(@"An error occurred while renaming '%@'.\n\nMySQL said: %@", @"rename table error informative message"), oldTableName, [mySQLConnection lastErrorMessage]]; + + if(mySQLConnection.lastErrorID == 1050 && tableType == SPTableTypeTableNewDB){ + NSString *message = [NSString stringWithFormat:NSLocalizedString(@"An error occurred while renaming '%@'.\n\nMySQL said: %@", @"rename table error informative message"), oldTableName, [mySQLConnection lastErrorMessage]]; + + [NSAlert createWarningAlertWithTitle:NSLocalizedString(@"Warning", @"warning") message:message callback:nil]; + + return; + } + else{ + [NSException raise:@"MySQL Error" format:NSLocalizedString(@"An error occurred while renaming '%@'.\n\nMySQL said: %@", @"rename table error informative message"), oldTableName, [mySQLConnection lastErrorMessage]]; + } } - + return; } diff --git a/Source/Other/Data/SPConstants.h b/Source/Other/Data/SPConstants.h index 71fa4d561..6097aac4a 100755 --- a/Source/Other/Data/SPConstants.h +++ b/Source/Other/Data/SPConstants.h @@ -106,7 +106,8 @@ typedef enum SPTableTypeView = 1, SPTableTypeProc = 2, SPTableTypeFunc = 3, - SPTableTypeEvent = 4 + SPTableTypeEvent = 4, + SPTableTypeTableNewDB = 5 } SPTableType; // Content views diff --git a/UnitTests/SPMutableArrayAdditionsTests.m b/UnitTests/SPMutableArrayAdditionsTests.m index 82fec4001..fcbe152c0 100644 --- a/UnitTests/SPMutableArrayAdditionsTests.m +++ b/UnitTests/SPMutableArrayAdditionsTests.m @@ -29,7 +29,7 @@ // More info at #import "SPMutableArrayAdditions.h" - +#import "NSMutableArray-MultipleSort.h" #import /** @@ -52,10 +52,60 @@ - (void)testReverse { NSMutableArray *testArray = [NSMutableArray arrayWithObjects:@"1", @"2", @"3", @"4", @"5", nil]; NSMutableArray *expectedArray = [NSMutableArray arrayWithObjects:@"5", @"4", @"3", @"2", @"1", nil]; - + [testArray reverse]; XCTAssertEqualObjects(testArray, expectedArray, @"The reversed array should look like: %@, but actually looks like: %@", expectedArray, testArray); } +- (void)testSort +{ + NSMutableArray *testArray = [NSMutableArray arrayWithObjects:@"o" ,@"n" ,@"m" ,@"l" ,@"k" ,@"j" ,@"i" ,@"h" ,@"g" ,@"f" ,@"e" ,@"d" ,@"c" ,@"b" ,@"a", nil]; + NSMutableArray *expectedArray = [NSMutableArray arrayWithObjects:@"a", @"b", @"c", @"d", @"e", @"f", @"g", @"h", @"i", @"j", @"k", @"l", @"m", @"n", @"o", nil]; + + NSMutableArray *sortedArray = [NSMutableArray array]; + + NSMutableArray *PairedMutableArray = [NSMutableArray arrayWithObjects:@0, @0, @0, @0, @0, @0, @0, @0, @0, @0, @0, @0, @0, @0, @0, @0, nil]; + + [sortedArray setArray:[testArray sortedArrayUsingSelector:@selector(localizedCompare:)]]; + + XCTAssertEqualObjects(sortedArray, expectedArray, @"The sorted array should look like: %@, but actually looks like: %@", expectedArray, testArray); + + [testArray sortArrayUsingSelector:@selector(localizedCompare:) withPairedMutableArrays:PairedMutableArray, nil]; + + XCTAssertEqualObjects(testArray, expectedArray, @"The sorted array should look like: %@, but actually looks like: %@", expectedArray, testArray); +} + + +- (void)testPerformance_withPairedMutableArrays { + // this is on main thread + [self measureBlock:^{ + // Put the code you want to measure the time of here. + NSMutableArray *testArray = [NSMutableArray arrayWithObjects:@"o" ,@"n" ,@"m" ,@"l" ,@"k" ,@"j" ,@"i" ,@"h" ,@"g" ,@"f" ,@"e" ,@"d" ,@"c" ,@"b" ,@"a", nil]; + NSMutableArray *PairedMutableArray = [NSMutableArray arrayWithObjects:@0, @0, @0, @0, @0, @0, @0, @0, @0, @0, @0, @0, @0, @0, @0, @0, nil]; + + int const iterations = 100000; + for (int i = 0; i < iterations; i++) { + @autoreleasepool { + [testArray sortArrayUsingSelector:@selector(localizedCompare:) withPairedMutableArrays:PairedMutableArray, nil]; + } + } + }]; +} + +- (void)testPerformance_sortArrayUsingSelector { + // this is on main thread + [self measureBlock:^{ + // Put the code you want to measure the time of here. + NSMutableArray *testArray = [NSMutableArray arrayWithObjects:@"o" ,@"n" ,@"m" ,@"l" ,@"k" ,@"j" ,@"i" ,@"h" ,@"g" ,@"f" ,@"e" ,@"d" ,@"c" ,@"b" ,@"a", nil]; + NSMutableArray *sortedArray = [NSMutableArray array]; + int const iterations = 100000; + for (int i = 0; i < iterations; i++) { + @autoreleasepool { + [sortedArray setArray:[testArray sortedArrayUsingSelector:@selector(localizedCompare:)]]; + } + } + }]; +} + @end diff --git a/sequel-ace.xcodeproj/project.pbxproj b/sequel-ace.xcodeproj/project.pbxproj index 4219e7789..4251c6cba 100644 --- a/sequel-ace.xcodeproj/project.pbxproj +++ b/sequel-ace.xcodeproj/project.pbxproj @@ -122,6 +122,7 @@ 1A4CB06B25926D7C00EDF804 /* StringRegexExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A4CB03325923C4B00EDF804 /* StringRegexExtension.swift */; }; 1A564F74237E2E4958CA593A /* SPPillAttachmentCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A56463D14569A0B56EE8BAC /* SPPillAttachmentCell.m */; }; 1A5A83532545DA8B00EDC196 /* SPObjectAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 584D878A15140FEB00F24774 /* SPObjectAdditions.m */; }; + 1A6377D4259B414400B1E96D /* SecureBookmark.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A96E4B42588F34C0055F5F5 /* SecureBookmark.swift */; }; 1A6447912588CD8B00927DB3 /* License.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 17CC993A10B4C9C80034CD7A /* License.rtf */; }; 1A6447992588CD9200927DB3 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 517E44FB257A94C400ED333B /* Credits.rtf */; }; 1A85CB8D2493BC4A00B57B93 /* SPSyncTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A85CB8C2493BC4A00B57B93 /* SPSyncTests.m */; }; @@ -132,8 +133,8 @@ 1A9498C125517191000BC793 /* DateExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A94988D25516057000BC793 /* DateExtension.swift */; }; 1A9498DE2551776D000BC793 /* DateFormatterExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A1EE9492551185D0056FECD /* DateFormatterExtension.swift */; }; 1A94997A25518549000BC793 /* DateComponentsFormatterExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A9D83A325514E740024B563 /* DateComponentsFormatterExtension.swift */; }; - 1A96E4B62588F34C0055F5F5 /* SecureBookmark.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A96E4B42588F34C0055F5F5 /* SecureBookmark.swift */; }; 1A96E4B72588F34C0055F5F5 /* SecureBookmarkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A96E4B52588F34C0055F5F5 /* SecureBookmarkManager.swift */; }; + 1A9A40D525875EC9009F0E71 /* NSMutableArray-MultipleSort.m in Sources */ = {isa = PBXBuildFile; fileRef = 584192A0101E57BB0089807F /* NSMutableArray-MultipleSort.m */; }; 1A9D83A425514E740024B563 /* DateComponentsFormatterExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A9D83A325514E740024B563 /* DateComponentsFormatterExtension.swift */; }; 1A9EB9AE25651F5000FE60FF /* SQLiteHistoryManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A9EB9AD25651F5000FE60FF /* SQLiteHistoryManager.swift */; }; 1A9F343F257B0DBE0062EC87 /* SPBundleManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A9F343E257B0DBE0062EC87 /* SPBundleManager.m */; }; @@ -3002,6 +3003,7 @@ 17DB5F441555CA300046834B /* SPMutableArrayAdditions.m in Sources */, 1717FA401558313A0065C036 /* RegexKitLite.m in Sources */, 50D3C35C1A771C4C00B5429C /* SPParserUtilsTest.m in Sources */, + 1A9A40D525875EC9009F0E71 /* NSMutableArray-MultipleSort.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3171,7 +3173,6 @@ 1785EB6A127DD79300F468C8 /* SPEditorPreferencePane.m in Sources */, 17FDB04C1280778B00DBBBC2 /* SPFontPreviewTextField.m in Sources */, 17D3C22212859E070047709F /* SPFavoriteNode.m in Sources */, - 1A96E4B62588F34C0055F5F5 /* SecureBookmark.swift in Sources */, 506CE9311A311C6C0039F736 /* SPRuleFilterController.m in Sources */, 17D3C66E128AD4710047709F /* SPFavoritesController.m in Sources */, 513515E62593568B001E4533 /* PSMOverflowPopUpButton.m in Sources */, @@ -3214,6 +3215,7 @@ 50E217B318174246009D3580 /* SPColorSelectorView.m in Sources */, 50E217B618174280009D3580 /* SPFavoriteColorSupport.m in Sources */, 513515E82593568B001E4533 /* PSMTabBarCell.m in Sources */, + 1A6377D4259B414400B1E96D /* SecureBookmark.swift in Sources */, 1A564F74237E2E4958CA593A /* SPPillAttachmentCell.m in Sources */, 9BE76F2886901784E4FD2321 /* SPFilterTableController.m in Sources */, 9BE765EBBDFD2F121C13D274 /* SPFillView.m in Sources */,