From 44cdc2f18931a6d5a7571b2dc485120a73b33b57 Mon Sep 17 00:00:00 2001 From: rowanbeentje Date: Sun, 3 Jan 2010 13:37:54 +0000 Subject: - Ensure all results for server variable requests are returned as strings, to avoid binary-mode result issues with certain versions of MySQL (including 4.1.14). This should address Issue #509. - TableDocument now requests the server version string from MCPConnection, aiding caching --- Frameworks/MCPKit/MCPFoundationKit/MCPConnection.h | 1 + Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m | 33 ++++++++++++++++----- Frameworks/MCPKit/MCPFoundationKit/MCPResult.h | 4 ++- Frameworks/MCPKit/MCPFoundationKit/MCPResult.m | 34 +++++++++++++++------- .../MCPKit/MCPFoundationKit/MCPStreamingResult.m | 4 +-- 5 files changed, 56 insertions(+), 20 deletions(-) (limited to 'Frameworks/MCPKit') diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.h b/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.h index e5de0713..f9e0fa82 100644 --- a/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.h +++ b/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.h @@ -173,6 +173,7 @@ void performThreadedKeepAlive(void *ptr); - (double)timeConnected; // Server versions +- (NSString *)serverVersionString; - (NSInteger)serverMajorVersion; - (NSInteger)serverMinorVersion; - (NSInteger)serverReleaseVersion; diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m b/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m index aa5dc842..9f87c0d1 100644 --- a/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m +++ b/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m @@ -733,6 +733,24 @@ void performThreadedKeepAlive(void *ptr) #pragma mark - #pragma mark Server versions +/** + * Return the server version string, or nil on failure. + */ +- (NSString *)serverVersionString +{ + if (mConnected) { + if (serverVersionString == nil) { + [self _getServerVersionString]; + } + + if (serverVersionString) { + return [NSString stringWithString:serverVersionString]; + } + } + + return nil; +} + /** * rReturn the server major version or -1 on fail */ @@ -1744,6 +1762,7 @@ void performThreadedKeepAlive(void *ptr) NSString *theQuery = [NSString stringWithFormat:@"SHOW TABLES FROM %@ LIKE '%@'", dbName, tablesName]; theResult = [self queryString:theQuery]; } + [theResult setReturnDataAsStrings:YES]; return theResult; } @@ -1773,7 +1792,8 @@ void performThreadedKeepAlive(void *ptr) NSString *theQuery = [NSString stringWithFormat:@"SHOW COLUMNS FROM %@ LIKE '%@'", tableName, fieldsName]; theResult = [self queryString:theQuery]; } - + [theResult setReturnDataAsStrings:YES]; + return theResult; } @@ -1936,16 +1956,12 @@ void performThreadedKeepAlive(void *ptr) NSArray *theRow; id theTZName; NSTimeZone *theTZ; - + + [theSessionTZ setReturnDataAsStrings:YES]; [theSessionTZ dataSeek:1ULL]; theRow = [theSessionTZ fetchRowAsArray]; theTZName = [theRow objectAtIndex:1]; - if ( [theTZName isKindOfClass:[NSData class]] ) { - // MySQL 4.1.14 returns the mysql variables as NSData - theTZName = [self stringWithText:theTZName]; - } - if ([theTZName isEqualToString:@"SYSTEM"]) { [theSessionTZ dataSeek:0ULL]; theRow = [theSessionTZ fetchRowAsArray]; @@ -1963,6 +1979,7 @@ void performThreadedKeepAlive(void *ptr) // By default set the time zone to the local one.. // Try to get the name using the previously available variable: theSessionTZ = [self queryString:@"SHOW VARIABLES LIKE 'timezone'"]; + [theSessionTZ setReturnDataAsStrings:YES]; [theSessionTZ dataSeek:0ULL]; theRow = [theSessionTZ fetchRowAsArray]; theTZName = [theRow objectAtIndex:1]; @@ -2003,6 +2020,7 @@ void performThreadedKeepAlive(void *ptr) if (0 == mysql_query(mConnection, queryString)) { if (mysql_field_count(mConnection) != 0) { MCPResult *r = [[MCPResult alloc] initWithMySQLPtr:mConnection encoding:mEncoding timeZone:mTimeZone]; + [r setReturnDataAsStrings:YES]; NSArray *a = [r fetchRowAsArray]; [r autorelease]; if([a count]) { @@ -2183,6 +2201,7 @@ void performThreadedKeepAlive(void *ptr) { if (mConnected) { MCPResult *theResult = [self queryString:@"SHOW VARIABLES LIKE 'version'"]; + [theResult setReturnDataAsStrings:YES]; if ([theResult numOfRows]) { [theResult dataSeek:0]; diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPResult.h b/Frameworks/MCPKit/MCPFoundationKit/MCPResult.h index 4f0d1f80..ac0217de 100644 --- a/Frameworks/MCPKit/MCPFoundationKit/MCPResult.h +++ b/Frameworks/MCPKit/MCPFoundationKit/MCPResult.h @@ -38,8 +38,9 @@ MYSQL_RES *mResult; /* The MYSQL_RES structure of the C API. */ NSArray *mNames; /* An NSArray holding the name of the columns. */ NSStringEncoding mEncoding; /* The encoding used by MySQL server, to ISO-1 default. */ - NSUInteger mNumOfFields; /* The number of fields in the result. */ + NSUInteger mNumOfFields; /* The number of fields in the result. */ NSTimeZone *mTimeZone; /* The time zone of the connection when the query was made. */ + BOOL mReturnDataAsStrings; /* Whether to return data types as strings */ } // Initialization @@ -70,6 +71,7 @@ - (BOOL)isBlobForKey:(NSString *)key; // Conversion +- (void) setReturnDataAsStrings:(BOOL)alwaysConvertData; - (NSString *)stringWithText:(NSData *)theTextData; - (const char *)cStringFromString:(NSString *)theString; - (NSString *)stringWithCString:(const char *)theCString; diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPResult.m b/Frameworks/MCPKit/MCPFoundationKit/MCPResult.m index d2061fca..98f26b6c 100644 --- a/Frameworks/MCPKit/MCPFoundationKit/MCPResult.m +++ b/Frameworks/MCPKit/MCPFoundationKit/MCPResult.m @@ -243,6 +243,8 @@ const OUR_CHARSET our_charsets60[] = { if ((self = [super init])) { mEncoding = [MCPConnection defaultMySQLEncoding]; + mReturnDataAsStrings = NO; + mTimeZone = nil; if (mResult) { mysql_free_result(mResult); @@ -269,6 +271,7 @@ const OUR_CHARSET our_charsets60[] = if ((self = [super init])) { mEncoding = iEncoding; mTimeZone = [iTimeZone retain]; + mReturnDataAsStrings = NO; if (mResult) { mysql_free_result(mResult); @@ -303,6 +306,7 @@ const OUR_CHARSET our_charsets60[] = if ((self = [super init])) { mEncoding = iEncoding; mTimeZone = [iTimeZone retain]; + mReturnDataAsStrings = NO; if (mResult) { mysql_free_result(mResult); @@ -452,8 +456,9 @@ const OUR_CHARSET our_charsets60[] = case FIELD_TYPE_LONG_BLOB: theCurrentObj = [NSData dataWithBytes:theData length:theLengths[i]]; - // It is TEXT and NOT BLOB - if (!(theField[i].flags & BINARY_FLAG)) { + // If the field is TEXT and NOT BLOB, or if force-return-as-string is + // enabled, return a NSString instead of NSData + if (mReturnDataAsStrings || !(theField[i].flags & BINARY_FLAG)) { theCurrentObj = [self stringWithText:theCurrentObj]; } @@ -988,6 +993,19 @@ const OUR_CHARSET our_charsets60[] = #pragma mark - #pragma mark Conversion +/** + * Set whether the result should return data types as strings. This may be useful + * for queries where the result may be returned in either string or data form, but + * will be converted to string for display and use anyway. + * Note that certain MySQL versions also return data types for strings - eg SHOW + * commands like SHOW CREATE TABLE or SHOW VARIABLES, and this conversion can be + * necessary there. + */ +- (void) setReturnDataAsStrings:(BOOL)alwaysConvertData +{ + mReturnDataAsStrings = alwaysConvertData; +} + /** * Use the string encoding to convert the returned NSData to a string (for a TEXT field). */ @@ -1325,14 +1343,10 @@ const OUR_CHARSET our_charsets60[] = */ - (void) dealloc { - if (mResult) { - mysql_free_result(mResult); - } - - if (mNames) { - [mNames autorelease]; - } - + if (mResult) mysql_free_result(mResult); + if (mNames) [mNames autorelease]; + if (mTimeZone) [mTimeZone release]; + [super dealloc]; } diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m b/Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m index d675cebc..58a8c3a6 100644 --- a/Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m +++ b/Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m @@ -276,8 +276,8 @@ case FIELD_TYPE_MEDIUM_BLOB: case FIELD_TYPE_LONG_BLOB: - // For binary data, return the data - if (fieldDefinitions[i].flags & BINARY_FLAG) { + // For binary data, return the data if force-return-as-string is not enabled + if ((fieldDefinitions[i].flags & BINARY_FLAG) && !mReturnDataAsStrings) { cellData = [NSData dataWithBytes:theData length:fieldLengths[i]]; } else { -- cgit v1.2.3