diff options
author | Bibiko <bibiko@eva.mpg.de> | 2010-09-09 13:48:26 +0000 |
---|---|---|
committer | Bibiko <bibiko@eva.mpg.de> | 2010-09-09 13:48:26 +0000 |
commit | 0e7ab97ce059e054886288401100586e59188ad3 (patch) | |
tree | c8c99fba4787fb5f44e91bc2a053a9defa6253ba /Source/SPTableStructure.m | |
parent | cc99469638a22d68a01650bf36adc3b99ae817d1 (diff) | |
download | sequelpro-0e7ab97ce059e054886288401100586e59188ad3.tar.gz sequelpro-0e7ab97ce059e054886288401100586e59188ad3.tar.bz2 sequelpro-0e7ab97ce059e054886288401100586e59188ad3.zip |
• TableStructure
- changed: field information are retrieved via [SPTableData columns]; mainly to get all infos like comment, encoding, and collation
- added the chance to edit encoding, collation, and comment for each field
Note: This is work is progress - not yet optimized but fully workable. Due to GUI I simply added these three columns - improvements will follow
Diffstat (limited to 'Source/SPTableStructure.m')
-rw-r--r-- | Source/SPTableStructure.m | 719 |
1 files changed, 377 insertions, 342 deletions
diff --git a/Source/SPTableStructure.m b/Source/SPTableStructure.m index ac490b82..2ec324a7 100644 --- a/Source/SPTableStructure.m +++ b/Source/SPTableStructure.m @@ -55,14 +55,14 @@ tableFields = [[NSMutableArray alloc] init]; oldRow = [[NSMutableDictionary alloc] init]; enumFields = [[NSMutableDictionary alloc] init]; - + currentlyEditingRow = -1; defaultValues = nil; selectedTable = nil; - + prefs = [NSUserDefaults standardUserDefaults]; } - + return self; } @@ -73,15 +73,17 @@ { // Set the structure and index view's vertical gridlines if required [tableSourceView setGridStyleMask:([prefs boolForKey:SPDisplayTableViewVerticalGridlines]) ? NSTableViewSolidVerticalGridLineMask : NSTableViewGridNone]; - + // Set the strutcture and index view's font BOOL useMonospacedFont = [prefs boolForKey:SPUseMonospacedFonts]; - + for (NSTableColumn *fieldColumn in [tableSourceView tableColumns]) { [[fieldColumn dataCell] setFont:(useMonospacedFont) ? [NSFont fontWithName:SPDefaultMonospacedFontName size:[NSFont smallSystemFontSize]] : [NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; } - + + databaseDataInstance = [tableDocumentInstance valueForKeyPath:@"databaseDataInstance"]; + // Add observers for document task activity [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(startDocumentTaskForTab:) @@ -100,12 +102,10 @@ */ - (void)loadTable:(NSString *)aTable { - NSArray *theTableFields, *theTableIndexes; + NSMutableArray *theTableFields = [NSMutableArray array]; + NSArray *theTableIndexes; NSMutableDictionary *theTableEnumLists = [NSMutableDictionary dictionary]; - NSArray *extrasArray; - NSMutableDictionary *tempDefaultValues; NSInteger i; - SPSQLParser *fieldParser; // Check whether a save of the current row is required. if ( ![[self onMainThread] saveRowOnDeselect] ) return; @@ -115,32 +115,10 @@ [[self onMainThread] setTableDetails:nil]; return; } - - // Send the query started/working notification - [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:@"SMySQLQueryWillBePerformed" object:tableDocumentInstance]; - - // Retrieve the column information for this table. - // TODO: update this and indexes to use TableData at some point - tiny bit more parsing required... - tableSourceResult = [[mySQLConnection queryString:[NSString stringWithFormat:@"SHOW COLUMNS FROM %@", [aTable backtickQuotedString]]] retain]; - - // If an error occurred, reset the interface and abort - if ([mySQLConnection queryErrored]) { - [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance]; - [[self onMainThread] setTableDetails:nil]; - - if ([mySQLConnection isConnected]) { - SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), - nil, nil, [NSApp mainWindow], self, nil, nil, - [NSString stringWithFormat:NSLocalizedString(@"An error occurred while retrieving information.\nMySQL said: %@", @"message of panel when retrieving information failed"), - [mySQLConnection getLastErrorMessage]]); - } - if (tableSourceResult) [tableSourceResult release]; - return; - } - // Process the field names into a local array of dictionaries - theTableFields = [self fetchResultAsArray:tableSourceResult]; - [tableSourceResult release]; + // Make a mutable copy out of the cached [tableDataInstance columns] since we're adding infos + for(id col in [tableDataInstance columns]) + [theTableFields addObject:[col mutableCopy]]; // Retrieve the indexes for the table indexResult = [[mySQLConnection queryString:[NSString stringWithFormat:@"SHOW INDEX FROM %@", [aTable backtickQuotedString]]] retain]; @@ -151,7 +129,7 @@ [[self onMainThread] setTableDetails:nil]; if ([mySQLConnection isConnected]) { - SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), + SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [NSApp mainWindow], self, nil, nil, [NSString stringWithFormat:NSLocalizedString(@"An error occurred while retrieving information.\nMySQL said: %@", @"message of panel when retrieving information failed"), [mySQLConnection getLastErrorMessage]]); @@ -164,72 +142,95 @@ theTableIndexes = [self fetchResultAsArray:indexResult]; [indexResult release]; - // Process all the fields to normalise keys and add additional information - for (id theField in theTableFields) { - NSString *type; - NSString *length; - NSString *extras; - - // Set up the field parser with the type definition - fieldParser = [[SPSQLParser alloc] initWithString:[theField objectForKey:@"Type"]]; - - // Pull out the field type; if no brackets are found, this returns nil - in which case simple values can be used. - type = [fieldParser trimAndReturnStringToCharacter:'(' trimmingInclusively:YES returningInclusively:NO]; - if (!type) { - type = [NSString stringWithString:fieldParser]; - length = @""; - extras = @""; - } else { - - // Pull out the length, which may include enum/set values - length = [fieldParser trimAndReturnStringToCharacter:')' trimmingInclusively:YES returningInclusively:NO]; - if (!length) length = @""; + // Set the Key column + for(NSDictionary* theIndex in theTableIndexes) { + for(id field in theTableFields) { + if([[field objectForKey:@"name"] isEqualToString:[theIndex objectForKey:@"Column_name"]]) { + if([[theIndex objectForKey:@"Key_name"] isEqualToString:@"PRIMARY"]) + [field setObject:@"PRI" forKey:@"Key"]; + else + [field setObject:(([[theIndex objectForKey:@"Non_unique"] isEqualToString:@"1"]) ? @"MUL" : @"UNI") forKey:@"Key"]; + break; + } + } + } - // Separate any remaining extras - extras = [NSString stringWithString:fieldParser]; - if (!extras) extras = @""; + // Set up the encoding PopUpButtonCell + NSArray *encodings = [databaseDataInstance getDatabaseCharacterSetEncodings]; + if (([encodings count] > 0) && ([tableDataInstance tableEncoding])) { + NSString *selectedTitle = @""; + [[[[tableSourceView tableColumns] objectAtIndex:10] dataCell] removeAllItems]; + [[[[tableSourceView tableColumns] objectAtIndex:10] dataCell] addItemWithTitle:@""]; + // Populate encoding popup button + for (NSDictionary *encoding in encodings) + { + NSString *menuItemTitle = (![encoding objectForKey:@"DESCRIPTION"]) ? [encoding objectForKey:@"CHARACTER_SET_NAME"] : [NSString stringWithFormat:@"%@ (%@)", [encoding objectForKey:@"DESCRIPTION"], [encoding objectForKey:@"CHARACTER_SET_NAME"]]; + [[[[tableSourceView tableColumns] objectAtIndex:10] dataCell] addItemWithTitle:menuItemTitle]; } + } + else { + [[[[tableSourceView tableColumns] objectAtIndex:10] dataCell] addItemWithTitle:NSLocalizedString(@"Not available", @"not available label")]; + } - [fieldParser release]; + // Process all the fields to normalise keys and add additional information + for (id theField in theTableFields) { - // Get possible values if the field is an enum or a set - if ([type isEqualToString:@"enum"] || [type isEqualToString:@"set"]) { - SPSQLParser *valueParser = [[SPSQLParser alloc] initWithString:length]; - NSMutableArray *possibleValues = [[NSMutableArray alloc] initWithArray:[valueParser splitStringByCharacter:',']]; - for (i = 0; i < [possibleValues count]; i++) { - [valueParser setString:[possibleValues objectAtIndex:i]]; - [possibleValues replaceObjectAtIndex:i withObject:[valueParser unquotedString]]; + // Select and re-map encoding and collation since [self dataSource] stores the choice as NSNumbers + NSString *fieldEncoding = @""; + NSInteger selectedIndex = 0; + if([theField objectForKey:@"encoding"]) { + for(id enc in encodings) { + if([[enc objectForKey:@"CHARACTER_SET_NAME"] isEqualToString:[theField objectForKey:@"encoding"]]) { + fieldEncoding = [theField objectForKey:@"encoding"]; + break; + } + selectedIndex++; } - [theTableEnumLists setObject:[NSArray arrayWithArray:possibleValues] forKey:[theField objectForKey:@"Field"]]; - [possibleValues release]; - [valueParser release]; + selectedIndex++; // due to leading @"" in popup list } - - // For timestamps check to see whether "on update CURRENT_TIMESTAMP" - not returned - // by SHOW COLUMNS - should be set from the table data store - if ([type isEqualToString:@"timestamp"] - && [[[tableDataInstance columnWithName:[theField objectForKey:@"Field"]] objectForKey:@"onupdatetimestamp"] integerValue]) - { - [theField setObject:@"on update CURRENT_TIMESTAMP" forKey:@"Extra"]; + [theField setObject:[NSNumber numberWithInt:selectedIndex] forKey:@"encoding"]; + selectedIndex = 0; + if([fieldEncoding length] && [theField objectForKey:@"collation"]) { + NSArray *theCollations = [databaseDataInstance getDatabaseCollationsForEncoding:fieldEncoding]; + for(id col in theCollations) { + if([[col objectForKey:@"COLLATION_NAME"] isEqualToString:[theField objectForKey:@"collation"]]) { + break; + } + selectedIndex++; + } + selectedIndex++; // due to leading @"" in popup list } + [theField setObject:[NSNumber numberWithInt:selectedIndex] forKey:@"collation"]; - // Scan extras for values like unsigned, zerofill, binary - extrasArray = [extras componentsSeparatedByString:@" "]; - for (id extra in extrasArray) { - if ([extra isEqualToString:@"unsigned"]) { - [theField setObject:@"1" forKey:@"unsigned"]; - } else if ([extra isEqualToString:@"zerofill"]) { - [theField setObject:@"1" forKey:@"zerofill"]; - } else if ([extra isEqualToString:@"binary"]) { - [theField setObject:@"1" forKey:@"binary"]; - } else { - if (![extra isEqualToString:@""]) - NSLog(@"ERROR: unknown option in field definition: %@", extra); - } + NSString *type = [[theField objectForKey:@"type"] uppercaseString]; + + // Get possible values if the field is an enum or a set + if (([type isEqualToString:@"ENUM"] || [type isEqualToString:@"SET"]) && [theField objectForKey:@"values"]) { + [theTableEnumLists setObject:[NSArray arrayWithArray:[theField objectForKey:@"values"]] forKey:[theField objectForKey:@"name"]]; + [theField setObject:[NSString stringWithFormat:@"'%@'", [[theField objectForKey:@"values"] componentsJoinedByString:@"','"]] forKey:@"length"]; } - [theField setObject:type forKey:@"Type"]; - [theField setObject:length forKey:@"Length"]; + // Join length and decimals if any + if ([theField objectForKey:@"decimals"]) + [theField setObject:[NSString stringWithFormat:@"%@,%@", [theField objectForKey:@"length"], [theField objectForKey:@"decimals"]] forKey:@"length"]; + + // Normalize default + if(![theField objectForKey:@"default"]) + [theField setObject:@"" forKey:@"default"]; + else if([[theField objectForKey:@"default"] isKindOfClass:[NSNull class]]) + [theField setObject:[prefs stringForKey:SPNullValue] forKey:@"default"]; + + // Init Extra field + [theField setObject:@"None" forKey:@"Extra"]; + + // Check for auto_increment and set Extra accordingly + if([[theField objectForKey:@"autoincrement"] integerValue]) + [theField setObject:@"auto_increment" forKey:@"Extra"]; + + // For timestamps check to see whether "on update CURRENT_TIMESTAMP" and set Extra accordingly + else if ([type isEqualToString:@"TIMESTAMP"] && [[theField objectForKey:@"onupdatetimestamp"] integerValue]) + [theField setObject:@"on update CURRENT_TIMESTAMP" forKey:@"Extra"]; + } // Set up the table details for the new table, and request an data/interface update @@ -243,7 +244,7 @@ // Send the query finished/work complete notification [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance]; - + } /** @@ -274,7 +275,7 @@ // Update the selected table name if (selectedTable) [selectedTable release], selectedTable = nil; if (newTableName) selectedTable = [[NSString alloc] initWithString:newTableName]; - + [indexesController setTable:selectedTable]; // Reset the table store and display @@ -301,27 +302,25 @@ // Update the fields and indexes stores [tableFields setArray:[tableDetails objectForKey:@"tableFields"]]; - + [indexesController setFields:tableFields]; [indexesController setIndexes:[tableDetails objectForKey:@"tableIndexes"]]; - + if (defaultValues) [defaultValues release], defaultValues = nil; - + newDefaultValues = [NSMutableDictionary dictionaryWithCapacity:[tableFields count]]; - - for (id theField in tableFields) - { - [newDefaultValues setObject:[theField objectForKey:@"Default"] forKey:[theField objectForKey:@"Field"]]; - } - + + for (id theField in tableFields) + [newDefaultValues setObject:[theField objectForKey:@"default"] forKey:[theField objectForKey:@"name"]]; + defaultValues = [[NSDictionary dictionaryWithDictionary:newDefaultValues] retain]; - + // Enable the edit table button [editTableButton setEnabled:enableInteraction]; // If a view is selected, disable the buttons; otherwise enable. BOOL editingEnabled = ([tablesListInstance tableType] == SPTableTypeTable) && enableInteraction; - + [addFieldButton setEnabled:editingEnabled]; [addIndexButton setEnabled:editingEnabled]; @@ -342,10 +341,10 @@ if ( ![self saveRowOnDeselect] ) return; NSInteger insertIndex = ([tableSourceView numberOfSelectedRows] == 0 ? [tableSourceView numberOfRows] : [tableSourceView selectedRow] + 1); - - [tableFields insertObject:[NSMutableDictionary - dictionaryWithObjects:[NSArray arrayWithObjects:@"", @"int", @"", @"0", @"0", @"0", ([prefs boolForKey:SPNewFieldsAllowNulls]) ? @"1" : @"0", @"", [prefs stringForKey:SPNullValue], @"None", nil] - forKeys:[NSArray arrayWithObjects:@"Field", @"Type", @"Length", @"unsigned", @"zerofill", @"binary", @"Null", @"Key", @"Default", @"Extra", nil]] + + [tableFields insertObject:[NSMutableDictionary + dictionaryWithObjects:[NSArray arrayWithObjects:@"", @"INT", @"", @"0", @"0", @"0", ([prefs boolForKey:SPNewFieldsAllowNulls]) ? @"1" : @"0", @"", [prefs stringForKey:SPNullValue], @"None", @"", @"", @"", nil] + forKeys:[NSArray arrayWithObjects:@"name", @"type", @"length", @"unsigned", @"zerofill", @"binary", @"null", @"Key", @"default", @"Extra", @"comment", @"encoding", @"collation", nil]] atIndex:insertIndex]; [tableSourceView reloadData]; @@ -373,10 +372,10 @@ // Check whether a save of the current row is required. if ( ![self saveRowOnDeselect] ) return; - + //add copy of selected row and go in edit mode tempRow = [NSMutableDictionary dictionaryWithDictionary:[tableFields objectAtIndex:rowToCopy]]; - [tempRow setObject:[[tempRow objectForKey:@"Field"] stringByAppendingString:@"Copy"] forKey:@"Field"]; + [tempRow setObject:[[tempRow objectForKey:@"name"] stringByAppendingString:@"Copy"] forKey:@"name"]; [tempRow setObject:@"" forKey:@"Key"]; [tempRow setObject:@"None" forKey:@"Extra"]; [tableFields addObject:tempRow]; @@ -397,31 +396,31 @@ // Check whether a save of the current row is required. if (![self saveRowOnDeselect]) return; - + NSInteger index = [tableSourceView selectedRow]; - + if ((index == -1) || (index > ([tableFields count] - 1))) return; // Check if the user tries to delete the last defined field in table // Note that because of better menu item validation, this check will now never evaluate to true. if ([tableSourceView numberOfRows] < 2) { NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Error while deleting field", @"Error while deleting field") - defaultButton:NSLocalizedString(@"OK", @"OK button") - alternateButton:nil - otherButton:nil + defaultButton:NSLocalizedString(@"OK", @"OK button") + alternateButton:nil + otherButton:nil informativeTextWithFormat:NSLocalizedString(@"You cannot delete the last field in a table. Delete the table instead.", @"You cannot delete the last field in a table. Delete the table instead.")]; [alert setAlertStyle:NSCriticalAlertStyle]; [alert beginSheetModalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"cannotremovefield"]; - + } - - NSString *field = [[tableFields objectAtIndex:index] objectForKey:@"Field"]; - + + NSString *field = [[tableFields objectAtIndex:index] objectForKey:@"name"]; + BOOL hasForeignKey = NO; NSString *referencedTable = @""; - + // Check to see whether the user is attempting to remove a field that has foreign key constraints and thus // would result in an error if not dropped before removing the field. for (NSDictionary *constraint in [tableDataInstance getConstraints]) @@ -435,22 +434,22 @@ } } } - + NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Delete field '%@'?", @"delete field message"), field] defaultButton:NSLocalizedString(@"Delete", @"delete button") - alternateButton:NSLocalizedString(@"Cancel", @"cancel button") - otherButton:nil + alternateButton:NSLocalizedString(@"Cancel", @"cancel button") + otherButton:nil informativeTextWithFormat:(hasForeignKey) ? [NSString stringWithFormat:NSLocalizedString(@"This field is part of a foreign key relationship with the table '%@'. This relationship must be removed before the field can be deleted.\n\nAre you sure you want to continue to delete the relationship and the field? This action cannot be undone.", @"delete field and foreign key informative message"), referencedTable] : [NSString stringWithFormat:NSLocalizedString(@"Are you sure you want to delete the field '%@'? This action cannot be undone.", @"delete field informative message"), field]]; - + [alert setAlertStyle:NSCriticalAlertStyle]; - + NSArray *buttons = [alert buttons]; - + // Change the alert's cancel button to have the key equivalent of return [[buttons objectAtIndex:0] setKeyEquivalent:@"d"]; [[buttons objectAtIndex:0] setKeyEquivalentModifierMask:NSCommandKeyMask]; [[buttons objectAtIndex:1] setKeyEquivalent:@"\r"]; - + [alert beginSheetModalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:@selector(removeFieldSheetDidEnd:returnCode:contextInfo:) contextInfo:(hasForeignKey) ? @"removeFieldAndForeignKey" : @"removeField"]; } @@ -460,19 +459,19 @@ - (IBAction)resetAutoIncrement:(id)sender { if ([sender tag] == 1) { - + [resetAutoIncrementLine setHidden:YES]; - + if ([[tableDocumentInstance valueForKeyPath:@"tableTabView"] indexOfTabViewItem:[[tableDocumentInstance valueForKeyPath:@"tableTabView"] selectedTabViewItem]] == 0) [resetAutoIncrementLine setHidden:NO]; - + // Begin the sheet [NSApp beginSheet:resetAutoIncrementSheet - modalForWindow:[tableDocumentInstance parentWindow] + modalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self - didEndSelector:@selector(resetAutoincrementSheetDidEnd:returnCode:contextInfo:) + didEndSelector:@selector(resetAutoincrementSheetDidEnd:returnCode:contextInfo:) contextInfo:nil]; - + [resetAutoIncrementValue setStringValue:@"1"]; } else if ([sender tag] == 2) { @@ -487,7 +486,7 @@ { // Order out current sheet to suppress overlapping of sheets [theSheet orderOut:nil]; - + if (returnCode == NSAlertDefaultReturn) { [self setAutoIncrementTo:[[resetAutoIncrementValue stringValue] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]]; } @@ -504,14 +503,14 @@ if (returnCode == NSAlertDefaultReturn) { [tableDocumentInstance startTaskWithDescription:NSLocalizedString(@"Removing field...", @"removing field task status message")]; - + NSNumber *removeKey = [NSNumber numberWithBool:[contextInfo hasSuffix:@"AndForeignKey"]]; - + if ([NSThread isMainThread]) { [NSThread detachNewThreadSelector:@selector(_removeFieldAndForeignKey:) toTarget:self withObject:removeKey]; - - [tableDocumentInstance enableTaskCancellationWithTitle:NSLocalizedString(@"Cancel", @"cancel button") callbackObject:self callbackFunction:NULL]; - } + + [tableDocumentInstance enableTaskCancellationWithTitle:NSLocalizedString(@"Cancel", @"cancel button") callbackObject:self callbackFunction:NULL]; + } else { [self _removeFieldAndForeignKey:removeKey]; } @@ -543,12 +542,12 @@ closes the keySheet #pragma mark Additional methods /** - * Sets the connection (received from SPDatabaseDocument) and makes things that have to be done only once + * Sets the connection (received from SPDatabaseDocument) and makes things that have to be done only once */ - (void)setConnection:(MCPConnection *)theConnection { mySQLConnection = theConnection; - + // Set the indexes controller connection [indexesController setConnection:mySQLConnection]; @@ -586,10 +585,10 @@ closes the keySheet [mySQLConnection queryString:[NSString stringWithFormat:@"ALTER TABLE %@ AUTO_INCREMENT = %@", [selTable backtickQuotedString], [autoIncValue stringValue]]]; if ([mySQLConnection queryErrored]) { - SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), + SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), - nil, nil, [NSApp mainWindow], nil, nil, nil, - [NSString stringWithFormat:NSLocalizedString(@"An error occurred while trying to reset AUTO_INCREMENT of table '%@'.\n\nMySQL said: %@", @"error resetting auto_increment informative message"), + nil, nil, [NSApp mainWindow], nil, nil, nil, + [NSString stringWithFormat:NSLocalizedString(@"An error occurred while trying to reset AUTO_INCREMENT of table '%@'.\n\nMySQL said: %@", @"error resetting auto_increment informative message"), selTable, [mySQLConnection getLastErrorMessage]]); } @@ -685,181 +684,196 @@ closes the keySheet if (!isEditingRow || currentlyEditingRow == -1) return YES; - + if (alertSheetOpened) return NO; theRow = [tableFields objectAtIndex:currentlyEditingRow]; - + if (isEditingNewRow) { // ADD syntax - if ([[theRow objectForKey:@"Length"] isEqualToString:@""] || ![theRow objectForKey:@"Length"]) { - + if ([[theRow objectForKey:@"length"] isEqualToString:@""] || ![theRow objectForKey:@"length"]) { + queryString = [NSMutableString stringWithFormat:@"ALTER TABLE %@ ADD %@ %@", - [selectedTable backtickQuotedString], - [[theRow objectForKey:@"Field"] backtickQuotedString], - [theRow objectForKey:@"Type"]]; - } + [selectedTable backtickQuotedString], + [[theRow objectForKey:@"name"] backtickQuotedString], + [[theRow objectForKey:@"type"] uppercaseString]]; + } else { queryString = [NSMutableString stringWithFormat:@"ALTER TABLE %@ ADD %@ %@(%@)", - [selectedTable backtickQuotedString], - [[theRow objectForKey:@"Field"] backtickQuotedString], - [theRow objectForKey:@"Type"], - [theRow objectForKey:@"Length"]]; + [selectedTable backtickQuotedString], + [[theRow objectForKey:@"name"] backtickQuotedString], + [[theRow objectForKey:@"type"] uppercaseString], + [theRow objectForKey:@"length"]]; } - } + } else { // CHANGE syntax - if (([[theRow objectForKey:@"Length"] isEqualToString:@""]) || - (![theRow objectForKey:@"Length"]) || - ([[theRow objectForKey:@"Type"] isEqualToString:@"datetime"])) + if (([[theRow objectForKey:@"length"] isEqualToString:@""]) || + (![theRow objectForKey:@"length"]) || + ([[[theRow objectForKey:@"type"] lowercaseString] isEqualToString:@"datetime"])) { - // If the old row and new row dictionaries are equal then the user didn't actually change anything so don't continue + // If the old row and new row dictionaries are equal then the user didn't actually change anything so don't continue if ([oldRow isEqualToDictionary:theRow]) { isEditingRow = NO; currentlyEditingRow = -1; return YES; } - + queryString = [NSMutableString stringWithFormat:@"ALTER TABLE %@ CHANGE %@ %@ %@", - [selectedTable backtickQuotedString], - [[oldRow objectForKey:@"Field"] backtickQuotedString], - [[theRow objectForKey:@"Field"] backtickQuotedString], - [theRow objectForKey:@"Type"]]; - } + [selectedTable backtickQuotedString], + [[oldRow objectForKey:@"name"] backtickQuotedString], + [[theRow objectForKey:@"name"] backtickQuotedString], + [[theRow objectForKey:@"type"] uppercaseString]]; + } else { - // If the old row and new row dictionaries are equal then the user didn't actually change anything so don't continue + // If the old row and new row dictionaries are equal then the user didn't actually change anything so don't continue if ([oldRow isEqualToDictionary:theRow]) { isEditingRow = NO; currentlyEditingRow = -1; return YES; } - + queryString = [NSMutableString stringWithFormat:@"ALTER TABLE %@ CHANGE %@ %@ %@(%@)", - [selectedTable backtickQuotedString], - [[oldRow objectForKey:@"Field"] backtickQuotedString], - [[theRow objectForKey:@"Field"] backtickQuotedString], - [theRow objectForKey:@"Type"], - [theRow objectForKey:@"Length"]]; + [selectedTable backtickQuotedString], + [[oldRow objectForKey:@"name"] backtickQuotedString], + [[theRow objectForKey:@"name"] backtickQuotedString], + [[theRow objectForKey:@"type"] uppercaseString], + [theRow objectForKey:@"length"]]; } } - + + NSString *fieldEncoding = @""; + if([[theRow objectForKey:@"encoding"] integerValue] > 0) { + NSString *enc = [[[[[tableSourceView tableColumns] objectAtIndex:10] dataCell] itemAtIndex:[[theRow objectForKey:@"encoding"] integerValue]] title]; + NSInteger start = [enc rangeOfString:@"("].location+1; + NSInteger end = [enc length] - start - 1; + fieldEncoding = [enc substringWithRange:NSMakeRange(start, end)]; + [queryString appendFormat:@" CHARACTER SET %@", fieldEncoding]; + } + if(![fieldEncoding length] && [tableDataInstance tableEncoding]) { + fieldEncoding = [tableDataInstance tableEncoding]; + } + if([fieldEncoding length] && [[theRow objectForKey:@"collation"] integerValue] > 0) { + NSArray *theCollations = [databaseDataInstance getDatabaseCollationsForEncoding:fieldEncoding]; + NSString *col = [[theCollations objectAtIndex:[[theRow objectForKey:@"collation"] integerValue]-1] objectForKey:@"COLLATION_NAME"]; + [queryString appendFormat:@" COLLATE %@", col]; + } + + // Field specification if ([[theRow objectForKey:@"unsigned"] integerValue] == 1) { [queryString appendString:@" UNSIGNED"]; } - + if ( [[theRow objectForKey:@"zerofill"] integerValue] == 1) { [queryString appendString:@" ZEROFILL"]; } - + if ( [[theRow objectForKey:@"binary"] integerValue] == 1) { [queryString appendString:@" BINARY"]; } - if ([[theRow objectForKey:@"Null"] integerValue] == 0) { + if ([[theRow objectForKey:@"null"] integerValue] == 0) { [queryString appendString:@" NOT NULL"]; } else { [queryString appendString:@" NULL"]; } - + // Don't provide any defaults for auto-increment fields if ([[theRow objectForKey:@"Extra"] isEqualToString:@"auto_increment"]) { [queryString appendString:@" "]; - } + } else { // If a NULL value has been specified, and NULL is allowed, specify DEFAULT NULL - if ([[theRow objectForKey:@"Default"] isEqualToString:[prefs objectForKey:SPNullValue]]) { - if ([[theRow objectForKey:@"Null"] integerValue] == 1) { + if ([[theRow objectForKey:@"default"] isEqualToString:[prefs objectForKey:SPNullValue]]) { + if ([[theRow objectForKey:@"null"] integerValue] == 1) { [queryString appendString:@" DEFAULT NULL "]; } - } + } // Otherwise, if CURRENT_TIMESTAMP was specified for timestamps, use that - else if ([[theRow objectForKey:@"Type"] isEqualToString:@"timestamp"] && - [[[theRow objectForKey:@"Default"] uppercaseString] isEqualToString:@"CURRENT_TIMESTAMP"]) + else if ([[theRow objectForKey:@"type"] isEqualToString:@"timestamp"] && + [[[theRow objectForKey:@"default"] uppercaseString] isEqualToString:@"CURRENT_TIMESTAMP"]) { [queryString appendString:@" DEFAULT CURRENT_TIMESTAMP "]; } // If the field is of type BIT, permit the use of single qoutes and also don't quote the default value. // For example, use DEFAULT b'1' as opposed to DEFAULT 'b\'1\'' which results in an error. - else if ([[theRow objectForKey:@"Type"] isEqualToString:@"bit"]) { - [queryString appendFormat:@" DEFAULT %@ ", [theRow objectForKey:@"Default"]]; + else if ([[[theRow objectForKey:@"type"] lowercaseString] isEqualToString:@"bit"]) { + [queryString appendFormat:@" DEFAULT %@ ", [theRow objectForKey:@"default"]]; } // Otherwise, use the provided default else { - [queryString appendFormat:@" DEFAULT '%@' ", [mySQLConnection prepareString:[theRow objectForKey:@"Default"]]]; + [queryString appendFormat:@" DEFAULT '%@' ", [mySQLConnection prepareString:[theRow objectForKey:@"default"]]]; } } - + if (!( - [[theRow objectForKey:@"Extra"] isEqualToString:@""] || + [[theRow objectForKey:@"Extra"] isEqualToString:@""] || [[theRow objectForKey:@"Extra"] isEqualToString:@"None"] - ) && - [theRow objectForKey:@"Extra"] ) + ) && + [theRow objectForKey:@"Extra"] ) { [queryString appendString:@" "]; [queryString appendString:[theRow objectForKey:@"Extra"]]; } - - if (!isEditingNewRow) { - // Add details not provided via the SHOW COLUMNS query from the table data cache so column details aren't lost - NSDictionary *originalColumnDetails = [[tableDataInstance columns] objectAtIndex:currentlyEditingRow]; + if (!isEditingNewRow) { // Any column comments - if ([originalColumnDetails objectForKey:@"comment"] && [(NSString *)[originalColumnDetails objectForKey:@"comment"] length]) { - [queryString appendFormat:@" COMMENT '%@'", [mySQLConnection prepareString:[originalColumnDetails objectForKey:@"comment"]]]; + if ([[theRow objectForKey:@"comment"] length]) { + [queryString appendFormat:@" COMMENT '%@'", [mySQLConnection prepareString:[theRow objectForKey:@"comment"]]]; } // Unparsed details - column formats, storage, reference definitions - if ([originalColumnDetails objectForKey:@"unparsed"]) { - [queryString appendString:[originalColumnDetails objectForKey:@"unparsed"]]; + if ([[theRow objectForKey:@"unparsed"] length]) { + [queryString appendString:[theRow objectForKey:@"unparsed"]]; } } - + // Asks the user to add an index to query if auto_increment is set and field isn't indexed - if ([[theRow objectForKey:@"Extra"] isEqualToString:@"auto_increment"] && - ([[theRow objectForKey:@"Key"] isEqualToString:@""] || - ![theRow objectForKey:@"Key"])) + if ([[theRow objectForKey:@"Extra"] isEqualToString:@"auto_increment"] && + ([[theRow objectForKey:@"Key"] isEqualToString:@""] || + ![theRow objectForKey:@"Key"])) { [chooseKeyButton selectItemAtIndex:0]; - - [NSApp beginSheet:keySheet - modalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self - didEndSelector:nil + + [NSApp beginSheet:keySheet + modalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self + didEndSelector:nil contextInfo:nil]; - + code = [NSApp runModalForWindow:keySheet]; - + [NSApp endSheet:keySheet]; [keySheet orderOut:nil]; - + if (code) { // User wants to add PRIMARY KEY - if ([chooseKeyButton indexOfSelectedItem] == 0 ) { + if ([chooseKeyButton indexOfSelectedItem] == 0 ) { [queryString appendString:@" PRIMARY KEY"]; - + // Add AFTER ... only if the user added a new field if (isEditingNewRow) { - [queryString appendFormat:@" AFTER %@", [[[tableFields objectAtIndex:(currentlyEditingRow -1)] objectForKey:@"Field"] backtickQuotedString]]; + [queryString appendFormat:@" AFTER %@", [[[tableFields objectAtIndex:(currentlyEditingRow -1)] objectForKey:@"name"] backtickQuotedString]]; } - } + } else { // Add AFTER ... only if the user added a new field if (isEditingNewRow) { - [queryString appendFormat:@" AFTER %@", [[[tableFields objectAtIndex:(currentlyEditingRow -1)] objectForKey:@"Field"] backtickQuotedString]]; - } - - [queryString appendFormat:@", ADD %@ (%@)", [chooseKeyButton titleOfSelectedItem], [[theRow objectForKey:@"Field"] backtickQuotedString]]; + [queryString appendFormat:@" AFTER %@", [[[tableFields objectAtIndex:(currentlyEditingRow -1)] objectForKey:@"name"] backtickQuotedString]]; + } + + [queryString appendFormat:@", ADD %@ (%@)", [chooseKeyButton titleOfSelectedItem], [[theRow objectForKey:@"name"] backtickQuotedString]]; } } - } + } // Add AFTER ... only if the user added a new field else if (isEditingNewRow) { - [queryString appendFormat:@" AFTER %@", [[[tableFields objectAtIndex:(currentlyEditingRow -1)] objectForKey:@"Field"] backtickQuotedString]]; + [queryString appendFormat:@" AFTER %@", [[[tableFields objectAtIndex:(currentlyEditingRow -1)] objectForKey:@"name"] backtickQuotedString]]; } - + // Execute query [mySQLConnection queryString:queryString]; @@ -867,7 +881,7 @@ closes the keySheet isEditingRow = NO; isEditingNewRow = NO; currentlyEditingRow = -1; - + [tableDataInstance resetAllData]; [tablesListInstance setStatusRequiresReload:YES]; [self loadTable:selectedTable]; @@ -879,14 +893,14 @@ closes the keySheet [NSThread detachNewThreadSelector:@selector(queryDbStructureWithUserInfo:) toTarget:mySQLConnection withObject:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], @"forceUpdate", selectedTable, @"affectedItem", [NSNumber numberWithInt:[tablesListInstance tableType]], @"affectedItemType", nil]]; return YES; - } + } else { alertSheetOpened = YES; if([mySQLConnection getLastErrorID] == 1146) { // If the current table doesn't exist anymore - SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), - NSLocalizedString(@"OK", @"OK button"), - nil, nil, [tableDocumentInstance parentWindow], self, nil, nil, - [NSString stringWithFormat:NSLocalizedString(@"An error occurred while trying to alter table '%@'.\n\nMySQL said: %@", @"error while trying to alter table message"), + SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), + NSLocalizedString(@"OK", @"OK button"), + nil, nil, [tableDocumentInstance parentWindow], self, nil, nil, + [NSString stringWithFormat:NSLocalizedString(@"An error occurred while trying to alter table '%@'.\n\nMySQL said: %@", @"error while trying to alter table message"), selectedTable, [mySQLConnection getLastErrorMessage]]); isEditingRow = NO; @@ -907,20 +921,20 @@ closes the keySheet } // Problem: alert sheet doesn't respond to first click if (isEditingNewRow) { - SPBeginAlertSheet(NSLocalizedString(@"Error adding field", @"error adding field message"), - NSLocalizedString(@"Edit row", @"Edit row button"), - NSLocalizedString(@"Discard changes", @"discard changes button"), nil, [tableDocumentInstance parentWindow], self, @selector(addRowErrorSheetDidEnd:returnCode:contextInfo:), nil, - [NSString stringWithFormat:NSLocalizedString(@"An error occurred when trying to add the field '%@'.\n\nMySQL said: %@", @"error adding field informative message"), - [theRow objectForKey:@"Field"], [mySQLConnection getLastErrorMessage]]); - } + SPBeginAlertSheet(NSLocalizedString(@"Error adding field", @"error adding field message"), + NSLocalizedString(@"Edit row", @"Edit row button"), + NSLocalizedString(@"Discard changes", @"discard changes button"), nil, [tableDocumentInstance parentWindow], self, @selector(addRowErrorSheetDidEnd:returnCode:contextInfo:), nil, + [NSString stringWithFormat:NSLocalizedString(@"An error occurred when trying to add the field '%@'.\n\nMySQL said: %@", @"error adding field informative message"), + [theRow objectForKey:@"name"], [mySQLConnection getLastErrorMessage]]); + } else { - SPBeginAlertSheet(NSLocalizedString(@"Error changing field", @"error changing field message"), - NSLocalizedString(@"Edit row", @"Edit row button"), - NSLocalizedString(@"Discard changes", @"discard changes button"), nil, [tableDocumentInstance parentWindow], self, @selector(addRowErrorSheetDidEnd:returnCode:contextInfo:), nil, - [NSString stringWithFormat:NSLocalizedString(@"An error occurred when trying to change the field '%@'.\n\nMySQL said: %@", @"error changing field informative message"), - [theRow objectForKey:@"Field"], [mySQLConnection getLastErrorMessage]]); + SPBeginAlertSheet(NSLocalizedString(@"Error changing field", @"error changing field message"), + NSLocalizedString(@"Edit row", @"Edit row button"), + NSLocalizedString(@"Discard changes", @"discard changes button"), nil, [tableDocumentInstance parentWindow], self, @selector(addRowErrorSheetDidEnd:returnCode:contextInfo:), nil, + [NSString stringWithFormat:NSLocalizedString(@"An error occurred when trying to change the field '%@'.\n\nMySQL said: %@", @"error changing field informative message"), + [theRow objectForKey:@"name"], [mySQLConnection getLastErrorMessage]]); } - + return NO; } } @@ -950,7 +964,7 @@ closes the keySheet [tableFields replaceObjectAtIndex:currentlyEditingRow withObject:[NSMutableDictionary dictionaryWithDictionary:oldRow]]; isEditingRow = NO; - } + } else { [tableFields removeObjectAtIndex:currentlyEditingRow]; isEditingRow = NO; @@ -965,7 +979,7 @@ closes the keySheet /** * A method to show an error sheet after a short delay, so that it can - * be called from within an endSheet selector. This should be called on + * be called from within an endSheet selector. This should be called on * the main thread. */ -(void)showErrorSheetWith:(NSDictionary *)errorDictionary @@ -979,9 +993,9 @@ closes the keySheet [self performSelector:@selector(showErrorSheetWith:) withObject:delayedErrorDictionary afterDelay:0.3]; return; } - + // Display the error sheet - SPBeginAlertSheet([errorDictionary objectForKey:@"title"], NSLocalizedString(@"OK", @"OK button"), + SPBeginAlertSheet([errorDictionary objectForKey:@"title"], NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil, [errorDictionary objectForKey:@"message"]); } @@ -990,21 +1004,21 @@ closes the keySheet * This method is called as part of Key Value Observing which is used to watch for preference changes which effect the interface. */ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context -{ +{ // Display table veiew vertical gridlines preference changed if ([keyPath isEqualToString:SPDisplayTableViewVerticalGridlines]) { [tableSourceView setGridStyleMask:([[change objectForKey:NSKeyValueChangeNewKey] boolValue]) ? NSTableViewSolidVerticalGridLineMask : NSTableViewGridNone]; } // Use monospaced fonts preference changed else if ([keyPath isEqualToString:SPUseMonospacedFonts]) { - + BOOL useMonospacedFont = [[change objectForKey:NSKeyValueChangeNewKey] boolValue]; - + for (NSTableColumn *fieldColumn in [tableSourceView tableColumns]) { [[fieldColumn dataCell] setFont:(useMonospacedFont) ? [NSFont fontWithName:SPDefaultMonospacedFontName size:[NSFont smallSystemFontSize]] : [NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; } - + [tableSourceView reloadData]; } } @@ -1018,17 +1032,17 @@ closes the keySheet if ([menuItem action] == @selector(removeField:)) { return (([tableSourceView numberOfSelectedRows] == 1) && ([tableSourceView numberOfRows] > 1)); } - + // Duplicate field if ([menuItem action] == @selector(copyField:)) { return ([tableSourceView numberOfSelectedRows] == 1); } - + // Reset AUTO_INCREMENT if ([menuItem action] == @selector(resetAutoIncrement:)) { return [indexesController validateMenuItem:menuItem]; } - + return YES; } @@ -1059,7 +1073,7 @@ get the default value for a specified field - (NSString *)defaultValueForField:(NSString *)field { if ( ![defaultValues objectForKey:field] ) { - return [prefs objectForKey:SPNullValue]; + return [prefs objectForKey:SPNullValue]; } else if ( [[defaultValues objectForKey:field] isMemberOfClass:[NSNull class]] ) { return [prefs objectForKey:SPNullValue]; } else { @@ -1075,18 +1089,18 @@ returns an array containing the field names of the selected table NSMutableArray *tempArray = [NSMutableArray array]; NSEnumerator *enumerator; id field; - + //load table if not already done if ( ![tablesListInstance structureLoaded] ) { [self loadTable:[tablesListInstance tableName]]; } - + //get field names enumerator = [tableFields objectEnumerator]; while ( (field = [enumerator nextObject]) ) { - [tempArray addObject:[field objectForKey:@"Field"]]; + [tempArray addObject:[field objectForKey:@"name"]]; } - + return [NSArray arrayWithArray:tempArray]; } @@ -1100,42 +1114,42 @@ returns a dictionary containing enum/set field names as key and possible values /** * Returns a dictionary describing the source of the table to be used for printing purposes. The object accessible - * via the key 'structure' is an array of the tables fields, where the first element is always the field names + * via the key 'structure' is an array of the tables fields, where the first element is always the field names * and each subsequent element is the field data. This is also true for the table's indexes, which are accessible * via the key 'indexes'. */ - (NSDictionary *)tableSourceForPrinting -{ +{ NSInteger i, j; NSMutableArray *tempResult = [NSMutableArray array]; NSMutableArray *tempResult2 = [NSMutableArray array]; - + NSString *nullValue = [prefs stringForKey:SPNullValue]; CFStringRef escapedNullValue = CFXMLCreateStringByEscapingEntities(NULL, ((CFStringRef)nullValue), NULL); - + MCPResult *structureQueryResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW COLUMNS FROM %@", [selectedTable backtickQuotedString]]]; MCPResult *indexesQueryResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW INDEXES FROM %@", [selectedTable backtickQuotedString]]]; - + [structureQueryResult setReturnDataAsStrings:YES]; [indexesQueryResult setReturnDataAsStrings:YES]; - + if ([structureQueryResult numOfRows]) [structureQueryResult dataSeek:0]; if ([indexesQueryResult numOfRows]) [indexesQueryResult dataSeek:0]; - + [tempResult addObject:[structureQueryResult fetchFieldNames]]; - + NSMutableArray *temp = [[indexesQueryResult fetchFieldNames] mutableCopy]; - + // Remove the 'table' column [temp removeObjectAtIndex:0]; - + [tempResult2 addObject:temp]; - + [temp release]; - + for (i = 0; i < [structureQueryResult numOfRows]; i++) { NSMutableArray *row = [[structureQueryResult fetchRowAsArray] mutableCopy]; - + // For every NULL value replace it with the user's NULL value placeholder so we can actually print it for (j = 0; j < [row count]; j++) { @@ -1143,18 +1157,18 @@ returns a dictionary containing enum/set field names as key and possible values [row replaceObjectAtIndex:j withObject:(NSString *)escapedNullValue]; } } - + [tempResult addObject:row]; - + [row release]; } for (i = 0; i < [indexesQueryResult numOfRows]; i++) { NSMutableArray *index = [[indexesQueryResult fetchRowAsArray] mutableCopy]; - + // Remove the 'table' column values [index removeObjectAtIndex:0]; - + // For every NULL value replace it with the user's NULL value placeholder so we can actually print it for (j = 0; j < [index count]; j++) { @@ -1162,9 +1176,9 @@ returns a dictionary containing enum/set field names as key and possible values [index replaceObjectAtIndex:j withObject:(NSString *)escapedNullValue]; } } - + [tempResult2 addObject:index]; - + [index release]; } @@ -1189,7 +1203,7 @@ returns a dictionary containing enum/set field names as key and possible values [copyFieldButton setEnabled:NO]; [reloadFieldsButton setEnabled:NO]; [editTableButton setEnabled:NO]; - + [indexesTableView setEnabled:NO]; [addIndexButton setEnabled:NO]; [removeIndexButton setEnabled:NO]; @@ -1205,22 +1219,22 @@ returns a dictionary containing enum/set field names as key and possible values if (![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:SPMainToolbarTableStructure]) return; BOOL editingEnabled = ([tablesListInstance tableType] == SPTableTypeTable); - + [tableSourceView setEnabled:YES]; [tableSourceView displayIfNeeded]; [addFieldButton setEnabled:editingEnabled]; - + if (editingEnabled && [tableSourceView numberOfSelectedRows] > 0) { [removeFieldButton setEnabled:YES]; [copyFieldButton setEnabled:YES]; } - + [reloadFieldsButton setEnabled:YES]; [editTableButton setEnabled:YES]; - + [indexesTableView setEnabled:YES]; [indexesTableView displayIfNeeded]; - + [addIndexButton setEnabled:editingEnabled]; [removeIndexButton setEnabled:(editingEnabled && ([indexesTableView numberOfSelectedRows] > 0))]; [refreshIndexesButton setEnabled:YES]; @@ -1235,10 +1249,34 @@ returns a dictionary containing enum/set field names as key and possible values } - (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex -{ +{ // Return a placeholder if the table is reloading if (rowIndex >= [tableFields count]) return @"..."; + if([[tableColumn identifier] isEqualToString:@"collation"]) { + if([[[tableFields objectAtIndex:rowIndex] objectForKey:@"encoding"] integerValue] > 0) { + NSString *enc = [[[[[tableSourceView tableColumns] objectAtIndex:10] dataCell] itemAtIndex:[[[tableFields objectAtIndex:rowIndex] objectForKey:@"encoding"] integerValue]] title]; + NSInteger start = [enc rangeOfString:@"("].location+1; + NSInteger end = [enc length] - start - 1; + collations = [databaseDataInstance getDatabaseCollationsForEncoding:[enc substringWithRange:NSMakeRange(start, end)]]; + } else { + if([tableDataInstance tableEncoding]) { + collations = [databaseDataInstance getDatabaseCollationsForEncoding:[tableDataInstance tableEncoding]]; + } else { + collations = [NSArray array]; + } + } + + [[tableColumn dataCell] removeAllItems]; + + if ([collations count] > 0) { + [[tableColumn dataCell] addItemWithTitle:@""]; + // Populate collation popup button + for (NSDictionary *collation in collations) + [[tableColumn dataCell] addItemWithTitle:[collation objectForKey:@"COLLATION_NAME"]]; + } + } + return [[tableFields objectAtIndex:rowIndex] objectForKey:[tableColumn identifier]]; } @@ -1252,7 +1290,7 @@ returns a dictionary containing enum/set field names as key and possible values isEditingRow = YES; currentlyEditingRow = rowIndex; } - + [[tableFields objectAtIndex:rowIndex] setObject:(anObject) ? anObject : @"" forKey:[aTableColumn identifier]]; } @@ -1305,11 +1343,11 @@ would result in a position change. // Ensure the drop is of the correct type if (operation == NSTableViewDropAbove && row != -1 && [pboardTypes containsObject:@"SequelProPasteboard"]) { - + // Ensure the drag originated within this table if ([info draggingSource] == tableView) { originalRow = [[[info draggingPasteboard] stringForType:@"SequelProPasteboard"] integerValue]; - + if (row != originalRow && row != (originalRow+1)) { return NSDragOperationMove; } @@ -1339,58 +1377,55 @@ would result in a position change. // Begin construction of the reordering query queryString = [NSMutableString stringWithFormat:@"ALTER TABLE %@ MODIFY COLUMN %@ %@", [selectedTable backtickQuotedString], - [[originalRow objectForKey:@"Field"] backtickQuotedString], - [originalRow objectForKey:@"Type"]]; + [[originalRow objectForKey:@"name"] backtickQuotedString], + [[originalRow objectForKey:@"type"] uppercaseString]]; // Add the length parameter if necessary - if ( [originalRow objectForKey:@"Length"] && ![[originalRow objectForKey:@"Length"] isEqualToString:@""]) { - [queryString appendFormat:@"(%@)", [originalRow objectForKey:@"Length"]]; + if ( [originalRow objectForKey:@"length"] && ![[originalRow objectForKey:@"length"] isEqualToString:@""]) { + [queryString appendFormat:@"(%@)", [originalRow objectForKey:@"length"]]; } // Add unsigned, zerofill, binary, not null if necessary - if ([[originalRow objectForKey:@"unsigned"] isEqualToString:@"1"]) { + if ([[originalRow objectForKey:@"unsigned"] integerValue]) { [queryString appendString:@" UNSIGNED"]; } - if ([[originalRow objectForKey:@"zerofill"] isEqualToString:@"1"]) { + if ([[originalRow objectForKey:@"zerofill"] integerValue]) { [queryString appendString:@" ZEROFILL"]; } - if ([[originalRow objectForKey:@"binary"] isEqualToString:@"1"]) { + if ([[originalRow objectForKey:@"binary"] integerValue]) { [queryString appendString:@" BINARY"]; } - if ([[originalRow objectForKey:@"Null"] isEqualToString:@"0"] ) { + if (![[originalRow objectForKey:@"null"] integerValue]) { [queryString appendString:@" NOT NULL"]; } if (![[originalRow objectForKey:@"Extra"] isEqualToString:@"None"] ) { [queryString appendString:@" "]; [queryString appendString:[[originalRow objectForKey:@"Extra"] uppercaseString]]; } - - BOOL isTimestampType = [[originalRow objectForKey:@"Type"] isEqualToString:@"timestamp"]; + + BOOL isTimestampType = [[[originalRow objectForKey:@"type"] lowercaseString] isEqualToString:@"timestamp"]; // Add the default value - if ([[originalRow objectForKey:@"Default"] isEqualToString:[prefs objectForKey:SPNullValue]]) { - if ([[originalRow objectForKey:@"Null"] integerValue] == 1) { + if ([[originalRow objectForKey:@"default"] isEqualToString:[prefs objectForKey:SPNullValue]]) { + if ([[originalRow objectForKey:@"null"] integerValue] == 1) { [queryString appendString:(isTimestampType) ? @" NULL DEFAULT NULL" : @" DEFAULT NULL"]; } - } - else if (isTimestampType && ([[[originalRow objectForKey:@"Default"] uppercaseString] isEqualToString:@"CURRENT_TIMESTAMP"]) ) { + } + else if (isTimestampType && ([[[originalRow objectForKey:@"default"] uppercaseString] isEqualToString:@"CURRENT_TIMESTAMP"]) ) { [queryString appendString:@" DEFAULT CURRENT_TIMESTAMP"]; - } + } else { - [queryString appendFormat:@" DEFAULT '%@'", [mySQLConnection prepareString:[originalRow objectForKey:@"Default"]]]; + [queryString appendFormat:@" DEFAULT '%@'", [mySQLConnection prepareString:[originalRow objectForKey:@"default"]]]; } - // Add details not provided via the SHOW COLUMNS query from the table data cache so column details aren't lost - NSDictionary *originalColumnDetails = [[tableDataInstance columns] objectAtIndex:originalRowIndex]; - // Any column comments - if ([originalColumnDetails objectForKey:@"comment"] && [(NSString *)[originalColumnDetails objectForKey:@"comment"] length]) { - [queryString appendFormat:@" COMMENT '%@'", [mySQLConnection prepareString:[originalColumnDetails objectForKey:@"comment"]]]; + if ([[originalRow objectForKey:@"comment"] length]) { + [queryString appendFormat:@" COMMENT '%@'", [mySQLConnection prepareString:[originalRow objectForKey:@"comment"]]]; } // Unparsed details - column formats, storage, reference definitions - if ([originalColumnDetails objectForKey:@"unparsed"]) { - [queryString appendString:[originalColumnDetails objectForKey:@"unparsed"]]; + if ([originalRow objectForKey:@"unparsed"]) { + [queryString appendString:[originalRow objectForKey:@"unparsed"]]; } // Add the new location @@ -1398,12 +1433,12 @@ would result in a position change. [queryString appendString:@" FIRST"]; } else { [queryString appendFormat:@" AFTER %@", - [[[tableFields objectAtIndex:destinationRowIndex-1] objectForKey:@"Field"] backtickQuotedString]]; + [[[tableFields objectAtIndex:destinationRowIndex-1] objectForKey:@"name"] backtickQuotedString]]; } // Run the query; report any errors, or reload the table on success [mySQLConnection queryString:queryString]; - + if ([mySQLConnection queryErrored]) { SPBeginAlertSheet(NSLocalizedString(@"Error moving field", @"error moving field message"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil, [NSString stringWithFormat:NSLocalizedString(@"An error occurred while trying to move the field.\n\nMySQL said: %@", @"error moving field informative message"), [mySQLConnection getLastErrorMessage]]); @@ -1423,7 +1458,7 @@ would result in a position change. } [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance]; - + [originalRow release]; return YES; } @@ -1437,13 +1472,13 @@ would result in a position change. - (void)tableViewSelectionDidChange:(NSNotification *)aNotification { id object = [aNotification object]; - + // Check for which table view the selection changed if (object == tableSourceView) { - + // If we are editing a row, attempt to save that row - if saving failed, reselect the edit row. if (isEditingRow && [tableSourceView selectedRow] != currentlyEditingRow && ![self saveRowOnDeselect]) return; - + [copyFieldButton setEnabled:YES]; // Check if there is currently a field selected and change button state accordingly @@ -1453,7 +1488,7 @@ would result in a position change. [removeFieldButton setEnabled:NO]; [copyFieldButton setEnabled:NO]; } - + // If the table only has one field, disable the remove button. This removes the need to check that the user // is attempting to remove the last field in a table in removeField: above, but leave it in just in case. if ([tableSourceView numberOfRows] == 1) { @@ -1495,7 +1530,7 @@ would result in a position change. } } return TRUE; - + // Trap the enter key, triggering a save } else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertNewline:)] ) @@ -1503,7 +1538,7 @@ would result in a position change. [[control window] makeFirstResponder:control]; [self addRowToDB]; return TRUE; - + // Trap escape, aborting the edit and reverting the row } else if ( [[control window] methodForSelector:command] == [[control window] methodForSelector:@selector(_cancelKey:)] || @@ -1532,7 +1567,7 @@ would result in a position change. * is uneditable. */ - (void)tableView:(NSTableView *)tableView willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { - + //make sure that the message is from the right table view if (tableView!=tableSourceView) return; @@ -1558,7 +1593,7 @@ would result in a position change. } - (NSRect)splitView:(NSSplitView *)splitView additionalEffectiveRectOfDividerAtIndex:(NSInteger)dividerIndex -{ +{ return [structureGrabber convertRect:[structureGrabber bounds] toView:splitView]; } @@ -1569,7 +1604,7 @@ would result in a position change. if ([tablesIndexesSplitView isSubviewCollapsed:indexesView]) { [indexesShowButton setHidden:NO]; } else { - [indexesShowButton setHidden:YES]; + [indexesShowButton setHidden:YES]; } } } @@ -1583,18 +1618,18 @@ would result in a position change. #pragma mark Private API methods /** - * Removes a field from the current table and the dependent foreign key if specified. + * Removes a field from the current table and the dependent foreign key if specified. */ - (void)_removeFieldAndForeignKey:(NSNumber *)removeForeignKey -{ +{ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - + // Remove the foreign key before the field if required if ([removeForeignKey boolValue]) { - + NSString *relationName = @""; - NSString *field = [[tableFields objectAtIndex:[tableSourceView selectedRow]] objectForKey:@"Field"]; - + NSString *field = [[tableFields objectAtIndex:[tableSourceView selectedRow]] objectForKey:@"name"]; + // Get the foreign key name for (NSDictionary *constraint in [tableDataInstance getConstraints]) { @@ -1606,42 +1641,42 @@ would result in a position change. } } } - + [mySQLConnection queryString:[NSString stringWithFormat:@"ALTER TABLE %@ DROP FOREIGN KEY %@", [selectedTable backtickQuotedString], [relationName backtickQuotedString]]]; - + // Check for errors, but only if the query wasn't cancelled if ([mySQLConnection queryErrored] && ![mySQLConnection queryCancelled]) { NSMutableDictionary *errorDictionary = [NSMutableDictionary dictionary]; [errorDictionary setObject:NSLocalizedString(@"Unable to delete relation", @"error deleting relation message") forKey:@"title"]; [errorDictionary setObject:[NSString stringWithFormat:NSLocalizedString(@"An error occurred while trying to delete the relation '%@'.\n\nMySQL said: %@", @"error deleting relation informative message"), relationName, [mySQLConnection getLastErrorMessage]] forKey:@"message"]; [[self onMainThread] showErrorSheetWith:errorDictionary]; - } + } } - + // Remove field [mySQLConnection queryString:[NSString stringWithFormat:@"ALTER TABLE %@ DROP %@", - [selectedTable backtickQuotedString], [[[tableFields objectAtIndex:[tableSourceView selectedRow]] objectForKey:@"Field"] backtickQuotedString]]]; - + [selectedTable backtickQuotedString], [[[tableFields objectAtIndex:[tableSourceView selectedRow]] objectForKey:@"name"] backtickQuotedString]]]; + // Check for errors, but only if the query wasn't cancelled if ([mySQLConnection queryErrored] && ![mySQLConnection queryCancelled]) { NSMutableDictionary *errorDictionary = [NSMutableDictionary dictionary]; [errorDictionary setObject:NSLocalizedString(@"Error", @"error") forKey:@"title"]; [errorDictionary setObject:[NSString stringWithFormat:NSLocalizedString(@"Couldn't delete field %@.\nMySQL said: %@", @"message of panel when field cannot be deleted"), - [[tableFields objectAtIndex:[tableSourceView selectedRow]] objectForKey:@"Field"], + [[tableFields objectAtIndex:[tableSourceView selectedRow]] objectForKey:@"name"], [mySQLConnection getLastErrorMessage]] forKey:@"message"]; [[self onMainThread] showErrorSheetWith:errorDictionary]; - } + } else { [tableDataInstance resetAllData]; [tablesListInstance setStatusRequiresReload:YES]; [self loadTable:selectedTable]; - + // Mark the content table cache for refresh [tablesListInstance setContentRequiresReload:YES]; } - + [tableDocumentInstance endTask]; - + [pool drain]; } @@ -1651,16 +1686,16 @@ would result in a position change. * Dealloc. */ - (void)dealloc -{ +{ [[NSNotificationCenter defaultCenter] removeObserver:self]; - + [tableFields release]; [oldRow release]; [enumFields release]; - + if (defaultValues) [defaultValues release]; if (selectedTable) [selectedTable release]; - + [super dealloc]; } |