//
// $Id$
//
// SPServerSupport.m
// sequel-pro
//
// Created by Stuart Connolly (stuconnolly.com) on September 23, 2010.
// Copyright (c) 2010 Stuart Connolly. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// More info at
#import "SPServerSupport.h"
#import
@interface SPServerSupport ()
- (void)_invalidate;
- (NSComparisonResult)_compareServerMajorVersion:(NSInteger)majorVersionA
minor:(NSInteger)minorVersionA
release:(NSInteger)releaseVersionA
withServerMajorVersion:(NSInteger)majorVersionB
minor:(NSInteger)minorVersionB
release:(NSInteger)releaseVersionB;
@end
@implementation SPServerSupport
@synthesize isMySQL3;
@synthesize isMySQL4;
@synthesize isMySQL5;
@synthesize isMySQL6;
@synthesize supportsInformationSchema;
@synthesize supportsSpatialExtensions;
@synthesize supportsShowCharacterSet;
@synthesize supportsShowCollation;
@synthesize supportsCharacterSetAndCollationVars;
@synthesize supportsPost41CharacterSetHandling;
@synthesize supportsCreateUser;
@synthesize supportsRenameUser;
@synthesize supportsDropUser;
@synthesize supportsFullDropUser;
@synthesize supportsUserMaxVars;
@synthesize supportsShowPrivileges;
@synthesize engineTypeQueryName;
@synthesize supportsInformationSchemaEngines;
@synthesize supportsPre41StorageEngines;
@synthesize supportsBlackholeStorageEngine;
@synthesize supportsArchiveStorageEngine;
@synthesize supportsCSVStorageEngine;
@synthesize supportsTriggers;
@synthesize supportsIndexKeyBlockSize;
@synthesize supportsQuotingEngineTypeInCreateSyntax;
@synthesize supportsFractionalSeconds;
@synthesize serverMajorVersion;
@synthesize serverMinorVersion;
@synthesize serverReleaseVersion;
#pragma mark -
#pragma mark Initialisation
/**
* Creates and returns an instance of SPServerSupport with the supplied version numbers. The caller is
* responsible it's memory.
*
* @param majorVersion The major version number of the server
* @param minorVersion The minor version number of the server
* @param releaseVersiod The release version number of the server
*
* @return The initializes SPServerSupport instance
*/
- (id)initWithMajorVersion:(NSInteger)majorVersion minor:(NSInteger)minorVersion release:(NSInteger)releaseVersion
{
if ((self = [super init])) {
serverMajorVersion = majorVersion;
serverMinorVersion = minorVersion;
serverReleaseVersion = releaseVersion;
// Determine what the server supports
[self evaluate];
}
return self;
}
#pragma mark -
#pragma mark Public API
/**
* Performs the actual version based comparisons to determine what functionaity the server supports. This
* method is called automatically as part of the designated initializer (initWithMajorVersion:major:minor:release:)
* and shouldn't really need to be called again throughout a connection's lifetime.
*
* Note that for the sake of simplicity this method does not try to be smart in that it does not assume
* the presence of functionality based on a previous version check. This allows adding new ivars in the
* future a matter of simply performing a new version comparison.
*
* To add a new metod for determining a server's support for specific functionality, simply add a new
* (read only) ivar with the prefix 'supports' and peform the version checking within this method.
*/
- (void)evaluate
{
// By default, assumme the server doesn't support anything
[self _invalidate];
isMySQL3 = (serverMajorVersion == 3);
isMySQL4 = (serverMajorVersion == 4);
isMySQL5 = (serverMajorVersion == 5);
isMySQL6 = (serverMajorVersion == 6);
// The information schema database wasn't added until MySQL 5
supportsInformationSchema = (serverMajorVersion >= 5);
// Support for spatial extensions wasn't added until MySQL 4.1
supportsSpatialExtensions = [self isEqualToOrGreaterThanMajorVersion:4 minor:1 release:0];
// The SHOW CHARACTER SET statement wasn't added until MySQL 4.1.0
supportsShowCharacterSet = [self isEqualToOrGreaterThanMajorVersion:4 minor:1 release:0];
// The SHOW COLLATION statement wasn't added until MySQL 4.1.0
supportsShowCollation = [self isEqualToOrGreaterThanMajorVersion:4 minor:1 release:0];
// The variables 'character_set_*' and 'collation_*' weren't added until MySQL 4.1.1
supportsCharacterSetAndCollationVars = [self isEqualToOrGreaterThanMajorVersion:4 minor:1 release:1];
// As of MySQL 4.1 encoding support was greatly improved
supportsPost41CharacterSetHandling = [self isEqualToOrGreaterThanMajorVersion:4 minor:1 release:0];
// The table information_schema.engines wasn't added until MySQL 5.1.5
supportsInformationSchemaEngines = [self isEqualToOrGreaterThanMajorVersion:5 minor:1 release:1];
// The CREATE USER statement wasn't added until MySQL 5.0.2
supportsCreateUser = [self isEqualToOrGreaterThanMajorVersion:5 minor:0 release:2];
// The RENAME USER statement wasn't added until MySQL 5.0.2
supportsRenameUser = [self isEqualToOrGreaterThanMajorVersion:5 minor:0 release:2];
// The DROP USER statement wasn't added until MySQL 4.1.1
supportsDropUser = [self isEqualToOrGreaterThanMajorVersion:4 minor:1 release:1];
// Similarly before MySQL 5.0.2 the DROP USER statement only removed users with no privileges
supportsFullDropUser = [self isEqualToOrGreaterThanMajorVersion:5 minor:0 release:2];
// The maximum user variable columns (within mysql.user) weren't added until MySQL 4.0.2
supportsUserMaxVars = [self isEqualToOrGreaterThanMajorVersion:4 minor:0 release:2];
// The SHOW PRIVILEGES statement wasn't added until MySQL 4.1.0
supportsShowPrivileges = [self isEqualToOrGreaterThanMajorVersion:4 minor:1 release:0];
// MySQL 4.0.18+ and 4.1.2+ changed the TYPE option to ENGINE, but 4.x supports both
engineTypeQueryName = [self isEqualToOrGreaterThanMajorVersion:5 minor:0 release:0] ? @"ENGINE" : @"TYPE";
// Before MySQL 4.1 the MEMORY engine was known as HEAP and the ISAM engine was available
supportsPre41StorageEngines = (![self isEqualToOrGreaterThanMajorVersion:4 minor:1 release:0]);
// The BLACKHOLE storage engine wasn't added until MySQL 4.1.11
supportsBlackholeStorageEngine = [self isEqualToOrGreaterThanMajorVersion:4 minor:1 release:11];
// The ARCHIVE storage engine wasn't added until MySQL 4.1.3
supportsArchiveStorageEngine = [self isEqualToOrGreaterThanMajorVersion:4 minor:1 release:3];
// The CSV storage engine wasn't added until MySQL 4.1.4
supportsCSVStorageEngine = [self isEqualToOrGreaterThanMajorVersion:4 minor:1 release:4];
// Support for triggers wasn't added until MySQL 5.0.2
supportsTriggers = [self isEqualToOrGreaterThanMajorVersion:5 minor:0 release:2];
// Support for specifying an index's key block size wasn't added until MySQL 5.1.10
supportsIndexKeyBlockSize = [self isEqualToOrGreaterThanMajorVersion:5 minor:1 release:10];
// MySQL 4.0 doesn't seem to like having the ENGINE/TYPE quoted in a table's create syntax
supportsQuotingEngineTypeInCreateSyntax = [self isEqualToOrGreaterThanMajorVersion:4 minor:1 release:0];
// Fractional second support wasn't added until MySQL 5.6.4
supportsFractionalSeconds = [self isEqualToOrGreaterThanMajorVersion:5 minor:6 release:4];
}
/**
* Convenience method provided as an easy way to determine whether the currently connected server version
* is equal to or greater than the supplied version numbers.
*
* This method should only be used in the case that the build in support ivars don't cover the version/functionality
* checking that is required.
*
* @param majorVersion The major version number of the server
* @param minorVersion The minor version number of the server
* @param releaseVersiod The release version number of the server
*
* @return A BOOL indicating the result of the comparison.
*/
- (BOOL)isEqualToOrGreaterThanMajorVersion:(NSInteger)majorVersion minor:(NSInteger)minorVersion release:(NSInteger)releaseVersion;
{
return ([self _compareServerMajorVersion:serverMajorVersion
minor:serverMinorVersion
release:serverReleaseVersion
withServerMajorVersion:majorVersion
minor:minorVersion
release:releaseVersion] > NSOrderedAscending);
}
/**
* Provides a general description of this object instance. Note that this should only be used for debugging purposes.
*
* @return The string describing the object instance
*/
- (NSString *)description
{
unsigned int i;
NSMutableString *description = [NSMutableString stringWithFormat:@"<%@: Server is MySQL version %d.%d.%d. Supports:\n", [self className], serverMajorVersion, serverMinorVersion, serverReleaseVersion];
Ivar *vars = class_copyIvarList([self class], &i);
for (NSUInteger j = 0; j < i; j++)
{
NSString *varName = [NSString stringWithUTF8String:ivar_getName(vars[j])];
if ([varName hasPrefix:@"supports"]) {
[description appendFormat:@"\t%@ = %@\n", varName, (object_getIvar(self, vars[j])) ? @"YES" : @"NO"];
}
}
[description appendString:@">"];
free(vars);
return description;
}
#pragma mark -
#pragma mark Private API
/**
* Invalidates all knowledge of what we know the server supports by simply reseting all ivars to their
* original state, that is, it doesn't support anything.
*/
- (void)_invalidate
{
isMySQL3 = NO;
isMySQL4 = NO;
isMySQL5 = NO;
isMySQL6 = NO;
supportsInformationSchema = NO;
supportsSpatialExtensions = NO;
supportsShowCharacterSet = NO;
supportsShowCollation = NO;
supportsCharacterSetAndCollationVars = NO;
supportsPost41CharacterSetHandling = NO;
supportsCreateUser = NO;
supportsRenameUser = NO;
supportsDropUser = NO;
supportsFullDropUser = NO;
supportsUserMaxVars = NO;
supportsShowPrivileges = NO;
engineTypeQueryName = @"ENGINE";
supportsInformationSchemaEngines = NO;
supportsPre41StorageEngines = NO;
supportsBlackholeStorageEngine = NO;
supportsArchiveStorageEngine = NO;
supportsCSVStorageEngine = NO;
supportsTriggers = NO;
supportsIndexKeyBlockSize = NO;
supportsQuotingEngineTypeInCreateSyntax = NO;
supportsFractionalSeconds = NO;
}
/**
* Compares the supplied version numbers to determine their order.
*
* Note that this method assumes (when comparing MySQL version numbers) that release verions in the form
* XX are larger than X. For example, version 5.0.18 is greater than version 5.0.8
*
* @param majorVersionA The major version number of server A
* @param minorVersionA The minor version number of server A
* @param releaseVersionA The release version number of server A
* @param majorVersionB The major version number of server B
* @param minorVersionB The minor version number of server B
* @param releaseVersionB The release version number of server B
*
* @return One of NSComparisonResult constants indicating the order of the comparison
*/
- (NSComparisonResult)_compareServerMajorVersion:(NSInteger)majorVersionA
minor:(NSInteger)minorVersionA
release:(NSInteger)releaseVersionA
withServerMajorVersion:(NSInteger)majorVersionB
minor:(NSInteger)minorVersionB
release:(NSInteger)releaseVersionB
{
if (majorVersionA > majorVersionB) return NSOrderedDescending;
if (majorVersionA < majorVersionB) return NSOrderedAscending;
// The major versions are the same so move to checking the minor versions
if (minorVersionA > minorVersionB) return NSOrderedDescending;
if (minorVersionA < minorVersionB) return NSOrderedAscending;
// The minor versions are the same so move to checking the release versions
if (releaseVersionA > releaseVersionB) return NSOrderedDescending;
if (releaseVersionA < releaseVersionB) return NSOrderedAscending;
// Both version numbers are the same
return NSOrderedSame;
}
#pragma mark -
#pragma mark Other
- (void)dealloc
{
// Reset version integers
serverMajorVersion = -1;
serverMinorVersion = -1;
serverReleaseVersion = -1;
// Invalidate all ivars
[self _invalidate];
[super dealloc];
}
@end