diff options
-rw-r--r-- | Source/SPExtendedTableInfo.m | 180 | ||||
-rw-r--r-- | Source/SPTableData.m | 114 | ||||
-rw-r--r-- | Source/SPTableInfo.m | 73 |
3 files changed, 212 insertions, 155 deletions
diff --git a/Source/SPExtendedTableInfo.m b/Source/SPExtendedTableInfo.m index f9e0bdb8..186c4c25 100644 --- a/Source/SPExtendedTableInfo.m +++ b/Source/SPExtendedTableInfo.m @@ -50,11 +50,11 @@ - (void)awakeFromNib { [tableCreateSyntaxTextView setAllowsDocumentBackgroundColorChange:YES]; - + NSMutableDictionary *bindingOptions = [NSMutableDictionary dictionary]; - + [bindingOptions setObject:NSUnarchiveFromDataTransformerName forKey:@"NSValueTransformerName"]; - + [tableCreateSyntaxTextView bind:@"backgroundColor" toObject:[NSUserDefaultsController sharedUserDefaultsController] withKeyPath:@"values.CustomQueryEditorBackgroundColor" @@ -81,7 +81,7 @@ { // Reset the table data's cache [tableDataInstance resetAllData]; - + // Load the new table info [self loadTable:selectedTable]; } @@ -98,18 +98,18 @@ if ([currentType isEqualToString:newType]) { return; } - + // Alter table's storage type [connection queryString:[NSString stringWithFormat:@"ALTER TABLE %@ TYPE = %@", [selectedTable backtickQuotedString], newType]]; - + if ([connection getLastErrorID] == 0) { // Reload the table's data [tablesListInstance updateSelectionWithTaskString:NSLocalizedString(@"Reloading data...", @"Reloading data task description")]; } else { [sender selectItemWithTitle:currentType]; - - SPBeginAlertSheet(NSLocalizedString(@"Error changing table type", @"error changing table type message"), + + SPBeginAlertSheet(NSLocalizedString(@"Error changing table type", @"error changing table type message"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [NSApp mainWindow], self, nil, nil, [NSString stringWithFormat:NSLocalizedString(@"An error occurred when trying to change the table type to '%@'.\n\nMySQL said: %@", @"error changing table type informative message"), newType, [connection getLastErrorMessage]]); } @@ -122,21 +122,21 @@ { NSString *currentEncoding = [tableDataInstance tableEncoding]; NSString *newEncoding = [[sender titleOfSelectedItem] stringByMatching:@"^.+\\((.+)\\)$" capture:1L]; - + // Check if the user selected the same encoding if ([currentEncoding isEqualToString:newEncoding]) return; - + // Alter table's character set encoding [connection queryString:[NSString stringWithFormat:@"ALTER TABLE %@ CHARACTER SET = %@", [selectedTable backtickQuotedString], newEncoding]]; - + if ([connection getLastErrorID] == 0) { // Reload the table's data [self reloadTable:self]; } else { [sender selectItemWithTitle:currentEncoding]; - - SPBeginAlertSheet(NSLocalizedString(@"Error changing table encoding", @"error changing table encoding message"), + + SPBeginAlertSheet(NSLocalizedString(@"Error changing table encoding", @"error changing table encoding message"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [NSApp mainWindow], self, nil, nil, [NSString stringWithFormat:NSLocalizedString(@"An error occurred when trying to change the table encoding to '%@'.\n\nMySQL said: %@", @"error changing table encoding informative message"), newEncoding, [connection getLastErrorMessage]]); } @@ -149,21 +149,21 @@ { NSString *newCollation = [sender titleOfSelectedItem]; NSString *currentCollation = [tableDataInstance statusValueForKey:@"Collation"]; - + // Check if the user selected the same collation if ([currentCollation isEqualToString:newCollation]) return; - + // Alter table's character set collation [connection queryString:[NSString stringWithFormat:@"ALTER TABLE %@ COLLATE = %@", [selectedTable backtickQuotedString], newCollation]]; - + if ([connection getLastErrorID] == 0) { // Reload the table's data [self reloadTable:self]; } else { [sender selectItemWithTitle:currentCollation]; - - SPBeginAlertSheet(NSLocalizedString(@"Error changing table collation", @"error changing table collation message"), + + SPBeginAlertSheet(NSLocalizedString(@"Error changing table collation", @"error changing table collation message"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [NSApp mainWindow], self, nil, nil, [NSString stringWithFormat:NSLocalizedString(@"An error occurred when trying to change the table collation to '%@'.\n\nMySQL said: %@", @"error changing table collation informative message"), newCollation, [connection getLastErrorMessage]]); } @@ -174,7 +174,7 @@ if ([sender tag] == 1) { [tableRowAutoIncrement setEditable:YES]; [tableRowAutoIncrement selectText:nil]; - } + } else { [tableRowAutoIncrement setEditable:NO]; [tableSourceInstance resetAutoIncrement:sender]; @@ -187,58 +187,58 @@ [tableSourceInstance setAutoIncrementTo:[[tableRowAutoIncrement stringValue] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]]; } -- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command +- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command { // Listen to ESC to abort editing of auto increment input field if (command == @selector(cancelOperation:) && control == tableRowAutoIncrement) { [tableRowAutoIncrement abortEditing]; return YES; } - + return NO; } #pragma mark - #pragma mark Other - + /** - * Load all the info for the supplied table by querying the table data instance and updaing the interface + * Load all the info for the supplied table by querying the table data instance and updaing the interface * elements accordingly. * Note that interface elements are also toggled in start/endDocumentTaskForTab:, with similar logic. * Due to the large quantity of interface interaction in this function it is not thread-safe. */ - (void)loadTable:(NSString *)table -{ +{ BOOL enableInteraction = ![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:SPMainToolbarTableInfo] || ![tableDocumentInstance isWorking]; [resetAutoIncrementResetButton setHidden:YES]; // Store the table name away for future use selectedTable = table; - + // Retrieve the table status information via the table data cache NSDictionary *statusFields = [tableDataInstance statusValues]; - + [tableTypePopUpButton removeAllItems]; [tableEncodingPopUpButton removeAllItems]; [tableCollationPopUpButton removeAllItems]; - + // No table selected or view selected if ((!table) || [table isEqualToString:@""] || [[statusFields objectForKey:@"Engine"] isEqualToString:@"View"]) { - + [tableTypePopUpButton setEnabled:NO]; [tableEncodingPopUpButton setEnabled:NO]; [tableCollationPopUpButton setEnabled:NO]; - + if ([[statusFields objectForKey:@"Engine"] isEqualToString:@"View"]) { [tableTypePopUpButton addItemWithTitle:@"View"]; // Set create syntax [tableCreateSyntaxTextView setEditable:YES]; [tableCreateSyntaxTextView shouldChangeTextInRange:NSMakeRange(0, [[tableCreateSyntaxTextView string] length]) replacementString:@""]; [tableCreateSyntaxTextView setString:@""]; - + NSString *createViewSyntax = [[[tableDataInstance tableCreateSyntax] createViewSyntaxPrettifier] stringByAppendingString:@";"]; - + if (createViewSyntax) { [tableCreateSyntaxTextView shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:createViewSyntax]; [tableCreateSyntaxTextView insertText:createViewSyntax]; @@ -252,101 +252,105 @@ [tableCreateSyntaxTextView didChangeText]; [tableCreateSyntaxTextView setEditable:NO]; } - + [tableCreatedAt setStringValue:@""]; [tableUpdatedAt setStringValue:@""]; - + // Set row values [tableRowNumber setStringValue:@""]; [tableRowFormat setStringValue:@""]; [tableRowAvgLength setStringValue:@""]; [tableRowAutoIncrement setStringValue:@""]; - + // Set size values [tableDataSize setStringValue:@""]; [tableMaxDataSize setStringValue:@""]; [tableIndexSize setStringValue:@""]; [tableSizeFree setStringValue:@""]; - - // Set comments + + // Set comments [tableCommentsTextView setEditable:NO]; [tableCommentsTextView shouldChangeTextInRange:NSMakeRange(0, [[tableCommentsTextView string] length]) replacementString:@""]; [tableCommentsTextView setString:@""]; [tableCommentsTextView didChangeText]; - + + if([[statusFields objectForKey:@"Engine"] isEqualToString:@"View"] && [statusFields objectForKey:@"CharacterSetClient"] && [statusFields objectForKey:@"Collation"]) { + [tableEncodingPopUpButton addItemWithTitle:[statusFields objectForKey:@"CharacterSetClient"]]; + [tableCollationPopUpButton addItemWithTitle:[statusFields objectForKey:@"Collation"]]; + } return; } - + NSArray *engines = [databaseDataInstance getDatabaseStorageEngines]; NSArray *encodings = [databaseDataInstance getDatabaseCharacterSetEncodings]; NSArray *collations = [databaseDataInstance getDatabaseCollationsForEncoding:[tableDataInstance tableEncoding]]; - + if (([engines count] > 0) && ([statusFields objectForKey:@"Engine"])) { - + // Populate type popup button for (NSDictionary *engine in engines) - { + { [tableTypePopUpButton addItemWithTitle:[engine objectForKey:@"Engine"]]; - } - + } + [tableTypePopUpButton selectItemWithTitle:[statusFields objectForKey:@"Engine"]]; [tableTypePopUpButton setEnabled:enableInteraction]; } else { [tableTypePopUpButton addItemWithTitle:NSLocalizedString(@"Not available", @"not available label")]; } - + if (([encodings count] > 0) && ([tableDataInstance tableEncoding])) { NSString *selectedTitle = @""; - + // 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"]]; - + [tableEncodingPopUpButton addItemWithTitle:menuItemTitle]; - + if ([[tableDataInstance tableEncoding] isEqualToString:[encoding objectForKey:@"CHARACTER_SET_NAME"]]) { selectedTitle = menuItemTitle; } - } - + } + [tableEncodingPopUpButton selectItemWithTitle:selectedTitle]; [tableEncodingPopUpButton setEnabled:enableInteraction]; } else { [tableEncodingPopUpButton addItemWithTitle:NSLocalizedString(@"Not available", @"not available label")]; } - + if (([collations count] > 0) && ([statusFields objectForKey:@"Collation"])) { // Populate collation popup button for (NSDictionary *collation in collations) - { + { [tableCollationPopUpButton addItemWithTitle:[collation objectForKey:@"COLLATION_NAME"]]; - } - + } + [tableCollationPopUpButton selectItemWithTitle:[statusFields objectForKey:@"Collation"]]; [tableCollationPopUpButton setEnabled:enableInteraction]; } else { [tableCollationPopUpButton addItemWithTitle:NSLocalizedString(@"Not available", @"not available label")]; } - + [tableCreatedAt setStringValue:[self _formatValueWithKey:@"Create_time" inDictionary:statusFields]]; [tableUpdatedAt setStringValue:[self _formatValueWithKey:@"Update_time" inDictionary:statusFields]]; - + // Set row values [tableRowNumber setStringValue:[self _formatValueWithKey:@"Rows" inDictionary:statusFields]]; [tableRowFormat setStringValue:[self _formatValueWithKey:@"Row_format" inDictionary:statusFields]]; [tableRowAvgLength setStringValue:[self _formatValueWithKey:@"Avg_row_length" inDictionary:statusFields]]; [tableRowAutoIncrement setStringValue:[self _formatValueWithKey:@"Auto_increment" inDictionary:statusFields]]; - + // Set size values [tableDataSize setStringValue:[self _formatValueWithKey:@"Data_length" inDictionary:statusFields]]; [tableMaxDataSize setStringValue:[self _formatValueWithKey:@"Max_data_length" inDictionary:statusFields]]; [tableIndexSize setStringValue:[self _formatValueWithKey:@"Index_length" inDictionary:statusFields]]; [tableSizeFree setStringValue:[self _formatValueWithKey:@"Data_free" inDictionary:statusFields]]; - + // Set comments NSString *commentText = [statusFields objectForKey:@"Comment"]; if (!commentText) commentText = @""; @@ -355,7 +359,7 @@ [tableCommentsTextView setString:commentText]; [tableCommentsTextView didChangeText]; [tableCommentsTextView setEditable:enableInteraction]; - + // Set create syntax [tableCreateSyntaxTextView setEditable:YES]; [tableCreateSyntaxTextView shouldChangeTextInRange:NSMakeRange(0, [[tableCommentsTextView string] length]) replacementString:@""]; @@ -367,7 +371,7 @@ } [tableCreateSyntaxTextView didChangeText]; [tableCreateSyntaxTextView setEditable:NO]; - + // Validate Reset AUTO_INCREMENT button if ([statusFields objectForKey:@"Auto_increment"] && ![[statusFields objectForKey:@"Auto_increment"] isKindOfClass:[NSNull class]]) { [resetAutoIncrementResetButton setHidden:NO]; @@ -418,8 +422,8 @@ NSError *error = nil; NSArray *HTMLExcludes = [NSArray arrayWithObjects:@"doctype", @"html", @"head", @"body", @"xml", nil]; - - NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:NSHTMLTextDocumentType, + + NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:NSHTMLTextDocumentType, NSDocumentTypeDocumentAttribute, HTMLExcludes, NSExcludedElementsDocumentAttribute, nil]; // Set tableCreateSyntaxTextView's font size temporarily to 10pt for printing @@ -429,13 +433,13 @@ [tableCreateSyntaxTextView setFont:[NSFont fontWithName:[oldFont fontName] size:10.0]]; // Convert tableCreateSyntaxTextView to HTML - NSData *HTMLData = [[tableCreateSyntaxTextView textStorage] dataFromRange:NSMakeRange(0, [[tableCreateSyntaxTextView string] length]) + NSData *HTMLData = [[tableCreateSyntaxTextView textStorage] dataFromRange:NSMakeRange(0, [[tableCreateSyntaxTextView string] length]) documentAttributes:attributes error:&error]; // Restore original font settings [tableCreateSyntaxTextView setFont:oldFont]; [tableCreateSyntaxTextView setEditable:editableStatus]; - + if (error != nil) { NSLog(@"Error generating table's create syntax HTML for printing. Excluding from print out. Error was: %@", [error localizedDescription]); @@ -445,7 +449,7 @@ NSString *HTMLString = [[[NSString alloc] initWithData:HTMLData encoding:NSUTF8StringEncoding] autorelease]; [tableInfo setObject:HTMLString forKey:@"createSyntax"]; - + return tableInfo; } @@ -455,24 +459,24 @@ - (void)textDidEndEditing:(NSNotification *)notification { id object = [notification object]; - + if ((object == tableCommentsTextView) && ([object isEditable]) && ([selectedTable length] > 0)) { - + NSString *currentComment = [[tableDataInstance statusValueForKey:@"Comment"] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; NSString *newComment = [[tableCommentsTextView string] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; // Check that the user actually changed the tables comment if (![currentComment isEqualToString:newComment]) { - + // Alter table's comment [connection queryString:[NSString stringWithFormat:@"ALTER TABLE %@ COMMENT = '%@'", [selectedTable backtickQuotedString], [connection prepareString:newComment]]]; - + if ([connection getLastErrorID] == 0) { // Reload the table's data [self reloadTable:self]; } else { - SPBeginAlertSheet(NSLocalizedString(@"Error changing table comment", @"error changing table comment message"), + SPBeginAlertSheet(NSLocalizedString(@"Error changing table comment", @"error changing table comment message"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [NSApp mainWindow], self, nil, nil, [NSString stringWithFormat:NSLocalizedString(@"An error occurred when trying to change the table's comment to '%@'.\n\nMySQL said: %@", @"error changing table comment informative message"), newComment, [connection getLastErrorMessage]]); } @@ -506,13 +510,13 @@ if (![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:SPMainToolbarTableInfo]) return; NSDictionary *statusFields = [tableDataInstance statusValues]; - + if (!selectedTable || ![selectedTable length] || [[statusFields objectForKey:@"Engine"] isEqualToString:@"View"]) return; // If we are viewing tables in the information_schema database, then disable all controls that cause table // changes as these tables are not modifiable by anyone. BOOL isInformationSchemaDb = [[tableDocumentInstance database] isEqualToString:@"information_schema"]; - + if ([[databaseDataInstance getDatabaseStorageEngines] count] && [statusFields objectForKey:@"Engine"]) { [tableTypePopUpButton setEnabled:(!isInformationSchemaDb)]; } @@ -540,7 +544,7 @@ [[NSNotificationCenter defaultCenter] removeObserver:self]; [connection release], connection = nil; - + [super dealloc]; } @@ -549,45 +553,45 @@ @implementation SPExtendedTableInfo (PrivateAPI) /** - * Format and returns the value within the info dictionary with the associated key. + * Format and returns the value within the info dictionary with the associated key. */ - (NSString *)_formatValueWithKey:(NSString *)key inDictionary:(NSDictionary *)infoDict { NSString *value = [infoDict objectForKey:key]; - + if ([value isKindOfClass:[NSNull class]]) { value = @""; - } + } else { // Format size strings - if ([key isEqualToString:@"Data_length"] || - [key isEqualToString:@"Max_data_length"] || - [key isEqualToString:@"Index_length"] || + if ([key isEqualToString:@"Data_length"] || + [key isEqualToString:@"Max_data_length"] || + [key isEqualToString:@"Index_length"] || [key isEqualToString:@"Data_free"]) { - + value = [NSString stringForByteSize:[value longLongValue]]; } // Format date strings to the user's long date format else if ([key isEqualToString:@"Create_time"] || [key isEqualToString:@"Update_time"]) { - + // Create date formatter NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease]; - + [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; - + [dateFormatter setDateStyle:NSDateFormatterLongStyle]; [dateFormatter setTimeStyle:NSDateFormatterMediumStyle]; - + value = [dateFormatter stringFromDate:[NSDate dateWithNaturalLanguageString:value]]; } // Format numbers else if ([key isEqualToString:@"Rows"] || - [key isEqualToString:@"Avg_row_length"] || + [key isEqualToString:@"Avg_row_length"] || [key isEqualToString:@"Auto_increment"]) { - + NSNumberFormatter *numberFormatter = [[[NSNumberFormatter alloc] init] autorelease]; - + [numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle]; value = [numberFormatter stringFromNumber:[NSNumber numberWithLongLong:[value longLongValue]]]; @@ -598,7 +602,7 @@ } } } - + if ([key isEqualToString:@"Auto_increment"]) { return ([value length] > 0) ? value : NSLocalizedString(@"Not available", @"not available label"); } diff --git a/Source/SPTableData.m b/Source/SPTableData.m index a6a5819a..db9cccfe 100644 --- a/Source/SPTableData.m +++ b/Source/SPTableData.m @@ -62,7 +62,7 @@ [mySQLConnection retain]; } - + /* * Retrieve the encoding for the current table, using or refreshing the cache as appropriate. */ @@ -86,7 +86,7 @@ if (tableCreateSyntax == nil) { if ([tableListInstance tableType] == SPTableTypeView) { [self updateInformationForCurrentView]; - } + } else { [self updateInformationForCurrentTable]; } @@ -141,7 +141,7 @@ * Retrieve a column with a specified name, using or refreshing the cache as appropriate. */ - (NSDictionary *) columnWithName:(NSString *)colName -{ +{ if ([columns count] == 0) { if ([tableListInstance tableType] == SPTableTypeView) { [self updateInformationForCurrentView]; @@ -159,7 +159,7 @@ * Retrieve column names for the current table as an array, using or refreshing the cache as appropriate. */ - (NSArray *) columnNames -{ +{ if ([columnNames count] == 0) { if ([tableListInstance tableType] == SPTableTypeView) { [self updateInformationForCurrentView]; @@ -175,7 +175,7 @@ * Retrieve a specified column for the current table as a dictionary, using or refreshing the cache as appropriate. */ - (NSDictionary *) columnAtIndex:(NSInteger)index -{ +{ if ([columns count] == 0) { if ([tableListInstance tableType] == SPTableTypeView) { [self updateInformationForCurrentView]; @@ -186,13 +186,13 @@ return [columns objectAtIndex:index]; } -/* +/* * Checks if this column is type text or blob. * Used to determine if we have to show a popup when we edit a value from this column. */ - (BOOL) columnIsBlobOrText:(NSString *)colName -{ +{ if ([columns count] == 0) { if ([tableListInstance tableType] == SPTableTypeView) { [self updateInformationForCurrentView]; @@ -200,7 +200,7 @@ [self updateInformationForCurrentTable]; } } - + return (BOOL) ([[[self columnWithName:colName] objectForKey:@"typegrouping"] isEqualToString:@"textdata" ] || [[[self columnWithName:colName] objectForKey:@"typegrouping"] isEqualToString:@"blobdata"]); } @@ -221,7 +221,7 @@ * via other means and are subsequently more accurate than the value currently set. */ - (void)setStatusValue:(NSString *)value forKey:(NSString *)key -{ +{ [status setValue:value forKey:key]; } @@ -246,17 +246,17 @@ [columns removeAllObjects]; [columnNames removeAllObjects]; [status removeAllObjects]; - + if (triggers != nil) { [triggers release]; triggers = nil; } - + if (tableEncoding != nil) { [tableEncoding release]; tableEncoding = nil; } - + if (tableCreateSyntax != nil) { [tableCreateSyntax release]; tableCreateSyntax = nil; @@ -292,15 +292,15 @@ NSDictionary *tableData = nil; NSDictionary *columnData; NSEnumerator *enumerator; - + [columns removeAllObjects]; [columnNames removeAllObjects]; [constraints removeAllObjects]; - if( [tableListInstance tableType] == SPTableTypeTable || [tableListInstance tableType] == SPTableTypeView ) { + if( [tableListInstance tableType] == SPTableTypeTable || [tableListInstance tableType] == SPTableTypeView ) { tableData = [self informationForTable:[tableListInstance tableName]]; } - + if (tableData == nil ) { return FALSE; } @@ -311,7 +311,7 @@ while (columnData = [enumerator nextObject]) { [columnNames addObject:[NSString stringWithString:[columnData objectForKey:@"name"]]]; } - + if (tableEncoding != nil) { [tableEncoding release]; } @@ -330,7 +330,7 @@ * Returns a boolean indicating success. */ - (NSDictionary *) informationForTable:(NSString *)tableName -{ +{ SPSQLParser *createTableParser, *fieldsParser, *fieldParser; NSMutableArray *tableColumns, *fieldStrings; NSMutableDictionary *tableColumn, *tableData; @@ -342,7 +342,7 @@ [columns removeAllObjects]; [columnNames removeAllObjects]; [constraints removeAllObjects]; - + // Catch unselected tables and return nil if ([tableName isEqualToString:@""] || !tableName) return nil; @@ -355,11 +355,11 @@ // Retrieve the CREATE TABLE syntax for the table MCPResult *theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW CREATE TABLE %@", [tableName backtickQuotedString]]]; [theResult setReturnDataAsStrings:YES]; - + // Check for any errors, but only display them if a connection still exists if ([mySQLConnection queryErrored]) { if ([mySQLConnection isConnected]) { - SPBeginAlertSheet(NSLocalizedString(@"Error retrieving table information", @"error retrieving table information message"), NSLocalizedString(@"OK", @"OK button"), + SPBeginAlertSheet(NSLocalizedString(@"Error retrieving table information", @"error retrieving table information message"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [NSApp mainWindow], self, nil, nil, [NSString stringWithFormat:NSLocalizedString(@"An error occurred while retrieving the information for table '%@'. Please try again.\n\nMySQL said: %@", @"error retrieving table information informative message"), tableName, [mySQLConnection getLastErrorMessage]]); @@ -370,18 +370,18 @@ } if (changeEncoding) [mySQLConnection restoreStoredEncoding]; } - + return nil; } // Retrieve the table syntax string NSArray *syntaxResult = [theResult fetchRowAsArray]; NSArray *resultFieldNames = [theResult fetchFieldNames]; - - // Only continue if syntaxResult is not nil. This accommodates causes where the above query caused the + + // Only continue if syntaxResult is not nil. This accommodates causes where the above query caused the // connection reconnect dialog to appear and the user chose to close the connection. if (!syntaxResult) return nil; - + if (tableCreateSyntax != nil) [tableCreateSyntax release], tableCreateSyntax = nil; // A NULL value indicates that the user does not have permission to view the syntax @@ -410,7 +410,7 @@ tableColumns = [[NSMutableArray alloc] init]; tableColumn = [[NSMutableDictionary alloc] init]; fieldParser = [[SPSQLParser alloc] init]; - + NSCharacterSet *whitespaceAndNewlineSet = [NSCharacterSet whitespaceAndNewlineCharacterSet]; NSCharacterSet *quoteSet = [NSCharacterSet characterSetWithCharactersInString:@"`'\""]; NSCharacterSet *bracketSet = [NSCharacterSet characterSetWithCharactersInString:@"()"]; @@ -461,18 +461,18 @@ ]; } [fieldsParser setIgnoreCommentStrings:NO]; - + [tableColumn setObject:[NSNumber numberWithInteger:[tableColumns count]] forKey:@"datacolumnindex"]; [tableColumn setObject:fieldName forKey:@"name"]; // Split the remaining field definition string by spaces and process [tableColumn addEntriesFromDictionary:[self parseFieldDefinitionStringParts:[fieldsParser splitStringByCharacter:' ' skippingBrackets:YES]]]; - + //if column is not null, but doesn't have a default value, set empty string if([[tableColumn objectForKey:@"null"] integerValue] == 0 && [[tableColumn objectForKey:@"autoincrement"] integerValue] == 0 && ![tableColumn objectForKey:@"default"]) { [tableColumn setObject:@"" forKey:@"default"]; } - + // Store the column. NSMutableDictionary *d = [NSMutableDictionary dictionaryWithCapacity:1]; [d setDictionary:tableColumn]; @@ -492,13 +492,13 @@ NSMutableArray *keyColumns = [NSMutableArray array]; NSArray *keyColumnStrings = [[[parts objectAtIndex:4] stringByTrimmingCharactersInSet:bracketSet] componentsSeparatedByString:@","]; - + for (NSString *keyColumn in keyColumnStrings) { [fieldsParser setString:[[keyColumn stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] stringByTrimmingCharactersInSet:bracketSet]]; [keyColumns addObject:[fieldsParser unquotedString]]; } - + [constraintDetails setObject:keyColumns forKey:@"columns"]; [fieldsParser setString:[[parts objectAtIndex:6] stringByTrimmingCharactersInSet:bracketSet]]; @@ -523,7 +523,7 @@ [constraintDetails setObject:NSArrayObjectAtIndex(parts, 10) forKey:@"update"]; } - } + } else if( [NSArrayObjectAtIndex(parts, 9) hasPrefix:@"DELETE"] ) { if( [NSArrayObjectAtIndex(parts, 10) hasPrefix:@"SET"] ) { [constraintDetails setObject:@"SET NULL" @@ -551,7 +551,7 @@ [constraintDetails setObject:NSArrayObjectAtIndex(parts, nextOffs+1) forKey:@"update"]; } - } + } else if( [NSArrayObjectAtIndex(parts, nextOffs) hasPrefix:@"DELETE"] ) { if( [NSArrayObjectAtIndex(parts, nextOffs+1) hasPrefix:@"SET"] ) { [constraintDetails setObject:@"SET NULL" @@ -597,7 +597,7 @@ break; } } - + } } // who knows @@ -635,7 +635,7 @@ [createTableParser release]; [fieldParser release]; - + // this will be 'Table' or 'View' [tableData setObject:[resultFieldNames objectAtIndex:0] forKey:@"type"]; @@ -675,7 +675,7 @@ while (columnData = [enumerator nextObject]) { [columnNames addObject:[NSString stringWithString:[columnData objectForKey:@"name"]]]; } - + if (tableEncoding != nil) { [tableEncoding release]; } @@ -720,7 +720,7 @@ // Check for any errors, but only display them if a connection still exists if ([mySQLConnection queryErrored]) { 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]]); @@ -754,7 +754,7 @@ // Check for any errors, but only display them if a connection still exists if ([mySQLConnection queryErrored]) { 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]]); @@ -826,13 +826,6 @@ if ([[tableListInstance tableName] isEqualToString:@""] || ![tableListInstance tableName]) return FALSE; - // When views are selected, populate the table with a default dictionary - all values, including comment, return no - // meaningful information for views so we may as well skip the query. - if ([tableListInstance tableType] == SPTableTypeView) { - [status setDictionary:[NSDictionary dictionaryWithObjectsAndKeys:@"View", @"Engine", @"No status information is available for views.", @"Comment", [tableListInstance tableName], @"Name", nil]]; - return TRUE; - } - // Ensure queries are run as UTF8 if (changeEncoding) { [mySQLConnection storeEncodingForRestoration]; @@ -855,6 +848,11 @@ [escapedDatabaseName replaceOccurrencesOfString:@"'" withString:@"\\\'" options:0 range:NSMakeRange(0, [escapedDatabaseName length])]; tableStatusResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SELECT * FROM information_schema.ROUTINES AS r WHERE r.SPECIFIC_NAME = '%@' AND r.ROUTINE_SCHEMA = '%@' AND r.ROUTINE_TYPE = 'FUNCTION'", escapedTableName, escapedDatabaseName]]; } + else if ([tableListInstance tableType] == SPTableTypeView) { + NSMutableString *escapedDatabaseName = [NSMutableString stringWithString:[tableDocumentInstance database]]; + [escapedDatabaseName replaceOccurrencesOfString:@"'" withString:@"\\\'" options:0 range:NSMakeRange(0, [escapedDatabaseName length])]; + tableStatusResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SELECT * FROM information_schema.VIEWS AS r WHERE r.TABLE_NAME = '%@' AND r.TABLE_SCHEMA = '%@'", escapedTableName, escapedDatabaseName]]; + } else if ([tableListInstance tableType] == SPTableTypeTable) { tableStatusResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW TABLE STATUS LIKE '%@'", escapedTableName ]]; [tableStatusResult setReturnDataAsStrings:YES]; @@ -863,7 +861,7 @@ // Check for any errors, only displaying them if the connection hasn't been terminated if ([mySQLConnection queryErrored]) { 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 occured while retrieving status data.\nMySQL said: %@", @"message of panel when retrieving view information failed"), [mySQLConnection getLastErrorMessage]]); @@ -904,6 +902,18 @@ [status setObject:[[tableStatusResult fetchRowAsArray] objectAtIndex:0] forKey:@"Rows"]; [status setObject:@"y" forKey:@"RowsCountAccurate"]; } + + } + + // When views are selected, populate the table by adding some default information. + else if ([tableListInstance tableType] == SPTableTypeView) { + [status addEntriesFromDictionary:[NSDictionary dictionaryWithObjectsAndKeys: + @"View", @"Engine", + @"No status information is available for views.", @"Comment", + [tableListInstance tableName], @"Name", + [status objectForKey:@"COLLATION_CONNECTION"], @"Collation", + [status objectForKey:@"CHARACTER_SET_CLIENT"], @"CharacterSetClient", + nil]]; } if (changeEncoding) [mySQLConnection restoreStoredEncoding]; @@ -924,14 +934,14 @@ [mySQLConnection setEncoding:@"utf8"]; } - MCPResult *theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"/*!50003 SHOW TRIGGERS WHERE `Table` = %@ */", + MCPResult *theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"/*!50003 SHOW TRIGGERS WHERE `Table` = %@ */", [[tableListInstance tableName] tickQuotedString]]]; [theResult setReturnDataAsStrings:YES]; - + // Check for any errors, but only display them if a connection still exists if ([mySQLConnection queryErrored]) { if ([mySQLConnection isConnected]) { - SPBeginAlertSheet(NSLocalizedString(@"Error retrieving trigger information", @"error retrieving trigger information message"), NSLocalizedString(@"OK", @"OK button"), + SPBeginAlertSheet(NSLocalizedString(@"Error retrieving trigger information", @"error retrieving trigger information message"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [NSApp mainWindow], self, nil, nil, [NSString stringWithFormat:NSLocalizedString(@"An error occurred while retrieving the trigger information for table '%@'. Please try again.\n\nMySQL said: %@", @"error retrieving table information informative message"), [tableListInstance tableName], [mySQLConnection getLastErrorMessage]]); @@ -1127,14 +1137,14 @@ && [[[definitionParts objectAtIndex:definitionPartsIndex+2] uppercaseString] isEqualToString:@"CURRENT_TIMESTAMP"]) { [fieldDetails setValue:[NSNumber numberWithBool:YES] forKey:@"onupdatetimestamp"]; definitionPartsIndex += 2; - + // Column comments } else if ([detailString isEqualToString:@"COMMENT"] && (definitionPartsIndex + 1 < partsArrayLength)) { detailParser = [[SPSQLParser alloc] initWithString:[definitionParts objectAtIndex:definitionPartsIndex+1]]; [fieldDetails setValue:[detailParser unquotedString] forKey:@"comment"]; [detailParser release]; definitionPartsIndex++; - + // Preserve unhandled details to avoid losing information when rearranging columns etc // TODO: Currently unhandled: [UNIQUE | PRIMARY] KEY | COLUMN_FORMAT bar | STORAGE q | REFERENCES... } else { @@ -1187,7 +1197,7 @@ return nil; } - + for( i = 0; i < [r numOfRows]; i++ ) { resultRow = [r fetchRowAsArray]; // check if the row is indeed a key (for MySQL servers before 5.0.3) @@ -1211,7 +1221,7 @@ [columnNames release]; [constraints release]; [status release]; - + if (triggers) [triggers release]; if (tableEncoding) [tableEncoding release]; if (tableCreateSyntax) [tableCreateSyntax release]; diff --git a/Source/SPTableInfo.m b/Source/SPTableInfo.m index 00db406e..61a0bb2c 100644 --- a/Source/SPTableInfo.m +++ b/Source/SPTableInfo.m @@ -50,8 +50,8 @@ - (void)awakeFromNib { [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(tableChanged:) - name:SPTableChangedNotification + selector:@selector(tableChanged:) + name:SPTableChangedNotification object:tableDocumentInstance]; [info addObject:NSLocalizedString(@"TABLE INFORMATION", @"header for table info pane")]; @@ -81,20 +81,12 @@ [info removeAllObjects]; - // For views, no information can be displayed. - if ([tableListInstance tableType] == SPTableTypeView) { - [info addObject:NSLocalizedString(@"VIEW INFORMATION", @"header for view info pane")]; - [info addObject:NSLocalizedString(@"no information available", @"no information available")]; - [infoTable reloadData]; - return; - } - if ([[tableListInstance tableName] isEqualToString:@""]) { [info addObject:NSLocalizedString(@"INFORMATION", @"header for blank info pane")]; [info addObject:NSLocalizedString(@"multiple selection", @"multiple selection")]; [infoTable reloadData]; return; - } + } // Get TABLE information if ([tableListInstance tableType] == SPTableTypeTable) { @@ -130,7 +122,7 @@ if (![[tableStatus objectForKey:@"Rows"] isNSNull]) { [info addObject:[NSString stringWithFormat:[[tableStatus objectForKey:@"RowsCountAccurate"] boolValue] ? NSLocalizedString(@"rows: %@", @"rows: %@") : NSLocalizedString(@"rows: ~%@", @"rows: ~%@"), [numberFormatter stringFromNumber:[NSNumber numberWithLongLong:[[tableStatus objectForKey:@"Rows"] longLongValue]]]]]; - } + } [info addObject:[NSString stringWithFormat:NSLocalizedString(@"size: %@", @"size: %@"), [NSString stringForByteSize:[[tableStatus objectForKey:@"Data_length"] longLongValue]]]]; [info addObject:[NSString stringWithFormat:NSLocalizedString(@"encoding: %@", @"encoding: %@"), [tableDataInstance tableEncoding]]]; @@ -142,7 +134,7 @@ } } - + // Get PROC/FUNC information else if ([tableListInstance tableType] == SPTableTypeProc || [tableListInstance tableType] == SPTableTypeFunc) { @@ -150,7 +142,7 @@ [info addObject:NSLocalizedString(@"PROCEDURE INFORMATION", @"header for procedure info pane")]; else [info addObject:NSLocalizedString(@"FUNCTION INFORMATION", @"header for function info pane")]; - + if ([tableListInstance tableName]) { // Retrieve the table status information via the data cache @@ -171,7 +163,7 @@ // Check for 'LAST_ALTERED' if (![[tableStatus objectForKey:@"LAST_ALTERED"] isNSNull]) { - + // Add the update date to the infoTable [info addObject:[NSString stringWithFormat:NSLocalizedString(@"updated: %@", @"updated: %@"), [self _getUserDefinedDateStringFromMySQLDate:[tableStatus objectForKey:@"LAST_ALTERED"]]]]; } @@ -200,6 +192,57 @@ } } + // Get VIEW information + else if ([tableListInstance tableType] == SPTableTypeView) { + + [info addObject:NSLocalizedString(@"VIEW INFORMATION", @"header for view info pane")]; + + if ([tableListInstance tableName]) { + + // Retrieve the table status information via the data cache + tableStatus = [tableDataInstance statusValues]; + + // Check for errors + if (![tableStatus count]) { + [info addObject:NSLocalizedString(@"error occurred", @"error occurred")]; + return; + } + + // Check for 'CREATED' == NULL + if (![[tableStatus objectForKey:@"DEFINER"] isNSNull]) { + + // Add the creation date to the infoTable + [info addObject:[NSString stringWithFormat:NSLocalizedString(@"definer: %@", @"definer: %@"), [tableStatus objectForKey:@"DEFINER"]]]; + + // Check for 'SECURITY_TYPE' + if (![[tableStatus objectForKey:@"SECURITY_TYPE"] isNSNull]) { + [info addObject:[NSString stringWithFormat:NSLocalizedString(@"execution privilege: %@", @"execution privilege: %@"), [tableStatus objectForKey:@"SECURITY_TYPE"]]]; + } + + // Check for 'IS_UPDATABLE' + if (![[tableStatus objectForKey:@"IS_UPDATABLE"] isNSNull]) { + [info addObject:[NSString stringWithFormat:NSLocalizedString(@"is updatable: %@", @"is updatable: %@"), [tableStatus objectForKey:@"IS_UPDATABLE"]]]; + } + + // Check for 'CHECK_OPTION' + if (![[tableStatus objectForKey:@"CHECK_OPTION"] isNSNull]) { + [info addObject:[NSString stringWithFormat:NSLocalizedString(@"check option: %@", @"check option: %@"), [tableStatus objectForKey:@"CHECK_OPTION"]]]; + } + + // Check for 'CHARACTER_SET_CLIENT' + if (![[tableStatus objectForKey:@"CHARACTER_SET_CLIENT"] isNSNull]) { + [info addObject:[NSString stringWithFormat:NSLocalizedString(@"character set client: %@", @"character set client: %@"), [tableStatus objectForKey:@"CHARACTER_SET_CLIENT"]]]; + } + + // Check for 'COLLATION_CONNECTION' + if (![[tableStatus objectForKey:@"COLLATION_CONNECTION"] isNSNull]) { + [info addObject:[NSString stringWithFormat:NSLocalizedString(@"collation connection: %@", @"collation connection: %@"), [tableStatus objectForKey:@"COLLATION_CONNECTION"]]]; + } + + } + } + + } [infoTable reloadData]; |