diff options
Diffstat (limited to 'Source/SPTableStructureLoading.m')
-rw-r--r-- | Source/SPTableStructureLoading.m | 194 |
1 files changed, 91 insertions, 103 deletions
diff --git a/Source/SPTableStructureLoading.m b/Source/SPTableStructureLoading.m index 5a1e8e10..b7f8e748 100644 --- a/Source/SPTableStructureLoading.m +++ b/Source/SPTableStructureLoading.m @@ -36,6 +36,8 @@ #import "SPIndexesController.h" #import "SPTablesList.h" #import "SPThreadAdditions.h" +#import "SPTableView.h" +#import "SPFunctions.h" #import <SPMySQL/SPMySQL.h> @@ -77,10 +79,11 @@ [[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 lastErrorMessage]]); + SPOnewayAlertSheet( + NSLocalizedString(@"Error", @"error"), + [NSApp mainWindow], + [NSString stringWithFormat:NSLocalizedString(@"An error occurred while retrieving information.\nMySQL said: %@", @"message of panel when retrieving information failed"), [mySQLConnection lastErrorMessage]] + ); } return; @@ -114,115 +117,97 @@ // Set up the encoding PopUpButtonCell NSArray *encodings = [databaseDataInstance getDatabaseCharacterSetEncodings]; - - if ([encodings count]) { - NSString *defaultEncodingDescription = nil; - - // Populate encoding popup button - NSMutableArray *encodingTitles = [[NSMutableArray alloc] initWithCapacity:[encodings count]+1]; - - [encodingTitles addObject:@""]; - - for (NSDictionary *encoding in encodings) - { - [encodingTitles addObject:(![encoding objectForKey:@"DESCRIPTION"]) ? [encoding objectForKey:@"CHARACTER_SET_NAME"] : [NSString stringWithFormat:@"%@ (%@)", [encoding objectForKey:@"DESCRIPTION"], [encoding objectForKey:@"CHARACTER_SET_NAME"]]]; - if ([[encoding objectForKey:@"CHARACTER_SET_NAME"] isEqualToString:[tableDataInstance tableEncoding]]) { - defaultEncodingDescription = [encodingTitles lastObject]; - } - } - - [[encodingPopupCell onMainThread] removeAllItems]; - [[encodingPopupCell onMainThread] addItemsWithTitles:encodingTitles]; - // Take the encoding that matches the table's encoding and gray it out - if (defaultEncodingDescription) { - NSMenuItem *tableEncodingMenuItem = [[encodingPopupCell menu] itemWithTitle:defaultEncodingDescription]; - NSMutableParagraphStyle *menuStyle = [[[NSMutableParagraphStyle alloc] init] autorelease]; - - [menuStyle setLineBreakMode:NSLineBreakByTruncatingTail]; - - NSMutableDictionary *menuAttributes = [NSMutableDictionary dictionaryWithObject:[NSColor lightGrayColor] forKey:NSForegroundColorAttributeName]; + SPMainQSync(^{ + [encodingPopupCell removeAllItems]; - CGFloat monospacedFontSize = [prefs floatForKey:SPMonospacedFontSize] > 0 ? [prefs floatForKey:SPMonospacedFontSize] : [NSFont smallSystemFontSize]; + if ([encodings count]) { - [menuAttributes setObject:[prefs boolForKey:SPUseMonospacedFonts] ? [NSFont fontWithName:SPDefaultMonospacedFontName size:monospacedFontSize] : [NSFont systemFontOfSize:[NSFont smallSystemFontSize]] forKey:NSFontAttributeName]; - - NSAttributedString *itemString = [[[NSAttributedString alloc] initWithString:defaultEncodingDescription attributes:menuAttributes] autorelease]; - - [[tableEncodingMenuItem onMainThread] setAttributedTitle:itemString]; - } + [encodingPopupCell addItemWithTitle:@"dummy"]; + //copy the default attributes and add gray color + NSMutableDictionary *defaultAttrs = [NSMutableDictionary dictionaryWithDictionary:[[encodingPopupCell attributedTitle] attributesAtIndex:0 effectiveRange:NULL]]; + [defaultAttrs setObject:[NSColor lightGrayColor] forKey:NSForegroundColorAttributeName]; + [[encodingPopupCell lastItem] setTitle:@""]; - [encodingTitles release]; - } - else { - [[encodingPopupCell onMainThread] removeAllItems]; - [[encodingPopupCell onMainThread] addItemWithTitle:NSLocalizedString(@"Not available", @"not available label")]; - } + for (NSDictionary *encoding in encodings) + { + NSString *encodingName = [encoding objectForKey:@"CHARACTER_SET_NAME"]; + NSString *title = (![encoding objectForKey:@"DESCRIPTION"]) ? encodingName : [NSString stringWithFormat:@"%@ (%@)", [encoding objectForKey:@"DESCRIPTION"], encodingName]; + + [encodingPopupCell addItemWithTitle:title]; + NSMenuItem *item = [encodingPopupCell lastItem]; + + [item setRepresentedObject:encodingName]; + + if ([encodingName isEqualToString:[tableDataInstance tableEncoding]]) { + + NSAttributedString *itemString = [[NSAttributedString alloc] initWithString:[item title] attributes:defaultAttrs]; + + [item setAttributedTitle:[itemString autorelease]]; + } + } + } + else { + [encodingPopupCell addItemWithTitle:NSLocalizedString(@"Not available", @"not available label")]; + } + }); // Process all the fields to normalise keys and add additional information for (id theField in theTableFields) { - // Select and re-map encoding and collation since [self dataSource] stores the choice as NSNumbers - NSString *fieldEncoding = @""; - NSInteger selectedIndex = 0; - NSString *type = [[[theField objectForKey:@"type"] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; - - NSString *collation = nil; - NSString *encoding = nil; - - if ([fieldValidation isFieldTypeString:type]) { - - collation = [theField objectForKey:@"collation"] ? [theField objectForKey:@"collation"] : [[tableDataInstance statusValues] objectForKey:@"collation"]; - encoding = [theField objectForKey:@"encoding"] ? [theField objectForKey:@"encoding"] : [tableDataInstance tableEncoding]; - - // If we still don't have a collation then fallback on the database default (not available on MySQL < 4.1.1). - if (!collation) { - collation = [databaseDataInstance getDatabaseDefaultCollation]; - } - } - if (encoding) { - for (id enc in encodings) - { - if ([[enc objectForKey:@"CHARACTER_SET_NAME"] isEqualToString:encoding]) { - fieldEncoding = encoding; - - // Set the selected index as the match index +1 due to the leading @"" in the popup list - [theField setObject:[NSNumber numberWithInteger:(selectedIndex + 1)] forKey:@"encoding"]; - break; + if([type isEqualToString:@"JSON"]) { + // MySQL 5.7 manual: + // "MySQL handles strings used in JSON context using the utf8mb4 character set and utf8mb4_bin collation. + // Strings in other character set are converted to utf8mb4 as necessary." + [theField setObject:@"utf8mb4" forKey:@"encodingName"]; + [theField setObject:@"utf8mb4_bin" forKey:@"collationName"]; + [theField setObject:@1 forKey:@"binary"]; + } + else if ([fieldValidation isFieldTypeString:type]) { + // The MySQL 4.1 manual says: + // + // MySQL chooses the column character set and collation in the following manner: + // 1. If both CHARACTER SET X and COLLATE Y were specified, then character set X and collation Y are used. + // 2. If CHARACTER SET X was specified without COLLATE, then character set X and its default collation are used. + // 3. If COLLATE Y was specified without CHARACTER SET, then the character set associated with Y and collation Y. + // 4. Otherwise, the table character set and collation are used. + NSString *encoding = [theField objectForKey:@"encoding"]; + NSString *collation = [theField objectForKey:@"collation"]; + if(encoding) { + if(collation) { + // 1 + } + else { + collation = [databaseDataInstance getDefaultCollationForEncoding:encoding]; // 2 } - - selectedIndex++; } - } - - selectedIndex = 0; - - if (encoding && collation) { - - NSArray *theCollations = [databaseDataInstance getDatabaseCollationsForEncoding:fieldEncoding]; - - for (id col in theCollations) - { - if ([[col objectForKey:@"COLLATION_NAME"] isEqualToString:collation]) { - - // Set the selected index as the match index +1 due to the leading @"" in the popup list - [theField setObject:[NSNumber numberWithInteger:(selectedIndex + 1)] forKey:@"collation"]; - - // Set BINARY if collation ends with _bin for convenience - if ([[col objectForKey:@"COLLATION_NAME"] hasSuffix:@"_bin"]) { - [theField setObject:@1 forKey:@"binary"]; + else { + if(collation) { + encoding = [databaseDataInstance getEncodingFromCollation:collation]; // 3 + } + else { + encoding = [tableDataInstance tableEncoding]; //4 + collation = [tableDataInstance statusValueForKey:@"Collation"]; + if(!collation) { + // should not happen, as the TABLE STATUS output always(?) includes the collation + collation = [databaseDataInstance getDefaultCollationForEncoding:encoding]; } - - break; } - - selectedIndex++; + } + + // MySQL < 4.1 does not support collations (they are part of the charset), it will be nil there + + [theField setObject:encoding forKey:@"encodingName"]; + [theField setObject:collation forKey:@"collationName"]; + + // Set BINARY if collation ends with _bin for convenience + if ([collation hasSuffix:@"_bin"]) { + [theField setObject:@1 forKey:@"binary"]; } } - // 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"]]; @@ -250,9 +235,15 @@ } // For timestamps/datetime check to see whether "on update CURRENT_TIMESTAMP" and set Extra accordingly - else if (([type isEqualToString:@"TIMESTAMP"] || [type isEqualToString:@"DATETIME"]) && - [[theField objectForKey:@"onupdatetimestamp"] integerValue]) { - [theField setObject:@"on update CURRENT_TIMESTAMP" forKey:@"Extra"]; + else if ([type isInArray:@[@"TIMESTAMP",@"DATETIME"]] && [[theField objectForKey:@"onupdatetimestamp"] boolValue]) { + NSString *ouct = @"on update CURRENT_TIMESTAMP"; + // restore a length parameter if the field has fractional seconds. + // the parameter of current_timestamp MUST match the field's length in that case, so we can just 'guess' it. + NSString *fieldLen = [theField objectForKey:@"length"]; + if([fieldLen length] && ![fieldLen isEqualToString:@"0"]) { + ouct = [ouct stringByAppendingFormat:@"(%@)",fieldLen]; + } + [theField setObject:ouct forKey:@"Extra"]; } } @@ -287,10 +278,7 @@ [tableDocumentInstance setStatusRequiresReload:YES]; // Query the structure of all databases in the background (mainly for completion) - [NSThread detachNewThreadWithName:SPCtxt(@"SPNavigatorController database structure querier", tableDocumentInstance) - target:[tableDocumentInstance databaseStructureRetrieval] - selector:@selector(queryDbStructureWithUserInfo:) - object:@{@"forceUpdate" : @YES}]; + [[tableDocumentInstance databaseStructureRetrieval] queryDbStructureInBackgroundWithUserInfo:@{@"forceUpdate" : @YES}]; [self loadTable:selectedTable]; } |