aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrowanbeentje <rowan@beent.je>2010-08-25 23:58:52 +0000
committerrowanbeentje <rowan@beent.je>2010-08-25 23:58:52 +0000
commitdc9d005f21b3e281294f61d4d8e49d0ad003e8fb (patch)
tree02ac106ff98341c4b87d420c5ec9c9c2f1acb130
parent47b27a6d2b5d3cd7fa7152d2679283e7fba3e82d (diff)
downloadsequelpro-dc9d005f21b3e281294f61d4d8e49d0ad003e8fb.tar.gz
sequelpro-dc9d005f21b3e281294f61d4d8e49d0ad003e8fb.tar.bz2
sequelpro-dc9d005f21b3e281294f61d4d8e49d0ad003e8fb.zip
Encoding changes and improvements, particularly to increase compatibility with extended characters in MySQL identifiers (names of dbs/tables/cols):
- Move encoding queries and control into MCPKit, with newly cleaned-up methods, and switch a number of locations to using the new code. - Use UTF8 connections for many identifier-based queries (selecting and listing databases, tables, stored procs, table information). This fixes selection and creation of table and database names containing extended characters, also fixing exceptions and errors. - Improve UTF8 over Latin1 to correctly set the client character set encoding as well, fixing custom queries and edits; remove custom code in SPTableContent achieving the same thing in a single location. - Fix database encoding detection routines - Update localisable strings
-rw-r--r--Frameworks/MCPKit/MCPFoundationKit/MCPConnection.h30
-rw-r--r--Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m224
-rw-r--r--Resources/English.lproj/DBView.stringsbin96036 -> 97514 bytes
-rw-r--r--Resources/English.lproj/Localizable.stringsbin165498 -> 167192 bytes
-rw-r--r--Resources/English.lproj/Navigator.stringsbin2720 -> 2076 bytes
-rw-r--r--Resources/English.lproj/Preferences.stringsbin45374 -> 50300 bytes
-rw-r--r--Resources/English.lproj/QueryFavoriteManager.stringsbin30014 -> 30020 bytes
-rw-r--r--Source/SPConnectionDelegate.m9
-rw-r--r--Source/SPCopyTable.m6
-rw-r--r--Source/SPCustomQuery.m8
-rw-r--r--Source/SPDataImport.m6
-rw-r--r--Source/SPDatabaseDocument.h4
-rw-r--r--Source/SPDatabaseDocument.m107
-rw-r--r--Source/SPExportController.h4
-rw-r--r--Source/SPExportFileUtilities.m2
-rw-r--r--Source/SPExportInitializer.m10
-rw-r--r--Source/SPExtendedTableInfo.m6
-rw-r--r--Source/SPTableContent.m27
-rw-r--r--Source/SPTableData.m63
-rw-r--r--Source/SPTablesList.m47
-rw-r--r--Source/SPXMLExporterDelegate.m4
21 files changed, 351 insertions, 206 deletions
diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.h b/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.h
index adcecb05..7e60ccb2 100644
--- a/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.h
+++ b/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.h
@@ -51,11 +51,6 @@
/**
*
*/
-- (BOOL)connectionEncodingViaLatin1:(id)connection;
-
-/**
- *
- */
- (NSString *)keychainPasswordForConnection:(id)connection;
/**
@@ -66,11 +61,6 @@
/**
*
*/
-- (NSString *)onReconnectShouldUseEncoding:(id)connection;
-
-/**
- *
- */
- (void)noConnectionAvailable:(id)connection;
/**
@@ -91,11 +81,6 @@
/**
*
*/
-- (NSString *)connectionEncoding;
-
-/**
- *
- */
- (BOOL)navigatorSchemaPathExistsForDatabase:(NSString*)dbname;
/**
@@ -153,7 +138,11 @@
NSString *connectionSocket;
NSInteger maxAllowedPacketSize;
unsigned long connectionThreadId;
-
+
+ NSString *encoding, *previousEncoding;
+ NSStringEncoding *stringEncoding;
+ BOOL encodingUsesLatin1Transport, previousEncodingUsesLatin1Transport;
+
NSInteger currentProxyState;
double lastQueryExecutionTime;
@@ -318,8 +307,13 @@ void performThreadedKeepAlive(void *ptr);
- (NSString *)findSocketPath;
// Encoding
-- (void)setEncoding:(NSStringEncoding)theEncoding;
-- (NSStringEncoding)encoding;
+- (BOOL)setEncoding:(NSString *)theEncoding;
+- (NSString *)encoding;
+- (NSStringEncoding)stringEncoding;
+- (BOOL)setEncodingUsesLatin1Transport:(BOOL)useLatin1;
+- (BOOL)encodingUsesLatin1Transport;
+- (void)storeEncodingForRestoration;
+- (void)restoreStoredEncoding;
// Time zone
- (void)setTimeZone:(NSTimeZone *)iTimeZone;
diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m b/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m
index 8ef0fb37..b619db67 100644
--- a/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m
+++ b/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m
@@ -94,7 +94,11 @@ static BOOL sTruncateLongFieldInLogs = YES;
return nil;
}
- mEncoding = NSISOLatin1StringEncoding;
+ encoding = [[NSString alloc] initWithString:@"latin1"];
+ previousEncoding = nil;
+ stringEncoding = NSISOLatin1StringEncoding;
+ encodingUsesLatin1Transport = NO;
+ previousEncodingUsesLatin1Transport = NO;
mConnectionFlags = kMCPConnectionDefaultOption;
// Anything that performs a mysql_net_read is not thread-safe: mysql queries, pings
@@ -401,7 +405,11 @@ static BOOL sTruncateLongFieldInLogs = YES;
lastKeepAliveTime = 0;
automaticReconnectAttempts = 0;
pingFailureCount = 0;
- mEncoding = [MCPConnection encodingForMySQLEncoding:mysql_character_set_name(mConnection)];
+ const char *mysqlStringEncoding = mysql_character_set_name(mConnection);
+ [encoding release];
+ encoding = [[NSString alloc] initWithUTF8String:mysqlStringEncoding];
+ stringEncoding = [MCPConnection encodingForMySQLEncoding:mysqlStringEncoding];
+ encodingUsesLatin1Transport = NO;
[self setLastErrorMessage:nil];
connectionThreadId = mConnection->thread_id;
[self timeZone]; // Getting the timezone used by the server.
@@ -469,23 +477,15 @@ static BOOL sTruncateLongFieldInLogs = YES;
- (BOOL)reconnect
{
NSAutoreleasePool *reconnectionPool = [[NSAutoreleasePool alloc] init];
- NSString *currentEncoding = nil;
- BOOL currentEncodingUsesLatin1Transport = NO;
+ NSString *currentEncoding = [NSString stringWithString:encoding];
+ BOOL currentEncodingUsesLatin1Transport = encodingUsesLatin1Transport;
NSString *currentDatabase = nil;
- // Store the currently selected database and encoding so they can be re-set if reconnection was successful
+ // Store the currently selected database so it can be re-set if reconnection was successful
if (delegate && [delegate respondsToSelector:@selector(onReconnectShouldSelectDatabase:)] && [delegate onReconnectShouldSelectDatabase:self]) {
currentDatabase = [NSString stringWithString:[delegate onReconnectShouldSelectDatabase:self]];
}
- if (delegate && [delegate respondsToSelector:@selector(onReconnectShouldUseEncoding:)]) {
- currentEncoding = [NSString stringWithString:[delegate onReconnectShouldUseEncoding:self]];
- }
-
- if (delegate && [delegate respondsToSelector:@selector(connectionEncodingViaLatin1:)]) {
- currentEncodingUsesLatin1Transport = [delegate connectionEncodingViaLatin1:self];
- }
-
// Close the connection if it exists.
if (mConnected) {
mysql_close(mConnection);
@@ -579,11 +579,8 @@ static BOOL sTruncateLongFieldInLogs = YES;
}
if (currentEncoding) {
- [self queryString:[NSString stringWithFormat:@"/*!40101 SET NAMES '%@' */", currentEncoding]];
- [self setEncoding:[MCPConnection encodingForMySQLEncoding:[currentEncoding UTF8String]]];
- if (currentEncodingUsesLatin1Transport) {
- [self queryString:@"/*!40101 SET CHARACTER_SET_RESULTS=latin1 */"];
- }
+ [self setEncoding:currentEncoding];
+ [self setEncodingUsesLatin1Transport:currentEncodingUsesLatin1Transport];
}
}
else {
@@ -653,7 +650,6 @@ static BOOL sTruncateLongFieldInLogs = YES;
// Note that a return of "NO" here has already asked the user, so if reconnect fails,
// return failure.
if ([self reconnect]) {
- [self restoreConnectionDetails];
return YES;
}
return NO;
@@ -851,12 +847,8 @@ void performThreadedKeepAlive(void *ptr)
connectionStartTime = mach_absolute_time();
[self fetchMaxAllowedPacket];
- if (delegate && [delegate respondsToSelector:@selector(onReconnectShouldUseEncoding:)]) {
- [self queryString:[NSString stringWithFormat:@"/*!40101 SET NAMES '%@' */", [NSString stringWithString:[delegate onReconnectShouldUseEncoding:self]]]];
- if (delegate && [delegate respondsToSelector:@selector(connectionEncodingViaLatin1:)]) {
- if ([delegate connectionEncodingViaLatin1:self]) [self queryString:@"/*!40101 SET CHARACTER_SET_RESULTS=latin1 */"];
- }
- }
+ [self setEncoding:encoding];
+ [self setEncodingUsesLatin1Transport:encodingUsesLatin1Transport];
}
/**
@@ -1241,7 +1233,11 @@ void performThreadedKeepAlive(void *ptr)
}
mConnected = YES;
- mEncoding = [MCPConnection encodingForMySQLEncoding:mysql_character_set_name(mConnection)];
+ const char *mysqlStringEncoding = mysql_character_set_name(mConnection);
+ [encoding release];
+ encoding = [[NSString alloc] initWithUTF8String:mysqlStringEncoding];
+ stringEncoding = [MCPConnection encodingForMySQLEncoding:mysqlStringEncoding];
+ encodingUsesLatin1Transport = NO;
// Getting the timezone used by the server.
[self timeZone];
@@ -1267,6 +1263,14 @@ void performThreadedKeepAlive(void *ptr)
if (dbName == nil) return NO;
if (mConnected) {
+
+ // Ensure the change is made in UTF8 to avoid encoding problems
+ BOOL changeEncoding = ![[self encoding] isEqualToString:@"utf8"];
+ if (changeEncoding) {
+ [self storeEncodingForRestoration];
+ [self setEncoding:@"utf8"];
+ }
+
const char *theDBName = [self cStringFromString:dbName];
[self lockConnection];
if (0 == mysql_select_db(mConnection, theDBName)) {
@@ -1274,6 +1278,8 @@ void performThreadedKeepAlive(void *ptr)
return YES;
}
[self unlockConnection];
+
+ if (changeEncoding) [self restoreStoredEncoding];
}
[self setLastErrorMessage:nil];
@@ -1391,7 +1397,7 @@ void performThreadedKeepAlive(void *ptr)
*/
- (NSString *)prepareString:(NSString *)theString
{
- NSData *theCData = [theString dataUsingEncoding:mEncoding allowLossyConversion:YES];
+ NSData *theCData = [theString dataUsingEncoding:stringEncoding allowLossyConversion:YES];
unsigned long theLength = [theCData length];
// const char *theCStringBuffer = [self cStringFromString:theString];
// unsigned long theLength = [theString length];
@@ -1407,7 +1413,7 @@ void performThreadedKeepAlive(void *ptr)
// theLength = strlen(theCStringBuffer);
theCEscBuffer = (char *)calloc(sizeof(char),(theLength * 2) + 1);
theEscapedLength = mysql_real_escape_string(mConnection, theCEscBuffer, [theCData bytes], theLength);
- theReturn = [[NSString alloc] initWithData:[NSData dataWithBytes:theCEscBuffer length:theEscapedLength] encoding:mEncoding];
+ theReturn = [[NSString alloc] initWithData:[NSData dataWithBytes:theCEscBuffer length:theEscapedLength] encoding:stringEncoding];
// theReturn = [self stringWithCString:theCEscBuffer];
free(theCEscBuffer);
@@ -1456,7 +1462,7 @@ void performThreadedKeepAlive(void *ptr)
*/
- (MCPResult *)queryString:(NSString *)query
{
- return [self queryString:query usingEncoding:mEncoding streamingResult:MCPStreamingNone];
+ return [self queryString:query usingEncoding:stringEncoding streamingResult:MCPStreamingNone];
}
/**
@@ -1466,7 +1472,7 @@ void performThreadedKeepAlive(void *ptr)
*/
- (MCPStreamingResult *)streamingQueryString:(NSString *)query
{
- return [self queryString:query usingEncoding:mEncoding streamingResult:MCPStreamingFast];
+ return [self queryString:query usingEncoding:stringEncoding streamingResult:MCPStreamingFast];
}
/**
@@ -1478,7 +1484,7 @@ void performThreadedKeepAlive(void *ptr)
*/
- (MCPStreamingResult *)streamingQueryString:(NSString *)query useLowMemoryBlockingStreaming:(BOOL)fullStream
{
- return [self queryString:query usingEncoding:mEncoding streamingResult:(fullStream?MCPStreamingLowMem:MCPStreamingFast)];
+ return [self queryString:query usingEncoding:stringEncoding streamingResult:(fullStream?MCPStreamingLowMem:MCPStreamingFast)];
}
/**
@@ -1603,16 +1609,16 @@ void performThreadedKeepAlive(void *ptr)
// For normal result sets, fetch the results and unlock the connection
if (streamResultType == MCPStreamingNone) {
- theResult = [[MCPResult alloc] initWithMySQLPtr:mConnection encoding:mEncoding timeZone:mTimeZone];
+ theResult = [[MCPResult alloc] initWithMySQLPtr:mConnection encoding:stringEncoding timeZone:mTimeZone];
if (!queryCancelled || !queryCancelUsedReconnect) {
[self unlockConnection];
}
// For streaming result sets, fetch the result pointer and leave the connection locked
} else if (streamResultType == MCPStreamingFast) {
- theResult = [[MCPStreamingResult alloc] initWithMySQLPtr:mConnection encoding:mEncoding timeZone:mTimeZone connection:self withFullStreaming:NO];
+ theResult = [[MCPStreamingResult alloc] initWithMySQLPtr:mConnection encoding:stringEncoding timeZone:mTimeZone connection:self withFullStreaming:NO];
} else if (streamResultType == MCPStreamingLowMem) {
- theResult = [[MCPStreamingResult alloc] initWithMySQLPtr:mConnection encoding:mEncoding timeZone:mTimeZone connection:self withFullStreaming:YES];
+ theResult = [[MCPStreamingResult alloc] initWithMySQLPtr:mConnection encoding:stringEncoding timeZone:mTimeZone connection:self withFullStreaming:YES];
}
// Ensure no problem occurred during the result fetch
@@ -1922,11 +1928,16 @@ void performThreadedKeepAlive(void *ptr)
MYSQL_RES *theResPtr;
if (![self checkConnection]) return [[[MCPResult alloc] init] autorelease];
-
+
+ // Ensure UTF8 - where supported - when getting database list.
+ NSString *currentEncoding = [NSString stringWithString:encoding];
+ BOOL currentEncodingUsesLatin1Transport = encodingUsesLatin1Transport;
+ [self setEncoding:@"utf8"];
+
[self lockConnection];
if ((dbsName == nil) || ([dbsName isEqualToString:@""])) {
if (theResPtr = mysql_list_dbs(mConnection, NULL)) {
- theResult = [[MCPResult alloc] initWithResPtr: theResPtr encoding: mEncoding timeZone:mTimeZone];
+ theResult = [[MCPResult alloc] initWithResPtr: theResPtr encoding:stringEncoding timeZone:mTimeZone];
}
else {
theResult = [[MCPResult alloc] init];
@@ -1936,13 +1947,17 @@ void performThreadedKeepAlive(void *ptr)
const char *theCDBsName = (const char *)[self cStringFromString:dbsName];
if (theResPtr = mysql_list_dbs(mConnection, theCDBsName)) {
- theResult = [[MCPResult alloc] initWithResPtr:theResPtr encoding:mEncoding timeZone:mTimeZone];
+ theResult = [[MCPResult alloc] initWithResPtr:theResPtr encoding:stringEncoding timeZone:mTimeZone];
}
else {
theResult = [[MCPResult alloc] init];
}
}
[self unlockConnection];
+
+ // Restore the connection encoding if necessary
+ [self setEncoding:currentEncoding];
+ [self setEncodingUsesLatin1Transport:currentEncodingUsesLatin1Transport];
if (theResult) {
[theResult autorelease];
@@ -1979,7 +1994,7 @@ void performThreadedKeepAlive(void *ptr)
[self lockConnection];
if ((tablesName == nil) || ([tablesName isEqualToString:@""])) {
if (theResPtr = mysql_list_tables(mConnection, NULL)) {
- theResult = [[MCPResult alloc] initWithResPtr: theResPtr encoding: mEncoding timeZone:mTimeZone];
+ theResult = [[MCPResult alloc] initWithResPtr: theResPtr encoding:stringEncoding timeZone:mTimeZone];
}
else {
theResult = [[MCPResult alloc] init];
@@ -1988,7 +2003,7 @@ void performThreadedKeepAlive(void *ptr)
else {
const char *theCTablesName = (const char *)[self cStringFromString:tablesName];
if (theResPtr = mysql_list_tables(mConnection, theCTablesName)) {
- theResult = [[MCPResult alloc] initWithResPtr: theResPtr encoding: mEncoding timeZone:mTimeZone];
+ theResult = [[MCPResult alloc] initWithResPtr: theResPtr encoding:stringEncoding timeZone:mTimeZone];
}
else {
theResult = [[MCPResult alloc] init];
@@ -2276,7 +2291,7 @@ void performThreadedKeepAlive(void *ptr)
unsigned long queryCStringLength;
// Get the doc encoding due to pref settings etc, defaulting to UTF8
- NSString *docEncoding = [[self delegate] connectionEncoding];
+ NSString *docEncoding = [self encoding];
if (!docEncoding) docEncoding = @"utf8";
NSStringEncoding theConnectionEncoding = [MCPConnection encodingForMySQLEncoding:[self cStringFromString:docEncoding]];
@@ -2559,7 +2574,7 @@ void performThreadedKeepAlive(void *ptr)
if (mConnected && (mConnection != NULL)) {
if (theResPtr = mysql_list_processes(mConnection)) {
- result = [[MCPResult alloc] initWithResPtr:theResPtr encoding:mEncoding timeZone:mTimeZone];
+ result = [[MCPResult alloc] initWithResPtr:theResPtr encoding:stringEncoding timeZone:mTimeZone];
}
else {
result = [[MCPResult alloc] init];
@@ -2619,23 +2634,118 @@ void performThreadedKeepAlive(void *ptr)
#pragma mark Encoding
/**
- * Sets the encoding used by the server for data transfer.
- * Used to make sure the output of the query result is ok even for non-ascii characters
- * The character set (encoding) used by the db is passed to the MCPConnection object upon connection,
- * so most likely the encoding (from -encoding) method is already the proper one.
- * That is to say : It's unlikely you will need to call this method directly, and #{if ever you use it, do it at your own risks}.
+ * Sets the encoding for the database connection.
+ * This sends a "SET NAMES" command to the server, as appropriate, and
+ * also updates the class to decode the returned strings correctly.
+ * If an encoding name unsupported by MySQL is encountered, a FALSE
+ * status will be returned, and errors will be updated.
+ * If an encoding name not supported by this class is encountered, a
+ * warning will be logged to console but the MySQL connection will still
+ * be updated.
+ * This resets any setting to use Latin1 transport for the connection.
*/
-- (void)setEncoding:(NSStringEncoding)theEncoding
+- (BOOL)setEncoding:(NSString *)theEncoding
{
- mEncoding = theEncoding;
+ if ([theEncoding isEqualToString:encoding] && !encodingUsesLatin1Transport) return YES;
+
+ // MySQL < 4.1 will fail
+ if ([self serverMajorVersion] < 4
+ || ([self serverMinorVersion] == 4 && [self serverMinorVersion] < 1))
+ {
+ return NO;
+ }
+
+ // Attempt to set the encoding of the connection, restoring the connection on failure
+ [self queryString:[NSString stringWithFormat:@"SET NAMES %@", [theEncoding tickQuotedString]]];
+ if ([self queryErrored]) {
+ [self queryString:[NSString stringWithFormat:@"SET NAMES %@", [encoding tickQuotedString]]];
+ if (encodingUsesLatin1Transport) [self queryString:@"SET CHARACTER_SET_RESULTS=latin1"];
+ return NO;
+ }
+
+ // The connection set was successful - update stored details
+ [encoding release];
+ encoding = [[NSString alloc] initWithString:theEncoding];
+ stringEncoding = [MCPConnection encodingForMySQLEncoding:[encoding UTF8String]];
+ encodingUsesLatin1Transport = NO;
+ return YES;
}
/**
- * Gets the encoding for the connection
+ * Returns the currently active encoding.
*/
-- (NSStringEncoding)encoding
+- (NSString *)encoding
{
- return mEncoding;
+ return [NSString stringWithString:encoding];
+}
+
+/**
+ * Gets the string encoding for the connection
+ */
+- (NSStringEncoding)stringEncoding
+{
+ return stringEncoding;
+}
+
+/**
+ * Sets whether the connection encoding should be transmitted via Latin1.
+ * This is a method purely for backwards compatibility: old codebases or
+ * applications often believed they stored UTF8 data in UTF8 tables, but
+ * for the purposes of storing and reading the data, the MySQL connecttion
+ * was never changed from the default Latin1. UTF8 data was therefore
+ * altered during transit and stored as UTF8 encoding Latin1 pairs which
+ * together make up extended UTF8 characters. Reading these characters back
+ * over Latin1 makes the data editable in a compatible fashion.
+ */
+- (BOOL)setEncodingUsesLatin1Transport:(BOOL)useLatin1
+{
+ if (encodingUsesLatin1Transport == useLatin1) return YES;
+
+ // If disabling Latin1 transport, restore the connection encoding
+ if (!useLatin1) return [self setEncoding:encoding];
+
+ // Otherwise attempt to set Latin1 transport
+ [self queryString:@"SET CHARACTER_SET_RESULTS=latin1"];
+ if ([self queryErrored]) return NO;
+ [self queryString:@"SET CHARACTER_SET_CLIENT=latin1"];
+ if ([self queryErrored]) {
+ [self setEncoding:encoding];
+ return NO;
+ }
+ encodingUsesLatin1Transport = YES;
+ return YES;
+}
+
+/**
+ * Return whether the current connection is set to use Latin1 tranport.
+ */
+- (BOOL)encodingUsesLatin1Transport
+{
+ return encodingUsesLatin1Transport;
+}
+
+/**
+ * Store a previous encoding setting. This allows easy restoration
+ * later - useful if certain tasks require the encoding to be
+ * temporarily changed.
+ */
+- (void)storeEncodingForRestoration
+{
+ if (previousEncoding) [previousEncoding release];
+ previousEncoding = [[NSString alloc] initWithString:encoding];
+ previousEncodingUsesLatin1Transport = encodingUsesLatin1Transport;
+}
+
+/**
+ * Restore a previously stored encoding setting, if one is stored.
+ * Useful if certain tasks required the encoding to be temporarily changed.
+ */
+- (void)restoreStoredEncoding
+{
+ if (!previousEncoding || !mConnected) return;
+
+ [self setEncoding:previousEncoding];
+ [self setEncodingUsesLatin1Transport:previousEncodingUsesLatin1Transport];
}
#pragma mark -
@@ -2734,7 +2844,7 @@ void performThreadedKeepAlive(void *ptr)
[self lockConnection];
if (0 == mysql_query(mConnection, queryString)) {
if (mysql_field_count(mConnection) != 0) {
- MCPResult *r = [[MCPResult alloc] initWithMySQLPtr:mConnection encoding:mEncoding timeZone:mTimeZone];
+ MCPResult *r = [[MCPResult alloc] initWithMySQLPtr:mConnection encoding:stringEncoding timeZone:mTimeZone];
[r setReturnDataAsStrings:YES];
NSArray *a = [r fetchRowAsArray];
[r autorelease];
@@ -2757,7 +2867,7 @@ void performThreadedKeepAlive(void *ptr)
- (NSInteger)getMaxAllowedPacket
{
MCPResult *r;
- r = [self queryString:@"SELECT @@global.max_allowed_packet" usingEncoding:mEncoding streamingResult:NO];
+ r = [self queryString:@"SELECT @@global.max_allowed_packet" usingEncoding:stringEncoding streamingResult:NO];
if (![[self getLastErrorMessage] isEqualToString:@""]) {
if ([self isConnected]) {
NSString *errorMessage = [NSString stringWithFormat:@"An error occured while retrieving max_allowed_packet size:\n\n%@", [self getLastErrorMessage]];
@@ -2828,7 +2938,7 @@ void performThreadedKeepAlive(void *ptr)
return (const char *)NULL;
}
- theData = [NSMutableData dataWithData:[theString dataUsingEncoding:mEncoding allowLossyConversion:YES]];
+ theData = [NSMutableData dataWithData:[theString dataUsingEncoding:stringEncoding allowLossyConversion:YES]];
[theData increaseLengthBy:1];
return (const char *)[theData bytes];
@@ -2864,7 +2974,7 @@ void performThreadedKeepAlive(void *ptr)
if (theCString == NULL) return @"";
theData = [NSData dataWithBytes:theCString length:(strlen(theCString))];
- theString = [[NSString alloc] initWithData:theData encoding:mEncoding];
+ theString = [[NSString alloc] initWithData:theData encoding:stringEncoding];
if (theString) {
[theString autorelease];
@@ -2922,7 +3032,7 @@ void performThreadedKeepAlive(void *ptr)
if (theTextData == nil) return nil;
- theString = [[NSString alloc] initWithData:theTextData encoding:mEncoding];
+ theString = [[NSString alloc] initWithData:theTextData encoding:stringEncoding];
if (theString) {
[theString autorelease];
@@ -2951,6 +3061,8 @@ void performThreadedKeepAlive(void *ptr)
[connectionProxy disconnect];
}
+ [encoding release];
+ if (previousEncoding) [previousEncoding release];
[keepAliveTimer invalidate];
[keepAliveTimer release];
[NSObject cancelPreviousPerformRequestsWithTarget:self];
diff --git a/Resources/English.lproj/DBView.strings b/Resources/English.lproj/DBView.strings
index a726b3f5..9310758a 100644
--- a/Resources/English.lproj/DBView.strings
+++ b/Resources/English.lproj/DBView.strings
Binary files differ
diff --git a/Resources/English.lproj/Localizable.strings b/Resources/English.lproj/Localizable.strings
index e345185b..62fc3d58 100644
--- a/Resources/English.lproj/Localizable.strings
+++ b/Resources/English.lproj/Localizable.strings
Binary files differ
diff --git a/Resources/English.lproj/Navigator.strings b/Resources/English.lproj/Navigator.strings
index 4ba3c740..d7debae9 100644
--- a/Resources/English.lproj/Navigator.strings
+++ b/Resources/English.lproj/Navigator.strings
Binary files differ
diff --git a/Resources/English.lproj/Preferences.strings b/Resources/English.lproj/Preferences.strings
index 90c165a3..97922977 100644
--- a/Resources/English.lproj/Preferences.strings
+++ b/Resources/English.lproj/Preferences.strings
Binary files differ
diff --git a/Resources/English.lproj/QueryFavoriteManager.strings b/Resources/English.lproj/QueryFavoriteManager.strings
index aa062ee2..f34470a9 100644
--- a/Resources/English.lproj/QueryFavoriteManager.strings
+++ b/Resources/English.lproj/QueryFavoriteManager.strings
Binary files differ
diff --git a/Source/SPConnectionDelegate.m b/Source/SPConnectionDelegate.m
index 5231c996..b1e586f1 100644
--- a/Source/SPConnectionDelegate.m
+++ b/Source/SPConnectionDelegate.m
@@ -70,15 +70,6 @@
}
/**
- * Invoked when the framework is in the process of reconnecting to the server and needs to know
- * what encoding to use for the connection.
- */
-- (NSString *)onReconnectShouldUseEncoding:(id)connection
-{
- return _encoding;
-}
-
-/**
* Invoked when the current connection needs a password from the Keychain.
*/
- (NSString *)keychainPasswordForConnection:(MCPConnection *)connection
diff --git a/Source/SPCopyTable.m b/Source/SPCopyTable.m
index b1b663a4..db8ce49d 100644
--- a/Source/SPCopyTable.m
+++ b/Source/SPCopyTable.m
@@ -295,7 +295,7 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003;
else if ([cellData isSPNotLoaded])
[result appendFormat:@"%@\t", NSLocalizedString(@"(not loaded)", @"value shown for hidden blob and text fields")];
else if ([cellData isKindOfClass:[NSData class]]) {
- NSString *displayString = [[NSString alloc] initWithData:cellData encoding:connectionEncoding];
+ NSString *displayString = [[NSString alloc] initWithData:cellData encoding:[mySQLConnection stringEncoding]];
if (!displayString) displayString = [[NSString alloc] initWithData:cellData encoding:NSASCIIStringEncoding];
if (displayString) {
[result appendFormat:@"%@\t", displayString];
@@ -520,7 +520,7 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003;
NSUInteger rowIndex = [selectedRows firstIndex];
NSString *nullString = [prefs objectForKey:SPNullValue];
Class nsDataClass = [NSData class];
- NSStringEncoding connectionEncoding = [mySQLConnection encoding];
+ NSStringEncoding connectionEncoding = [mySQLConnection stringEncoding];
while ( rowIndex != NSNotFound )
{
for ( c = 0; c < numColumns; c++) {
@@ -681,7 +681,7 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003;
// Otherwise, ensure the cell is represented as a short string
if ([contentString isKindOfClass:[NSData class]]) {
- contentString = [contentString shortStringRepresentationUsingEncoding:[mySQLConnection encoding]];
+ contentString = [contentString shortStringRepresentationUsingEncoding:[mySQLConnection stringEncoding]];
} else if ([contentString length] > 500) {
contentString = [contentString substringToIndex:500];
}
diff --git a/Source/SPCustomQuery.m b/Source/SPCustomQuery.m
index 82b40465..adb806ad 100644
--- a/Source/SPCustomQuery.m
+++ b/Source/SPCustomQuery.m
@@ -1792,7 +1792,7 @@
}
if ([theValue isKindOfClass:[NSData class]])
- return [theValue shortStringRepresentationUsingEncoding:[mySQLConnection encoding]];
+ return [theValue shortStringRepresentationUsingEncoding:[mySQLConnection stringEncoding]];
if ([theValue isNSNull])
return [prefs objectForKey:SPNullValue];
@@ -2262,9 +2262,9 @@
id editData = [[fieldEditor editWithObject:originalData
fieldName:[columnDefinition objectForKey:@"name"]
- usingEncoding:[mySQLConnection encoding]
- isObjectBlob:isBlob
- isEditable:isFieldEditable
+ usingEncoding:[mySQLConnection stringEncoding]
+ isObjectBlob:isBlob
+ isEditable:isFieldEditable
withWindow:[tableDocumentInstance parentWindow]] retain];
if ( editData )
diff --git a/Source/SPDataImport.m b/Source/SPDataImport.m
index ac1eadc0..98129f19 100644
--- a/Source/SPDataImport.m
+++ b/Source/SPDataImport.m
@@ -233,7 +233,7 @@
if ([[[importFormatPopup selectedItem] title] isEqualToString:@"SQL"])
encoding = NSUTF8StringEncoding;
else
- encoding = [MCPConnection encodingForMySQLEncoding:[[tableDocumentInstance connectionEncoding] UTF8String]];
+ encoding = [mySQLConnection stringEncoding];
if(![[[NSPasteboard generalPasteboard] stringForType:NSStringPboardType] writeToFile:importFileName atomically:NO encoding:encoding error:nil]) {
NSBeep();
@@ -406,7 +406,7 @@
sqlEncoding = [fileEncodingDetector encoding];
[fileEncodingDetector release];
if ([MCPConnection mySQLEncodingForStringEncoding:sqlEncoding]) {
- connectionEncodingToRestore = [tableDocumentInstance connectionEncoding];
+ connectionEncodingToRestore = [mySQLConnection encoding];
[mySQLConnection queryString:[NSString stringWithFormat:@"SET NAMES '%@'", [MCPConnection mySQLEncodingForStringEncoding:sqlEncoding]]];
}
}
@@ -673,7 +673,7 @@
BOOL allDataRead = NO;
BOOL insertBaseStringHasEntries;
- NSStringEncoding csvEncoding = [MCPConnection encodingForMySQLEncoding:[[tableDocumentInstance connectionEncoding] UTF8String]];
+ NSStringEncoding csvEncoding = [mySQLConnection stringEncoding];
fieldMappingArray = nil;
fieldMappingGlobalValueArray = nil;
diff --git a/Source/SPDatabaseDocument.h b/Source/SPDatabaseDocument.h
index 28ee97ad..07c3f7bb 100644
--- a/Source/SPDatabaseDocument.h
+++ b/Source/SPDatabaseDocument.h
@@ -139,8 +139,6 @@
NSMenu *selectEncodingMenu;
BOOL _supportsEncoding;
- NSString *_encoding;
- BOOL _encodingViaLatin1;
BOOL _isConnected;
NSInteger _isWorkingLevel;
BOOL _mainNibLoaded;
@@ -238,8 +236,6 @@
// Encoding methods
- (void)setConnectionEncoding:(NSString *)mysqlEncoding reloadingViews:(BOOL)reloadViews;
- (NSString *)databaseEncoding;
-- (NSString *)connectionEncoding;
-- (BOOL)connectionEncodingViaLatin1:(id)connection;
- (IBAction)chooseEncoding:(id)sender;
- (BOOL)supportsEncoding;
- (void)updateEncodingMenuWithSelectedEncoding:(NSNumber *)encodingTag;
diff --git a/Source/SPDatabaseDocument.m b/Source/SPDatabaseDocument.m
index e99bc702..00831c85 100644
--- a/Source/SPDatabaseDocument.m
+++ b/Source/SPDatabaseDocument.m
@@ -83,7 +83,6 @@
if ((self = [super init])) {
_mainNibLoaded = NO;
- _encoding = [[NSString alloc] initWithString:@"utf8"];
_isConnected = NO;
_isWorkingLevel = 0;
_isSavedInBundle = NO;
@@ -552,7 +551,7 @@
[mainToolbar setVisible:[[spfSession objectForKey:@"isToolbarVisible"] boolValue]];
// Reset database view encoding if differs from default
- if([spfSession objectForKey:@"connectionEncoding"] && ![[self connectionEncoding] isEqualToString:[spfSession objectForKey:@"connectionEncoding"]])
+ if([spfSession objectForKey:@"connectionEncoding"] && ![[mySQLConnection encoding] isEqualToString:[spfSession objectForKey:@"connectionEncoding"]])
[self setConnectionEncoding:[spfSession objectForKey:@"connectionEncoding"] reloadingViews:YES];
if(isSelectedTableDefined) {
@@ -658,14 +657,6 @@
// ...but hide the icon while the document is temporary
if ([self isUntitled]) [[parentWindow standardWindowButton:NSWindowDocumentIconButton] setImage:nil];
- // Set the connection encoding
- NSNumber *encodingType = [prefs objectForKey:SPDefaultEncoding];
- if ( [encodingType intValue] == SPEncodingAutodetect ) {
- [self setConnectionEncoding:[self databaseEncoding] reloadingViews:NO];
- } else {
- [self setConnectionEncoding:[self mysqlEncodingFromEncodingTag:encodingType] reloadingViews:NO];
- }
-
// Get the mysql version
mySQLVersion = [[NSString alloc] initWithString:[mySQLConnection serverVersionString]];
@@ -676,12 +667,24 @@
[spHistoryControllerInstance updateHistoryEntries];
}
+ // Ensure the connection encoding is set to utf8 for database/table name retrieval
+ [mySQLConnection setEncoding:@"utf8"];
+
// Update the database list
[self setDatabases:self];
[chooseDatabaseButton setEnabled:!_isWorkingLevel];
- // For each of the main controllers, assign the current connection
+ // Set the connection on the tables list instance - this updates the table list while the connection
+ // is still UTF8
[tablesListInstance setConnection:mySQLConnection];
+
+ // Set the connection encoding if necessary
+ NSNumber *encodingType = [prefs objectForKey:SPDefaultEncoding];
+ if ( [encodingType intValue] != SPEncodingAutodetect ) {
+ [self setConnectionEncoding:[self mysqlEncodingFromEncodingTag:encodingType] reloadingViews:NO];
+ }
+
+ // For each of the main controllers, assign the current connection
[tableSourceInstance setConnection:mySQLConnection];
[tableContentInstance setConnection:mySQLConnection];
[tableRelationsInstance setConnection:mySQLConnection];
@@ -692,9 +695,8 @@
[tableDataInstance setConnection:mySQLConnection];
[extendedTableInfoInstance setConnection:mySQLConnection];
[databaseDataInstance setConnection:mySQLConnection];
-// userManagerInstance.mySqlConnection = mySQLConnection;
- // Set the cutom query editor's MySQL version
+ // Set the custom query editor's MySQL version
[customQueryInstance setMySQLversion:mySQLVersion];
[self updateWindowTitle:self];
@@ -1561,41 +1563,32 @@
*/
- (void)setConnectionEncoding:(NSString *)mysqlEncoding reloadingViews:(BOOL)reloadViews
{
- _encodingViaLatin1 = NO;
+ BOOL useLatin1Transport = NO;
// Special-case UTF-8 over latin 1 to allow viewing/editing of mangled data.
if ([mysqlEncoding isEqualToString:@"utf8-"]) {
- _encodingViaLatin1 = YES;
+ useLatin1Transport = YES;
mysqlEncoding = @"utf8";
}
- // set encoding of connection and client
- [mySQLConnection queryString:[NSString stringWithFormat:@"SET NAMES '%@'", mysqlEncoding]];
-
- if (![mySQLConnection queryErrored]) {
- if (_encodingViaLatin1)
- [mySQLConnection queryString:@"SET CHARACTER_SET_RESULTS=latin1"];
- [mySQLConnection setEncoding:[MCPConnection encodingForMySQLEncoding:[mysqlEncoding UTF8String]]];
- [_encoding release];
- _encoding = [[NSString alloc] initWithString:mysqlEncoding];
- } else {
- [mySQLConnection queryString:[NSString stringWithFormat:@"SET NAMES '%@'", [self databaseEncoding]]];
- _encodingViaLatin1 = NO;
- if ([mySQLConnection queryErrored]) {
- NSLog(@"Error: could not set encoding to %@ nor fall back to database encoding on MySQL %@", mysqlEncoding, [self mySQLVersion]);
- return;
- }
+ // Set the connection encoding
+ if (![mySQLConnection setEncoding:mysqlEncoding]) {
+ NSLog(@"Error: could not set encoding to %@ nor fall back to database encoding on MySQL %@", mysqlEncoding, [self mySQLVersion]);
+ return;
}
+ [mySQLConnection setEncodingUsesLatin1Transport:useLatin1Transport];
- // update the selected menu item
- if (_encodingViaLatin1) {
+ // Update the selected menu item
+ if (useLatin1Transport) {
[self updateEncodingMenuWithSelectedEncoding:[self encodingTagFromMySQLEncoding:[NSString stringWithFormat:@"%@-", mysqlEncoding]]];
} else {
[self updateEncodingMenuWithSelectedEncoding:[self encodingTagFromMySQLEncoding:mysqlEncoding]];
}
+ // Update the stored connection encoding to prevent switches
+ [mySQLConnection storeEncodingForRestoration];
+
// Reload stuff as appropriate
- [tableDataInstance resetAllData];
if (reloadViews) {
if ([tablesListInstance structureLoaded]) [tableSourceInstance reloadTable:self];
if ([tablesListInstance contentLoaded]) [tableContentInstance reloadTable:self];
@@ -1604,23 +1597,6 @@
}
/**
- * returns the current mysql encoding for this object
- */
-- (NSString *)connectionEncoding
-{
- return _encoding;
-}
-
-/**
- * Returns whether the current encoding should display results via Latin1 transport for backwards compatibility.
- * This is a delegate method of MCPKit's MCPConnection class.
- */
-- (BOOL)connectionEncodingViaLatin1:(id)connection
-{
- return _encodingViaLatin1;
-}
-
-/**
* updates the currently selected item in the encoding menu
*
* @param NSString *encoding - the title of the menu item which will be selected
@@ -1707,26 +1683,29 @@
}
/**
- * Detect and return the database connection encoding.
- * TODO: See http://code.google.com/p/sequel-pro/issues/detail?id=134 - some question over why this [historically] uses _connection not _database...
+ * Detect and return the database encoding.
+ * Falls back to Latin1.
*/
- (NSString *)databaseEncoding
{
MCPResult *charSetResult;
- NSString *mysqlEncoding;
+ NSString *mysqlEncoding = nil;
- // MySQL > 4.0
- charSetResult = [mySQLConnection queryString:@"SHOW VARIABLES LIKE 'character_set_connection'"];
- [charSetResult setReturnDataAsStrings:YES];
- mysqlEncoding = [[charSetResult fetchRowAsDictionary] objectForKey:@"Value"];
- _supportsEncoding = (mysqlEncoding != nil);
+ // MySQL >= 4.1
+ if ([mySQLConnection serverMajorVersion] > 4
+ || ([mySQLConnection serverMajorVersion] == 4 && [mySQLConnection serverMinorVersion] >= 1))
+ {
+ charSetResult = [mySQLConnection queryString:@"SHOW VARIABLES LIKE 'character_set_database'"];
+ [charSetResult setReturnDataAsStrings:YES];
+ mysqlEncoding = [[charSetResult fetchRowAsDictionary] objectForKey:@"Value"];
+ _supportsEncoding = (mysqlEncoding != nil);
// mysql 4.0 or older -> only default character set possible, cannot choose others using "set names xy"
- if ( !mysqlEncoding ) {
+ } else {
mysqlEncoding = [[[mySQLConnection queryString:@"SHOW VARIABLES LIKE 'character_set'"] fetchRowAsDictionary] objectForKey:@"Value"];
}
- // older version? -> set encoding to mysql default encoding latin1
+ // Fallback or older version? -> set encoding to mysql default encoding latin1
if ( !mysqlEncoding ) {
NSLog(@"Error: no character encoding found, mysql version is %@", [self mySQLVersion]);
mysqlEncoding = @"latin1";
@@ -3380,7 +3359,7 @@
[session setObject:aString forKey:@"view"];
[session setObject:[NSNumber numberWithBool:[[parentWindow toolbar] isVisible]] forKey:@"isToolbarVisible"];
- [session setObject:[self connectionEncoding] forKey:@"connectionEncoding"];
+ [session setObject:[mySQLConnection encoding] forKey:@"connectionEncoding"];
[session setObject:[NSNumber numberWithBool:[tableContentInstance sortColumnIsAscending]] forKey:@"contentSortColIsAsc"];
[session setObject:[NSNumber numberWithInteger:[tableContentInstance pageNumber]] forKey:@"contentPageNumber"];
@@ -4675,7 +4654,6 @@
for (id retainedObject in nibObjectsToRelease) [retainedObject release];
[nibObjectsToRelease release];
- [_encoding release];
[allDatabases release];
[allSystemDatabases release];
[printWebView release];
@@ -4773,6 +4751,9 @@
SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, parentWindow, self, nil, nil, NSLocalizedString(@"Database must have a name.", @"message of panel when no db name is given"));
return;
}
+
+ // As we're amending identifiers, ensure UTF8
+ if (![[mySQLConnection encoding] isEqualToString:@"utf8"]) [mySQLConnection setEncoding:@"utf8"];
NSString *createStatement = [NSString stringWithFormat:@"CREATE DATABASE %@", [[databaseNameField stringValue] backtickQuotedString]];
diff --git a/Source/SPExportController.h b/Source/SPExportController.h
index c5dade4a..befde1b9 100644
--- a/Source/SPExportController.h
+++ b/Source/SPExportController.h
@@ -198,12 +198,12 @@
* User defaults
*/
NSUserDefaults *prefs;
-
+
/**
* Previous connection encoding
*/
NSString *sqlPreviousConnectionEncoding;
-
+
/**
* Previous connection encoding was via Latin1
*/
diff --git a/Source/SPExportFileUtilities.m b/Source/SPExportFileUtilities.m
index 74e992e4..23eb7666 100644
--- a/Source/SPExportFileUtilities.m
+++ b/Source/SPExportFileUtilities.m
@@ -65,7 +65,7 @@
NSLocalizedString(@"Table", @"csv export table heading"),
[[tables objectAtIndex:0] objectAtIndex:0],
lineEnding,
- lineEnding] dataUsingEncoding:[connection encoding]]];
+ lineEnding] dataUsingEncoding:[connection stringEncoding]]];
}
/**
diff --git a/Source/SPExportInitializer.m b/Source/SPExportInitializer.m
index cc9aa16e..a34f729b 100644
--- a/Source/SPExportInitializer.m
+++ b/Source/SPExportInitializer.m
@@ -269,8 +269,8 @@
[sqlExporter setSqlInsertDivider:[exportSQLInsertDividerPopUpButton indexOfSelectedItem]];
// Cache the current connection encoding then change it to UTF-8 to allow SQL dumps to work
- sqlPreviousConnectionEncoding = [[NSString alloc] initWithString:[tableDocumentInstance connectionEncoding]];
- sqlPreviousConnectionEncodingViaLatin1 = [tableDocumentInstance connectionEncodingViaLatin1:nil];
+ sqlPreviousConnectionEncoding = [[NSString alloc] initWithString:[connection encoding]];
+ sqlPreviousConnectionEncodingViaLatin1 = [connection encodingUsesLatin1Transport];
[tableDocumentInstance setConnectionEncoding:@"utf8" reloadingViews:NO];
@@ -354,8 +354,8 @@
[dotExporter setDotDatabaseVersion:[tableDocumentInstance mySQLVersion]];
// Cache the current connection encoding then change it to UTF-8 to allow SQL dumps to work
- sqlPreviousConnectionEncoding = [[NSString alloc] initWithString:[tableDocumentInstance connectionEncoding]];
- sqlPreviousConnectionEncodingViaLatin1 = [tableDocumentInstance connectionEncodingViaLatin1:nil];
+ sqlPreviousConnectionEncoding = [[NSString alloc] initWithString:[connection encoding]];
+ sqlPreviousConnectionEncodingViaLatin1 = [connection encodingUsesLatin1Transport];
[tableDocumentInstance setConnectionEncoding:@"utf8" reloadingViews:NO];
@@ -386,7 +386,7 @@
for (SPExporter *exporter in exporters)
{
[exporter setConnection:connection];
- [exporter setExportOutputEncoding:[connection encoding]];
+ [exporter setExportOutputEncoding:[connection stringEncoding]];
[exporter setExportMaxProgress:(NSInteger)[exportProgressIndicator bounds].size.width];
[exporter setExportUsingLowMemoryBlockingStreaming:[exportProcessLowMemoryButton state]];
[exporter setExportOutputCompressionFormat:[exportOutputCompressionFormatPopupButton indexOfSelectedItem]];
diff --git a/Source/SPExtendedTableInfo.m b/Source/SPExtendedTableInfo.m
index aac89bb9..f9e0bdb8 100644
--- a/Source/SPExtendedTableInfo.m
+++ b/Source/SPExtendedTableInfo.m
@@ -348,9 +348,11 @@
[tableSizeFree setStringValue:[self _formatValueWithKey:@"Data_free" inDictionary:statusFields]];
// Set comments
+ NSString *commentText = [statusFields objectForKey:@"Comment"];
+ if (!commentText) commentText = @"";
[tableCommentsTextView setEditable:YES];
- [tableCommentsTextView shouldChangeTextInRange:NSMakeRange(0, [[tableCommentsTextView string] length]) replacementString:[statusFields objectForKey:@"Comment"]];
- [tableCommentsTextView setString:[statusFields objectForKey:@"Comment"]];
+ [tableCommentsTextView shouldChangeTextInRange:NSMakeRange(0, [[tableCommentsTextView string] length]) replacementString:commentText];
+ [tableCommentsTextView setString:commentText];
[tableCommentsTextView didChangeText];
[tableCommentsTextView setEditable:enableInteraction];
diff --git a/Source/SPTableContent.m b/Source/SPTableContent.m
index 86a960e5..14150607 100644
--- a/Source/SPTableContent.m
+++ b/Source/SPTableContent.m
@@ -2342,24 +2342,7 @@
[queryString appendFormat:@" WHERE %@", [self argumentForRow:-2]];
}
- // If UTF-8 via Latin1 view encoding is set convert the queryString into Latin1 and
- // set the MySQL connection to Latin1 before executing this query to allow editing.
- // After executing reset all.
- if([tableDocumentInstance connectionEncodingViaLatin1:mySQLConnection]) {
-
- NSStringEncoding currentEncoding = [mySQLConnection encoding];
- NSString *latin1String = [[NSString alloc] initWithCString:[queryString UTF8String] encoding:NSISOLatin1StringEncoding];
- [mySQLConnection setEncoding:NSISOLatin1StringEncoding];
- [mySQLConnection queryString:@"SET NAMES 'latin1'"];
- [mySQLConnection queryString:latin1String];
- [mySQLConnection setEncoding:currentEncoding];
- [mySQLConnection queryString:@"SET NAMES 'utf8'"];
- [mySQLConnection queryString:@"SET CHARACTER_SET_RESULTS=latin1"];
- [latin1String release];
-
- } else {
- [mySQLConnection queryString:queryString];
- }
+ [mySQLConnection queryString:queryString];
[fieldValues release];
[[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance];
@@ -3072,7 +3055,7 @@
return [prefs objectForKey:SPNullValue];
if ([theValue isKindOfClass:[NSData class]])
- return [theValue shortStringRepresentationUsingEncoding:[mySQLConnection encoding]];
+ return [theValue shortStringRepresentationUsingEncoding:[mySQLConnection stringEncoding]];
if ([theValue isSPNotLoaded])
return NSLocalizedString(@"(not loaded)", @"value shown for hidden blob and text fields");
@@ -3534,9 +3517,9 @@
id editData = [[fieldEditor editWithObject:cellValue
fieldName:[[aTableColumn headerCell] stringValue]
- usingEncoding:[mySQLConnection encoding]
- isObjectBlob:isBlob
- isEditable:isFieldEditable
+ usingEncoding:[mySQLConnection stringEncoding]
+ isObjectBlob:isBlob
+ isEditable:isFieldEditable
withWindow:[tableDocumentInstance parentWindow]] retain];
if (editData) {
diff --git a/Source/SPTableData.m b/Source/SPTableData.m
index 8ec18cae..a6a5819a 100644
--- a/Source/SPTableData.m
+++ b/Source/SPTableData.m
@@ -337,6 +337,7 @@
NSString *encodingString = nil;
NSUInteger i, stringStart;
unichar quoteCharacter;
+ BOOL changeEncoding = ![[mySQLConnection encoding] isEqualToString:@"utf8"];
[columns removeAllObjects];
[columnNames removeAllObjects];
@@ -345,6 +346,12 @@
// Catch unselected tables and return nil
if ([tableName isEqualToString:@""] || !tableName) return nil;
+ // Ensure the encoding is set to UTF8
+ if (changeEncoding) {
+ [mySQLConnection storeEncodingForRestoration];
+ [mySQLConnection setEncoding:@"utf8"];
+ }
+
// Retrieve the CREATE TABLE syntax for the table
MCPResult *theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW CREATE TABLE %@", [tableName backtickQuotedString]]];
[theResult setReturnDataAsStrings:YES];
@@ -361,6 +368,7 @@
[[tableListInstance valueForKeyPath:@"tablesListView"] deselectAll:nil];
[tableListInstance updateTables:self];
}
+ if (changeEncoding) [mySQLConnection restoreStoredEncoding];
}
return nil;
@@ -384,6 +392,7 @@
informativeTextWithFormat:NSLocalizedString(@"The creation syntax could not be retrieved due to a permissions error.\n\nPlease check your user permissions with an administrator.", @"Create syntax permission denied detail")]
beginSheetModalForWindow:[NSApp mainWindow]
modalDelegate:self didEndSelector:NULL contextInfo:NULL];
+ if (changeEncoding) [mySQLConnection restoreStoredEncoding];
return nil;
}
@@ -637,6 +646,8 @@
[encodingString release];
[tableColumns release];
+ if (changeEncoding) [mySQLConnection restoreStoredEncoding];
+
return tableData;
}
@@ -689,10 +700,17 @@
NSDictionary *resultRow;
NSMutableDictionary *tableColumn, *viewData;
NSUInteger i;
+ BOOL changeEncoding = ![[mySQLConnection encoding] isEqualToString:@"utf8"];
// Catch unselected views and return nil
if ([viewName isEqualToString:@""] || !viewName) return nil;
+ // Ensure that queries are made in UTF8
+ if (changeEncoding) {
+ [mySQLConnection storeEncodingForRestoration];
+ [mySQLConnection setEncoding:@"utf8"];
+ }
+
// Retrieve the CREATE TABLE syntax for the table
MCPResult *theResult = [mySQLConnection queryString: [NSString stringWithFormat: @"SHOW CREATE TABLE %@",
[viewName backtickQuotedString]
@@ -706,6 +724,7 @@
nil, nil, [NSApp mainWindow], self, nil, nil,
[NSString stringWithFormat:NSLocalizedString(@"An error occurred while retrieving information.\nMySQL said: %@", @"message of panel when retrieving information failed"),
[mySQLConnection getLastErrorMessage]]);
+ if (changeEncoding) [mySQLConnection restoreStoredEncoding];
}
return nil;
}
@@ -722,6 +741,7 @@
informativeTextWithFormat:NSLocalizedString(@"The creation syntax could not be retrieved due to a permissions error.\n\nPlease check your user permissions with an administrator.", @"Create syntax permission denied detail")]
beginSheetModalForWindow:[NSApp mainWindow]
modalDelegate:self didEndSelector:NULL contextInfo:NULL];
+ if (changeEncoding) [mySQLConnection restoreStoredEncoding];
return nil;
}
@@ -738,6 +758,7 @@
nil, nil, [NSApp mainWindow], self, nil, nil,
[NSString stringWithFormat:NSLocalizedString(@"An error occurred while retrieving information.\nMySQL said: %@", @"message of panel when retrieving information failed"),
[mySQLConnection getLastErrorMessage]]);
+ if (changeEncoding) [mySQLConnection restoreStoredEncoding];
}
return nil;
}
@@ -787,6 +808,8 @@
[tableColumns release];
+ if (changeEncoding) [mySQLConnection restoreStoredEncoding];
+
return viewData;
}
@@ -797,6 +820,7 @@
*/
- (BOOL)updateStatusInformationForCurrentTable
{
+ BOOL changeEncoding = ![[mySQLConnection encoding] isEqualToString:@"utf8"];
// Catch unselected tables and return false
if ([[tableListInstance tableName] isEqualToString:@""] || ![tableListInstance tableName])
@@ -809,6 +833,12 @@
return TRUE;
}
+ // Ensure queries are run as UTF8
+ if (changeEncoding) {
+ [mySQLConnection storeEncodingForRestoration];
+ [mySQLConnection setEncoding:@"utf8"];
+ }
+
// Run the status query and retrieve as a dictionary.
NSMutableString *escapedTableName = [NSMutableString stringWithString:[tableListInstance tableName]];
[escapedTableName replaceOccurrencesOfString:@"'" withString:@"\\\'" options:0 range:NSMakeRange(0, [escapedTableName length])];
@@ -837,6 +867,7 @@
nil, nil, [NSApp mainWindow], self, nil, nil,
[NSString stringWithFormat:NSLocalizedString(@"An error occured while retrieving status data.\nMySQL said: %@", @"message of panel when retrieving view information failed"),
[mySQLConnection getLastErrorMessage]]);
+ if (changeEncoding) [mySQLConnection restoreStoredEncoding];
}
return FALSE;
}
@@ -854,6 +885,7 @@
// If the "Engine" key is NULL, a problem occurred when retrieving the table information.
if ([[status objectForKey:@"Engine"] isNSNull]) {
[status setDictionary:[NSDictionary dictionaryWithObjectsAndKeys:@"Error", @"Engine", [NSString stringWithFormat:NSLocalizedString(@"An error occurred retrieving table information. MySQL said: %@", @"MySQL table info retrieval error message"), [status objectForKey:@"Comment"]], @"Comment", [tableListInstance tableName], @"Name", nil]];
+ if (changeEncoding) [mySQLConnection restoreStoredEncoding];
return FALSE;
}
@@ -874,6 +906,8 @@
}
}
+ if (changeEncoding) [mySQLConnection restoreStoredEncoding];
+
return TRUE;
}
@@ -882,6 +916,14 @@
*/
- (BOOL) updateTriggersForCurrentTable
{
+
+ // Ensure queries are made in UTF8
+ BOOL changeEncoding = ![[mySQLConnection encoding] isEqualToString:@"utf8"];
+ if (changeEncoding) {
+ [mySQLConnection storeEncodingForRestoration];
+ [mySQLConnection setEncoding:@"utf8"];
+ }
+
MCPResult *theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"/*!50003 SHOW TRIGGERS WHERE `Table` = %@ */",
[[tableListInstance tableName] tickQuotedString]]];
[theResult setReturnDataAsStrings:YES];
@@ -894,6 +936,7 @@
[NSString stringWithFormat:NSLocalizedString(@"An error occurred while retrieving the trigger information for table '%@'. Please try again.\n\nMySQL said: %@", @"error retrieving table information informative message"),
[tableListInstance tableName], [mySQLConnection getLastErrorMessage]]);
if (triggers) [triggers release], triggers = nil;
+ if (changeEncoding) [mySQLConnection restoreStoredEncoding];
}
return NO;
@@ -905,6 +948,8 @@
[triggers addObject:[theResult fetchRowAsDictionary]];
}
+ if (changeEncoding) [mySQLConnection restoreStoredEncoding];
+
return YES;
}
@@ -1109,6 +1154,13 @@
- (NSArray *)primaryKeyColumnNames
{
+ // Ensure that identifier queries occur over UTF8
+ BOOL changeEncoding = ![[mySQLConnection encoding] isEqualToString:@"utf8"];
+ if (changeEncoding) {
+ [mySQLConnection storeEncodingForRestoration];
+ [mySQLConnection setEncoding:@"utf8"];
+ }
+
NSString *selectedTable = [tableListInstance tableName];
if(![selectedTable length]) return nil;
@@ -1122,11 +1174,16 @@
r = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW COLUMNS FROM %@ /*!50003 WHERE `key` = 'PRI'*/", [selectedTable backtickQuotedString]]];
[r setReturnDataAsStrings:YES];
- if([r numOfRows] < 1) return nil;
+ if([r numOfRows] < 1) {
+ if (changeEncoding && [mySQLConnection isConnected]) [mySQLConnection restoreStoredEncoding];
+ return nil;
+ }
if ([mySQLConnection queryErrored]) {
- if ([mySQLConnection isConnected])
+ if ([mySQLConnection isConnected]) {
NSRunAlertPanel(@"Error", [NSString stringWithFormat:NSLocalizedString(@"An error occured while retrieving the PRIMARY KEY data:\n\n%@",@"message when the query that fetches the primary keys fails"), [mySQLConnection getLastErrorMessage]], @"OK", nil, nil);
+ if (changeEncoding) [mySQLConnection restoreStoredEncoding];
+ }
return nil;
}
@@ -1139,6 +1196,8 @@
}
}
+ if (changeEncoding) [mySQLConnection restoreStoredEncoding];
+
if([keyColumns count]) return keyColumns;
return nil;
diff --git a/Source/SPTablesList.m b/Source/SPTablesList.m
index 7ae16742..b0e4594e 100644
--- a/Source/SPTablesList.m
+++ b/Source/SPTablesList.m
@@ -70,6 +70,7 @@
NSInteger i;
NSString *previousSelectedTable = nil;
BOOL previousTableListIsSelectable = tableListIsSelectable;
+ BOOL changeEncoding = ![[mySQLConnection encoding] isEqualToString:@"utf8"];
if (selectedTableName) previousSelectedTable = [[NSString alloc] initWithString:selectedTableName];
if (isTableListFiltered) {
@@ -92,6 +93,12 @@
// Notify listeners that a query has started
[[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:@"SMySQLQueryWillBePerformed" object:tableDocumentInstance];
+ // Use UTF8 for identifier-based queries
+ if (changeEncoding) {
+ [mySQLConnection storeEncodingForRestoration];
+ [mySQLConnection setEncoding:@"utf8"];
+ }
+
// Select the table list for the current database. On MySQL versions after 5 this will include
// views; on MySQL versions >= 5.0.02 select the "full" list to also select the table type column.
theResult = [mySQLConnection queryString:@"SHOW /*!50002 FULL*/ TABLES"];
@@ -104,7 +111,8 @@
} else {
for ( i = 0 ; i < [theResult numOfRows] ; i++ ) {
resultRow = [theResult fetchRowAsArray];
- [tables addObject:[resultRow objectAtIndex:0]];
+ NSString *tableName = [NSString stringWithUTF8String:[[resultRow objectAtIndex:0] cStringUsingEncoding:[mySQLConnection stringEncoding]]];
+ [tables addObject:tableName];
if ([[resultRow objectAtIndex:1] isEqualToString:@"VIEW"]) {
[tableTypes addObject:[NSNumber numberWithInteger:SPTableTypeView]];
tableListContainsViews = YES;
@@ -206,7 +214,11 @@
}
}
}
- */
+ */
+
+ // Restore encoding if appropriate
+ if (changeEncoding) [mySQLConnection restoreStoredEncoding];
+
// Notify listeners that the query has finished
[[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance];
}
@@ -695,6 +707,12 @@
{
NSAutoreleasePool *selectionChangePool = [[NSAutoreleasePool alloc] init];
NSString *tableEncoding = nil;
+ NSString *previousEncoding = [mySQLConnection encoding];
+ BOOL changeEncoding = ![previousEncoding isEqualToString:@"utf8"];
+ if (changeEncoding) {
+ [mySQLConnection storeEncodingForRestoration];
+ [mySQLConnection setEncoding:@"utf8"];
+ }
// Update selection variables and interface
NSDictionary *selectionDetails = [NSDictionary dictionaryWithObjectsAndKeys:
@@ -702,8 +720,11 @@
[filteredTableTypes objectAtIndex:[tablesListView selectedRow]], @"type",
nil];
[self performSelectorOnMainThread:@selector(setSelection:) withObject:selectionDetails waitUntilDone:YES];
-
- // Check the encoding if appropriate to determine if an encoding change and reset is required
+
+ // Ensure status information is cached on the working thread
+ [tableDataInstance updateStatusInformationForCurrentTable];
+
+ // Check the encoding if appropriate to determine if an encoding change is required
if( selectedTableType == SPTableTypeView || selectedTableType == SPTableTypeTable) {
// tableEncoding == nil indicates that there was an error while retrieving table data
@@ -712,16 +733,14 @@
// If encoding is set to Autodetect, update the connection character set encoding
// based on the newly selected table's encoding - but only if it differs from the current encoding.
if ([[[NSUserDefaults standardUserDefaults] objectForKey:SPDefaultEncoding] intValue] == SPEncodingAutodetect) {
- if (tableEncoding != nil && ![tableEncoding isEqualToString:[tableDocumentInstance connectionEncoding]]) {
+ if (tableEncoding != nil && ![tableEncoding isEqualToString:previousEncoding]) {
[tableDocumentInstance setConnectionEncoding:tableEncoding reloadingViews:NO];
- [tableDataInstance resetAllData];
- tableEncoding = [tableDataInstance tableEncoding];
+ changeEncoding = NO;
}
}
}
- // Ensure status information is cached on the working thread
- [tableDataInstance updateStatusInformationForCurrentTable];
+ if (changeEncoding) [mySQLConnection restoreStoredEncoding];
// Notify listeners of the table change now that the state is fully set up.
[[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:SPTableChangedNotification object:tableDocumentInstance];
@@ -2154,6 +2173,13 @@
NSString *tableType = [tableTypeButton title];
NSString *tableName = [tableNameField stringValue];
+
+ // Ensure the use of UTF8 when creating new tables
+ BOOL changeEncoding = ![[mySQLConnection encoding] isEqualToString:@"utf8"];
+ if (changeEncoding) {
+ [mySQLConnection storeEncodingForRestoration];
+ [mySQLConnection setEncoding:@"utf8"];
+ }
// If there is an encoding selected other than the default we must specify it in CREATE TABLE statement
if ([tableEncodingButton indexOfSelectedItem] > 0) {
@@ -2226,7 +2252,8 @@
NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self,
@selector(sheetDidEnd:returnCode:contextInfo:), @"addRow",
[NSString stringWithFormat:NSLocalizedString(@"An error occurred while trying to add the new table '%@'.\n\nMySQL said: %@", @"error adding new table informative message"), tableName, [mySQLConnection getLastErrorMessage]]);
-
+
+ if (changeEncoding) [mySQLConnection restoreStoredEncoding];
[tablesListView reloadData];
}
diff --git a/Source/SPXMLExporterDelegate.m b/Source/SPXMLExporterDelegate.m
index 17748bdc..e5073aed 100644
--- a/Source/SPXMLExporterDelegate.m
+++ b/Source/SPXMLExporterDelegate.m
@@ -71,7 +71,7 @@
// If we're exporting to multiple files then close the file handle of the exporter
// that just finished, ensuring its data is written to disk.
if (exportToMultipleFiles) {
- [[exporter exportOutputFile] writeData:[[NSString stringWithFormat:@"</%@>\n", [[tableDocumentInstance database] HTMLEscapeString]] dataUsingEncoding:[connection encoding]]];
+ [[exporter exportOutputFile] writeData:[[NSString stringWithFormat:@"</%@>\n", [[tableDocumentInstance database] HTMLEscapeString]] dataUsingEncoding:[connection stringEncoding]]];
[[exporter exportOutputFile] close];
}
@@ -85,7 +85,7 @@
// Otherwise if the exporter list is empty, close the progress sheet
else {
if (exportSource == SPTableExport) {
- [[exporter exportOutputFile] writeData:[[NSString stringWithFormat:@"</%@>\n", [[tableDocumentInstance database] HTMLEscapeString]] dataUsingEncoding:[connection encoding]]];
+ [[exporter exportOutputFile] writeData:[[NSString stringWithFormat:@"</%@>\n", [[tableDocumentInstance database] HTMLEscapeString]] dataUsingEncoding:[connection stringEncoding]]];
}
// Close the last exporter's file handle