diff options
author | Max Lohrmann <dmoagx@users.noreply.github.com> | 2016-04-09 04:28:00 +0200 |
---|---|---|
committer | Max Lohrmann <dmoagx@users.noreply.github.com> | 2016-04-09 04:28:00 +0200 |
commit | fc9e31b3e4bf24bbc0448ab900dfaeddf51ef4f7 (patch) | |
tree | 7da1960ca4e94048d5feb44d23925ace30dd07c3 | |
parent | 6672e0d55810a7447fd06ef1113ad88473ba7538 (diff) | |
download | sequelpro-fc9e31b3e4bf24bbc0448ab900dfaeddf51ef4f7.tar.gz sequelpro-fc9e31b3e4bf24bbc0448ab900dfaeddf51ef4f7.tar.bz2 sequelpro-fc9e31b3e4bf24bbc0448ab900dfaeddf51ef4f7.zip |
* Added two helper methods for working with nil/NSNull in arrays
* Fixed a case of "Updating UI from background thread" when navigating foreign keys *within* a table
* Fixed navigating foreign keys of binary columns causing exceptions if the origin table is not in latin1 and the binary data not "text like" (#2098).
* As a consequence binary columns will now use Hex representation when navigating FKs.
* Added a new content filter to do "= UNHEX($x)" as an interim solution
-rw-r--r-- | Resources/English.lproj/ContentFilters.plist | 8 | ||||
-rw-r--r-- | Source/SPFunctions.h | 7 | ||||
-rw-r--r-- | Source/SPFunctions.m | 7 | ||||
-rw-r--r-- | Source/SPObjectAdditions.h | 6 | ||||
-rw-r--r-- | Source/SPObjectAdditions.m | 7 | ||||
-rw-r--r-- | Source/SPTableContent.m | 61 |
6 files changed, 73 insertions, 23 deletions
diff --git a/Resources/English.lproj/ContentFilters.plist b/Resources/English.lproj/ContentFilters.plist index 88e11ea5..a3eab36f 100644 --- a/Resources/English.lproj/ContentFilters.plist +++ b/Resources/English.lproj/ContentFilters.plist @@ -219,6 +219,14 @@ Do quote strings manually.</string> <key>Clause</key> <string>NOT LIKE ''</string> </dict> + <dict> + <key>MenuLabel</key> + <string>= (Hex String)</string> + <key>NumberOfArguments</key> + <integer>1</integer> + <key>Clause</key> + <string>= $BINARY UNHEX('${}')</string> + </dict> </array> <key>date</key> <array> diff --git a/Source/SPFunctions.h b/Source/SPFunctions.h index 0cda7e36..6a7845c0 100644 --- a/Source/SPFunctions.h +++ b/Source/SPFunctions.h @@ -49,3 +49,10 @@ int SPBetterRandomBytes(uint8_t *buf, size_t count); * @return the same value, casted to unsigned integer */ NSUInteger SPIntS2U(NSInteger i); + +/** + * Converts nil to NSNull for passing into arrays + * @return The object that was passed in or [NSNull null] if object == nil + * @see -[SPObjectAdditions unboxNull] + */ +id SPBoxNil(id object); diff --git a/Source/SPFunctions.m b/Source/SPFunctions.m index 6f11d236..93008059 100644 --- a/Source/SPFunctions.m +++ b/Source/SPFunctions.m @@ -76,3 +76,10 @@ NSUInteger SPIntS2U(NSInteger i) return (NSUInteger)i; } + +id SPBoxNil(id object) +{ + if(object == nil) return [NSNull null]; + + return object; +} diff --git a/Source/SPObjectAdditions.h b/Source/SPObjectAdditions.h index bfe620d9..cf71801b 100644 --- a/Source/SPObjectAdditions.h +++ b/Source/SPObjectAdditions.h @@ -36,6 +36,12 @@ - (BOOL)isNSNull; /** + * This is the complementing method to SPBoxNull() + * @return The object itself or nil if self == [NSNull null] + */ +- (instancetype)unboxNull; + +/** * easier to read version of [array containsObject:x] */ - (BOOL)isInArray:(NSArray *)list; diff --git a/Source/SPObjectAdditions.m b/Source/SPObjectAdditions.m index 9dfe8559..43956623 100644 --- a/Source/SPObjectAdditions.m +++ b/Source/SPObjectAdditions.m @@ -44,6 +44,13 @@ return (self == null); } +- (instancetype)unboxNull +{ + if([self isNSNull]) return nil; + + return self; +} + - (BOOL)isInArray:(NSArray *)list { return [list containsObject:self]; diff --git a/Source/SPTableContent.m b/Source/SPTableContent.m index d39edd73..1ed74576 100644 --- a/Source/SPTableContent.m +++ b/Source/SPTableContent.m @@ -62,6 +62,7 @@ #import "SPCustomQuery.h" #import "SPThreadAdditions.h" #import "SPTableFilterParser.h" +#import "SPFunctions.h" #import <pthread.h> #import <SPMySQL/SPMySQL.h> @@ -721,7 +722,7 @@ static NSString *SPTableFilterSetDefaultOperator = @"SPTableFilterSetDefaultOper if ([fieldField itemWithTitle:filterFieldToRestore] && ((!filterComparisonToRestore && filterValueToRestore) - || [compareField itemWithTitle:filterComparisonToRestore])) + || (filterComparisonToRestore && [compareField itemWithTitle:filterComparisonToRestore]))) { if (filterComparisonToRestore) [compareField selectItemWithTitle:filterComparisonToRestore]; if([filterComparisonToRestore isEqualToString:@"BETWEEN"]) { @@ -1118,7 +1119,7 @@ static NSString *SPTableFilterSetDefaultOperator = @"SPTableFilterSetDefaultOper NSDictionary *filter = [[contentFilters objectForKey:compareType] objectAtIndex:[[compareField selectedItem] tag]]; if(![filter objectForKey:@"NumberOfArguments"]) { - NSLog(@"Error while retrieving filter clause. No “Clause” or/and “NumberOfArguments” key found."); + NSLog(@"Error while retrieving filter clause. No “NumberOfArguments” key found."); NSBeep(); return nil; } @@ -2487,6 +2488,7 @@ static NSString *SPTableFilterSetDefaultOperator = @"SPTableFilterSetDefaultOper [self clickLinkArrowTask:theArrowCell]; } } + - (void)clickLinkArrowTask:(SPTextAndLinkCell *)theArrowCell { NSAutoreleasePool *linkPool = [[NSAutoreleasePool alloc] init]; @@ -2494,7 +2496,8 @@ static NSString *SPTableFilterSetDefaultOperator = @"SPTableFilterSetDefaultOper BOOL tableFilterRequired = NO; // Ensure the clicked cell has foreign key details available - NSDictionary *refDictionary = [[dataColumns objectAtIndex:dataColumnIndex] objectForKey:@"foreignkeyreference"]; + NSDictionary *columnDefinition = [dataColumns objectAtIndex:dataColumnIndex]; + NSDictionary *refDictionary = [columnDefinition objectForKey:@"foreignkeyreference"]; if (!refDictionary) { [linkPool release]; return; @@ -2508,24 +2511,35 @@ static NSString *SPTableFilterSetDefaultOperator = @"SPTableFilterSetDefaultOper NSString *targetFilterValue = [tableValues cellDataAtRow:[theArrowCell getClickedRow] column:dataColumnIndex]; + //when navigating binary relations (eg. raw UUID) do so via a hex-encoded value for charset safety + BOOL navigateAsHex = ([targetFilterValue isKindOfClass:[NSData class]] && [[columnDefinition objectForKey:@"typegrouping"] isEqualToString:@"binary"]); + if(navigateAsHex) targetFilterValue = [mySQLConnection escapeData:(NSData *)targetFilterValue includingQuotes:NO]; + // If the link is within the current table, apply filter settings manually if ([[refDictionary objectForKey:@"table"] isEqualToString:selectedTable]) { - [fieldField selectItemWithTitle:[refDictionary objectForKey:@"column"]]; - [self setCompareTypes:self]; - if ([targetFilterValue isNSNull]) { - [compareField selectItemWithTitle:@"IS NULL"]; - } else { - [argumentField setStringValue:targetFilterValue]; - } + SPMainQSync(^{ + [fieldField selectItemWithTitle:[refDictionary objectForKey:@"column"]]; + [self setCompareTypes:self]; + if ([targetFilterValue isNSNull]) { + [compareField selectItemWithTitle:@"IS NULL"]; + } + else { + if(navigateAsHex) [compareField selectItemWithTitle:@"= (Hex String)"]; + [argumentField setStringValue:targetFilterValue]; + } + }); tableFilterRequired = YES; } else { - + NSString *filterComparison = nil; + if([targetFilterValue isNSNull]) filterComparison = @"IS NULL"; + else if(navigateAsHex) filterComparison = @"= (Hex String)"; + // Store the filter details to use when loading the target table - NSDictionary *filterSettings = [NSDictionary dictionaryWithObjectsAndKeys: - [refDictionary objectForKey:@"column"], @"filterField", - targetFilterValue, @"filterValue", - ([targetFilterValue isNSNull]?@"IS NULL":nil), @"filterComparison", - nil]; + NSDictionary *filterSettings = @{ + @"filterField": [refDictionary objectForKey:@"column"], + @"filterValue": targetFilterValue, + @"filterComparison": SPBoxNil(filterComparison) + }; [self setFiltersToRestore:filterSettings]; // Attempt to switch to the target table @@ -3880,10 +3894,10 @@ static NSString *SPTableFilterSetDefaultOperator = @"SPTableFilterSetDefaultOper if (firstBetweenValueToRestore) SPClear(firstBetweenValueToRestore); if (secondBetweenValueToRestore) SPClear(secondBetweenValueToRestore); - if (filterSettings) { + if ([filterSettings count]) { if ([filterSettings objectForKey:@"filterField"]) filterFieldToRestore = [[NSString alloc] initWithString:[filterSettings objectForKey:@"filterField"]]; - if ([filterSettings objectForKey:@"filterComparison"]) { + if ([[filterSettings objectForKey:@"filterComparison"] unboxNull]) { // Check if operator is BETWEEN, if so set up input fields if([[filterSettings objectForKey:@"filterComparison"] isEqualToString:@"BETWEEN"]) { [argumentField setHidden:YES]; @@ -3896,17 +3910,18 @@ static NSString *SPTableFilterSetDefaultOperator = @"SPTableFilterSetDefaultOper filterComparisonToRestore = [[NSString alloc] initWithString:[filterSettings objectForKey:@"filterComparison"]]; } - if([[filterSettings objectForKey:@"filterComparison"] isEqualToString:@"BETWEEN"]) { + if([filterComparisonToRestore isEqualToString:@"BETWEEN"]) { if ([filterSettings objectForKey:@"firstBetweenField"]) firstBetweenValueToRestore = [[NSString alloc] initWithString:[filterSettings objectForKey:@"firstBetweenField"]]; if ([filterSettings objectForKey:@"secondBetweenField"]) secondBetweenValueToRestore = [[NSString alloc] initWithString:[filterSettings objectForKey:@"secondBetweenField"]]; } else { - if ([filterSettings objectForKey:@"filterValue"] && ![[filterSettings objectForKey:@"filterValue"] isNSNull]) { - if ([[filterSettings objectForKey:@"filterValue"] isKindOfClass:[NSData class]]) { - filterValueToRestore = [[NSString alloc] initWithData:[filterSettings objectForKey:@"filterValue"] encoding:[mySQLConnection stringEncoding]]; + id filterValue = [filterSettings objectForKey:@"filterValue"]; + if ([filterValue unboxNull]) { + if ([filterValue isKindOfClass:[NSData class]]) { + filterValueToRestore = [[NSString alloc] initWithData:(NSData *)filterValue encoding:[mySQLConnection stringEncoding]]; } else { - filterValueToRestore = [[NSString alloc] initWithString:[filterSettings objectForKey:@"filterValue"]]; + filterValueToRestore = [[NSString alloc] initWithString:(NSString *)filterValue]; } } } |