aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Lohrmann <dmoagx@users.noreply.github.com>2016-04-09 04:28:00 +0200
committerMax Lohrmann <dmoagx@users.noreply.github.com>2016-04-09 04:28:00 +0200
commitfc9e31b3e4bf24bbc0448ab900dfaeddf51ef4f7 (patch)
tree7da1960ca4e94048d5feb44d23925ace30dd07c3
parent6672e0d55810a7447fd06ef1113ad88473ba7538 (diff)
downloadsequelpro-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.plist8
-rw-r--r--Source/SPFunctions.h7
-rw-r--r--Source/SPFunctions.m7
-rw-r--r--Source/SPObjectAdditions.h6
-rw-r--r--Source/SPObjectAdditions.m7
-rw-r--r--Source/SPTableContent.m61
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 &apos;&apos;</string>
</dict>
+ <dict>
+ <key>MenuLabel</key>
+ <string>= (Hex String)</string>
+ <key>NumberOfArguments</key>
+ <integer>1</integer>
+ <key>Clause</key>
+ <string>= $BINARY UNHEX(&apos;${}&apos;)</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];
}
}
}