aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax <post@wickenrode.com>2015-10-30 01:41:01 +0100
committerMax <post@wickenrode.com>2015-10-30 01:41:01 +0100
commitb2d798ba9282d3acf1a2d65de30849e529d4d255 (patch)
tree3d1efd017e3e6ef85a524b8d30c362ac02885885
parent2b2a177e7adceabadd451c0dca300b30f14aebb2 (diff)
downloadsequelpro-b2d798ba9282d3acf1a2d65de30849e529d4d255.tar.gz
sequelpro-b2d798ba9282d3acf1a2d65de30849e529d4d255.tar.bz2
sequelpro-b2d798ba9282d3acf1a2d65de30849e529d4d255.zip
* Lock connection during disconnect to prevent some race conditions
* Always use the server version name provided by mysql_get_server_info() as that should me more reliable * Use mysql_get_server_version() for version comparisons. Less code, official API and closer to what mysql does
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.m13
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Server Info.m56
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLConnection.h1
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m30
-rw-r--r--Source/SPFieldMapperController.m4
-rw-r--r--Source/SPServerSupport.m13
6 files changed, 48 insertions, 69 deletions
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.m b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.m
index cfbb7183..7940b483 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.m
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.m
@@ -94,15 +94,15 @@
// attempt a single reconnection in the background
if (_elapsedSecondsSinceAbsoluteTime(lastConnectionUsedTime) < 60 * 15) {
[self _reconnectAfterBackgroundConnectionLoss];
-
+ }
// Otherwise set the state to connection lost for automatic reconnect on
// next use.
- } else {
+ else {
state = SPMySQLConnectionLostInBackground;
}
// Return as no further ping action required this cycle.
- goto end;
+ goto end_cleanup;
}
// Otherwise, perform a background ping.
@@ -112,7 +112,7 @@
} else {
keepAlivePingFailures++;
}
-end:
+end_cleanup:
keepAliveThread = nil;
}
@@ -139,6 +139,11 @@ end:
// Set up a query lock
[self _lockConnection];
+ //we might find ourselves at the losing end of a contest with -[self _disconnect]
+ if(!mySQLConnection) {
+ [self _unlockConnection];
+ return NO;
+ }
volatile BOOL keepAliveLastPingSuccess = NO;
keepAliveLastPingBlocked = NO;
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Server Info.m b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Server Info.m
index dd684c78..01410eb5 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Server Info.m
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Server Info.m
@@ -46,54 +46,34 @@
return [NSString stringWithString:serverVariableVersion];
}
-#warning FIXME: There is probably a race condition here with -[self _disconnect]
- if(mySQLConnection) {
- return [self _stringForCString:mysql_get_server_info(mySQLConnection)];
- }
-
return nil;
}
/**
- * Return the server major version or NSNotFound on failure
+ * Return the server major version or 0 on failure
*/
- (NSUInteger)serverMajorVersion
{
- NSString *ver;
- if ((ver = [self serverVersionString]) != nil) {
- NSString *s = [[ver componentsSeparatedByString:@"."] objectAtIndex:0];
- return (NSUInteger)[s integerValue];
- }
-
- return NSNotFound;
+ // 5.5.33 => 50533 / 10'000 => 5.0533 => 5
+ return (serverVersionNumber / 10000);
}
/**
- * Return the server minor version or NSNotFound on failure
+ * Return the server minor version or 0 on failure
*/
- (NSUInteger)serverMinorVersion
{
- NSString *ver;
- if ((ver = [self serverVersionString]) != nil) {
- NSString *s = [[ver componentsSeparatedByString:@"."] objectAtIndex:1];
- return (NSUInteger)[s integerValue];
- }
-
- return NSNotFound;
+ // 5.5.33 => 50533 - (5*10'000) => 533 / 100 => 5.33 => 5
+ return ((serverVersionNumber - [self serverMajorVersion]*10000) / 100);
}
/**
- * Return the server release version or NSNotFound on failure
+ * Return the server release version or 0 on failure
*/
- (NSUInteger)serverReleaseVersion
{
- NSString *ver;
- if ((ver = [self serverVersionString]) != nil) {
- NSString *s = [[ver componentsSeparatedByString:@"."] objectAtIndex:2];
- return (NSUInteger)[[[s componentsSeparatedByString:@"-"] objectAtIndex:0] integerValue];
- }
-
- return NSNotFound;
+ // 5.5.33 => 50533 - (5*10'000 + 5*100) => 33
+ return (serverVersionNumber - ([self serverMajorVersion]*10000 + [self serverMinorVersion]*100));
}
#pragma mark -
@@ -105,23 +85,9 @@
*/
- (BOOL)serverVersionIsGreaterThanOrEqualTo:(NSUInteger)aMajorVersion minorVersion:(NSUInteger)aMinorVersion releaseVersion:(NSUInteger)aReleaseVersion
{
- NSString *ver;
- if (!(ver = [self serverVersionString])) return NO;
-
- NSArray *serverVersionParts = [ver componentsSeparatedByString:@"."];
-
- NSUInteger serverMajorVersion = (NSUInteger)[[serverVersionParts objectAtIndex:0] integerValue];
- if (serverMajorVersion < aMajorVersion) return NO;
- if (serverMajorVersion > aMajorVersion) return YES;
-
- NSUInteger serverMinorVersion = (NSUInteger)[[serverVersionParts objectAtIndex:1] integerValue];
- if (serverMinorVersion < aMinorVersion) return NO;
- if (serverMinorVersion > aMinorVersion) return YES;
+ unsigned long myver = aMajorVersion * 10000 + aMinorVersion * 100 + aReleaseVersion;
- NSString *serverReleasePart = [serverVersionParts objectAtIndex:2];
- NSUInteger serverReleaseVersion = (NSUInteger)[[[serverReleasePart componentsSeparatedByString:@"-"] objectAtIndex:0] integerValue];
- if (serverReleaseVersion < aReleaseVersion) return NO;
- return YES;
+ return (myver >= serverVersionNumber);
}
#pragma mark -
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.h b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.h
index 444e8dff..6a3a1013 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.h
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.h
@@ -99,6 +99,7 @@
// Server details
NSString *serverVariableVersion;
+ unsigned long serverVersionNumber;
// Error state for the last query or connection state
NSUInteger queryErrorID;
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m
index eb1816b5..1ca2f182 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m
@@ -174,6 +174,7 @@ const char *SPMySQLSSLPermissibleCiphers = "DHE-RSA-AES256-SHA:AES256-SHA:DHE-RS
// Ensure the server detail records are initialised
serverVariableVersion = nil;
+ serverVersionNumber = 0;
// Start with a blank error state
queryErrorID = 0;
@@ -475,6 +476,19 @@ asm(".desc ___crashreporter_info__, 0x10");
mysqlConnectionThreadId = mySQLConnection->thread_id;
lastConnectionUsedTime = initialConnectTime;
+ // Copy the server version string to the instance variable
+ if (serverVariableVersion) [serverVariableVersion release], serverVariableVersion = nil;
+ // the mysql_get_server_info() function
+ // * returns the version name that is part of the initial connection handshake.
+ // * Unless the connection failed, it will always return a non-null buffer containing at least a '\0'.
+ // * It will never affect the error variables (since it only returns a struct member)
+ //
+ // At that point (handshake) there is no charset and it's highly unlikely this will ever contain something other than ASCII,
+ // but to be safe, we'll use the Latin1 encoding which won't bail on invalid chars.
+ serverVariableVersion = [[NSString alloc] initWithCString:mysql_get_server_info(mySQLConnection) encoding:NSISOLatin1StringEncoding];
+ // this one can actually change the error state, but only if the server version string is not set (ie. no connection)
+ serverVersionNumber = mysql_get_server_version(mySQLConnection);
+
// Update SSL state
connectedWithSSL = NO;
if (useSSL) connectedWithSSL = (mysql_get_ssl_cipher(mySQLConnection))?YES:NO;
@@ -892,6 +906,7 @@ asm(".desc ___crashreporter_info__, 0x10");
[self _unlockConnection];
[self _cancelKeepAlives];
+ [self _lockConnection];
// Close the underlying MySQL connection if it still appears to be active, and not reading
// or writing. While this may result in a leak of the MySQL object, it prevents crashes
// due to attempts to close a blocked/stuck connection.
@@ -899,17 +914,16 @@ asm(".desc ___crashreporter_info__, 0x10");
mysql_close(mySQLConnection);
}
mySQLConnection = NULL;
+ if (serverVariableVersion) [serverVariableVersion release], serverVariableVersion = nil;
+ serverVersionNumber = 0;
+ if (database) [database release], database = nil;
+ state = SPMySQLDisconnected;
+ [self _unlockConnection];
// If using a connection proxy, disconnect that too
if (proxy) {
[proxy performSelectorOnMainThread:@selector(disconnect) withObject:nil waitUntilDone:YES];
}
-
- // Clear host-specific information
- if (serverVariableVersion) [serverVariableVersion release], serverVariableVersion = nil;
- if (database) [database release], database = nil;
-
- state = SPMySQLDisconnected;
}
/**
@@ -934,10 +948,6 @@ asm(".desc ___crashreporter_info__, 0x10");
[variables setObject:[variableRow objectAtIndex:1] forKey:[variableRow objectAtIndex:0]];
}
- // Copy the server version string to the instance variable
- if (serverVariableVersion) [serverVariableVersion release], serverVariableVersion = nil;
- serverVariableVersion = [[variables objectForKey:@"version"] retain];
-
// Get the connection encoding. Although a specific encoding may have been requested on
// connection, it may be overridden by init_connect commands or connection state changes.
// Default to latin1 for older server versions.
diff --git a/Source/SPFieldMapperController.m b/Source/SPFieldMapperController.m
index 9bef9d03..1a6cfc83 100644
--- a/Source/SPFieldMapperController.m
+++ b/Source/SPFieldMapperController.m
@@ -1043,9 +1043,7 @@ static NSUInteger SPSourceColumnTypeInteger = 1;
NSArray *encodings = [databaseDataInstance getDatabaseCharacterSetEncodings];
NSString *utf8MenuItemTitle = nil;
- if ([encodings count] > 0
- && ([mySQLConnection serverMajorVersion] > 4
- || ([mySQLConnection serverMajorVersion] == 4 && [mySQLConnection serverMinorVersion] >= 1)))
+ if ([encodings count] > 0 && ([mySQLConnection serverVersionIsGreaterThanOrEqualTo:4 minorVersion:1 releaseVersion:0]))
{
[[newTableInfoEncodingPopup menu] addItem:[NSMenuItem separatorItem]];
for (NSDictionary *encoding in encodings) {
diff --git a/Source/SPServerSupport.m b/Source/SPServerSupport.m
index a3b2a1a7..90a47b73 100644
--- a/Source/SPServerSupport.m
+++ b/Source/SPServerSupport.m
@@ -95,10 +95,9 @@
- (id)initWithMajorVersion:(NSInteger)majorVersion minor:(NSInteger)minorVersion release:(NSInteger)releaseVersion
{
if ((self = [super init])) {
- // Might be NSNotFound if unknown. unknown should also lose against "0".
- serverMajorVersion = (majorVersion != NSNotFound)? majorVersion : -1;
- serverMinorVersion = (minorVersion != NSNotFound)? minorVersion : -1;
- serverReleaseVersion = (releaseVersion != NSNotFound)? releaseVersion : -1;
+ serverMajorVersion = majorVersion;
+ serverMinorVersion = minorVersion;
+ serverReleaseVersion = releaseVersion;
// Determine what the server supports
[self evaluate];
@@ -363,9 +362,9 @@
- (void)dealloc
{
// Reset version integers
- serverMajorVersion = -1;
- serverMinorVersion = -1;
- serverReleaseVersion = -1;
+ serverMajorVersion = 0;
+ serverMinorVersion = 0;
+ serverReleaseVersion = 0;
// Invalidate all ivars
[self _invalidate];