diff options
author | stuconnolly <stuart02@gmail.com> | 2010-07-15 10:57:32 +0000 |
---|---|---|
committer | stuconnolly <stuart02@gmail.com> | 2010-07-15 10:57:32 +0000 |
commit | b21ab51d37672f7e5934938d0ffde641f4de3a26 (patch) | |
tree | 0a2b670bebcaa55e046019794270beac0a699f6e | |
parent | 11bd9d4da5e42d5914b50c1f149d38ce6df863e7 (diff) | |
download | sequelpro-b21ab51d37672f7e5934938d0ffde641f4de3a26.tar.gz sequelpro-b21ab51d37672f7e5934938d0ffde641f4de3a26.tar.bz2 sequelpro-b21ab51d37672f7e5934938d0ffde641f4de3a26.zip |
Improve handling of BIT fields, including:
- Exporting BIT fields properly in SQL dumps using b'x' notation.
- Properly handling editing of BIT fields in both the content and custom query results views.
- Correctly display BIT fields in the content view, where binary values are zero-padded to the specified length of the field.
(Note, that the new BIT handling logic has only been added to MCPKit's MCPStreamingResult and MCPResult as the latter does not keep a record of the field's length which the new functionality depends on. Needs to be discussed).
-rw-r--r-- | Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m | 35 | ||||
-rw-r--r-- | Source/SPCustomQuery.m | 4 | ||||
-rw-r--r-- | Source/SPSQLExporter.m | 11 | ||||
-rw-r--r-- | Source/SPTableContent.m | 33 |
4 files changed, 61 insertions, 22 deletions
diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m b/Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m index 3b39738b..be09ed44 100644 --- a/Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m +++ b/Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m @@ -45,8 +45,12 @@ @interface MCPStreamingResult (PrivateAPI) + +const char *_int2bin(unsigned int n, unsigned long len, char *buf); + - (void) _downloadAllData; - (void) _freeAllDataWhenDone; + @end @implementation MCPStreamingResult : MCPResult @@ -159,7 +163,7 @@ - (NSArray *)fetchNextRowAsArray { MYSQL_ROW theRow; - char *theRowData; + char *theRowData, *buf; unsigned long *fieldLengths; NSInteger i, copiedDataLength; NSMutableArray *returnArray; @@ -242,7 +246,12 @@ copiedDataLength += fieldLengths[i] + 1; } } - + + // If the field is of type BIT, then allocate the binary buffer + if (fieldDefinitions[i].type == FIELD_TYPE_BIT) { + buf = malloc(fieldDefinitions[i].length + 1); + } + // If the data hasn't already been detected as NULL - in which case it will have been // set to NSNull - process the data by type if (cellData == nil) { @@ -283,7 +292,12 @@ break; case FIELD_TYPE_BIT: - cellData = (theData != NULL) ? [NSString stringWithFormat:@"%u", theData[0]] : @""; + // Get a binary representation of the data + _int2bin(theData[1], fieldDefinitions[i].length, buf); + + cellData = (theData != NULL) ? [NSString stringWithUTF8String:buf] : @""; + + free(buf); break; case FIELD_TYPE_TINY_BLOB: @@ -414,6 +428,21 @@ @implementation MCPStreamingResult (PrivateAPI) /** + * Provides a binary representation of the supplied integer (n) in the supplied buffer (buf). The resulting + * binary representation will be zero-padded according to the supplied field length (len). + */ +const char *_int2bin(unsigned int n, unsigned long len, char *buf) +{ + for (int i = (len - 1); i >= 0; --i) + { + buf[i] = (n & 1) ? '1' : '0'; + n >>= 1; + } + + buf[len] = '\0'; +} + +/** * Used internally to download results in a background thread */ - (void)_downloadAllData diff --git a/Source/SPCustomQuery.m b/Source/SPCustomQuery.m index ebc4f726..02cd25ff 100644 --- a/Source/SPCustomQuery.m +++ b/Source/SPCustomQuery.m @@ -1671,7 +1671,7 @@ } else if([anObject isEqualToString:[prefs stringForKey:SPNullValue]]) { newObject = @"NULL"; } else if ([[columnDefinition objectForKey:@"typegrouping"] isEqualToString:@"bit"]) { - newObject = ((![[anObject description] length] || [[anObject description] isEqualToString:@"0"])?@"0":@"1"); + newObject = [NSString stringWithFormat:@"b'%@'", ((![[anObject description] length] || [[anObject description] isEqualToString:@"0"]) ? @"0" : [anObject description])]; } else if ([[columnDefinition objectForKey:@"typegrouping"] isEqualToString:@"date"] && [[anObject description] isEqualToString:@"NOW()"]) { newObject = @"NOW()"; @@ -1681,7 +1681,7 @@ } [mySQLConnection queryString: - [NSString stringWithFormat:@"UPDATE %@.%@ SET %@.%@.%@=%@ %@ LIMIT 1", + [NSString stringWithFormat:@"UPDATE %@.%@ SET %@.%@.%@ = %@ %@ LIMIT 1", [[columnDefinition objectForKey:@"db"] backtickQuotedString], [tableForColumn backtickQuotedString], [[columnDefinition objectForKey:@"db"] backtickQuotedString], [tableForColumn backtickQuotedString], [columnName backtickQuotedString], newObject, fieldIDQueryString]]; diff --git a/Source/SPSQLExporter.m b/Source/SPSQLExporter.m index ad16a119..683e3a48 100644 --- a/Source/SPSQLExporter.m +++ b/Source/SPSQLExporter.m @@ -365,11 +365,17 @@ } id object = NSArrayObjectAtIndex(row, t); - + // Add NULL values directly to the output row if ([object isMemberOfClass:[NSNull class]]) { [sqlString appendString:@"NULL"]; } + // If the field is off type BIT, the values need a binary prefix of b'x'. + else if ([[NSArrayObjectAtIndex([tableDetails objectForKey:@"columns"], t) objectForKey:@"type"] isEqualToString:@"BIT"]) { + [sqlString appendString:@"b'"]; + [sqlString appendString:[object description]]; + [sqlString appendString:@"'"]; + } // Add data types directly as hex data else if ([object isKindOfClass:[NSData class]]) { @@ -400,8 +406,7 @@ if ([cellValue length] == 0) { [sqlString appendString:@"''"]; } - else { - // If this is a numeric column type, add the number directly. + else { if ([NSArrayObjectAtIndex(tableColumnNumericStatus, t) boolValue]) { [sqlString appendString:cellValue]; } diff --git a/Source/SPTableContent.m b/Source/SPTableContent.m index 4af8685e..15f4df31 100644 --- a/Source/SPTableContent.m +++ b/Source/SPTableContent.m @@ -2150,7 +2150,7 @@ if ([[rowObject description] isEqualToString:@"CURRENT_TIMESTAMP"]) { [rowValue setString:@"CURRENT_TIMESTAMP"]; } else if ([[NSArrayObjectAtIndex(dataColumns, i) objectForKey:@"typegrouping"] isEqualToString:@"bit"]) { - [rowValue setString:((![[rowObject description] length] || [[rowObject description] isEqualToString:@"0"])?@"0":@"1")]; + [rowValue setString:[NSString stringWithFormat:@"b'%@'", ((![[rowObject description] length] || [[rowObject description] isEqualToString:@"0"]) ? @"0" : [rowObject description])]]; } else if ([[NSArrayObjectAtIndex(dataColumns, i) objectForKey:@"typegrouping"] isEqualToString:@"date"] && [[rowObject description] isEqualToString:@"NOW()"]) { [rowValue setString:@"NOW()"]; @@ -2161,12 +2161,11 @@ } [fieldValues addObject:[NSString stringWithString:rowValue]]; } - + // Use INSERT syntax when creating new rows - no need to do not loaded checking, as all values have been entered if ( isEditingNewRow ) { queryString = [NSString stringWithFormat:@"INSERT INTO %@ (%@) VALUES (%@)", - [selectedTable backtickQuotedString], [[tableDataInstance columnNames] componentsJoinedAndBacktickQuoted], [fieldValues componentsJoinedByString:@","]]; - + [selectedTable backtickQuotedString], [[tableDataInstance columnNames] componentsJoinedAndBacktickQuoted], [fieldValues componentsJoinedByString:@","]]; // Use UPDATE syntax otherwise } else { BOOL firstCellOutput = NO; @@ -2179,7 +2178,7 @@ if (firstCellOutput) [queryString appendString:@", "]; else firstCellOutput = YES; - [queryString appendString:[NSString stringWithFormat:@"%@=%@", + [queryString appendString:[NSString stringWithFormat:@"%@ = %@", [[NSArrayObjectAtIndex(dataColumns, i) objectForKey:@"name"] backtickQuotedString], [fieldValues objectAtIndex:i]]]; } [queryString appendString:[NSString stringWithFormat:@" WHERE %@", [self argumentForRow:-2]]]; @@ -2332,7 +2331,6 @@ id tempValue; NSMutableString *value = [NSMutableString string]; NSMutableString *argument = [NSMutableString string]; - // NSString *columnType; NSArray *columnNames; NSInteger i; @@ -2384,18 +2382,25 @@ tempValue = [tableValues cellDataAtRow:row column:[[[tableDataInstance columnWithName:NSArrayObjectAtIndex(keys, i)] objectForKey:@"datacolumnindex"] integerValue]]; // Otherwise use the oldRow - } else { + } + else { tempValue = [oldRow objectAtIndex:[[[tableDataInstance columnWithName:NSArrayObjectAtIndex(keys, i)] objectForKey:@"datacolumnindex"] integerValue]]; } - if ( [tempValue isNSNull] ) { + if ([tempValue isNSNull]) { [argument appendString:[NSString stringWithFormat:@"%@ IS NULL", [NSArrayObjectAtIndex(keys, i) backtickQuotedString]]]; - } else if ( [tempValue isSPNotLoaded] ) { + } + else if ([tempValue isSPNotLoaded]) { NSLog(@"Exceptional case: SPNotLoaded object found for method “argumentForRow:”!"); return @""; - } else { - - if ( [tempValue isKindOfClass:[NSData class]] ) + } + else { + // If the field is of type BIT then it needs a binary prefix + if ([[[tableDataInstance columnWithName:NSArrayObjectAtIndex(keys, i)] objectForKey:@"type"] isEqualToString:@"BIT"]) { + [value setString:[NSString stringWithFormat:@"b'%@'", [mySQLConnection prepareString:tempValue]]]; + } + // BLOB/TEXT data + else if ([tempValue isKindOfClass:[NSData class]]) [value setString:[NSString stringWithFormat:@"X'%@'", [mySQLConnection prepareBinaryData:tempValue]]]; else [value setString:[NSString stringWithFormat:@"'%@'", [mySQLConnection prepareString:tempValue]]]; @@ -2435,7 +2440,7 @@ { NSInteger i; NSMutableArray *fields = [NSMutableArray array]; - + if (([prefs boolForKey:SPLoadBlobsAsNeeded]) && ([dataColumns count] > 0)) { NSArray *columnNames = [tableDataInstance columnNames]; @@ -2443,7 +2448,7 @@ for (i = 0 ; i < [columnNames count]; i++) { if (![tableDataInstance columnIsBlobOrText:[NSArrayObjectAtIndex(dataColumns, i) objectForKey:@"name"]] ) { - [fields addObject:[NSArrayObjectAtIndex(columnNames, i) backtickQuotedString]]; + [fields addObject:[NSArrayObjectAtIndex(columnNames, i) backtickQuotedString]]; } else { // For blob/text fields, select a null placeholder so the column count is still correct |