Permalink
Browse files

Merge remote-tracking branch 'sequelpro/master'

  • Loading branch information...
abhibeckert committed Aug 4, 2017
2 parents ff1db69 + 1cbc8f7 commit ebf7d8b7db4144d304bf2224db19d787d631eda0
Showing with 981 additions and 412 deletions.
  1. +13 −0 Frameworks/SPMySQLFramework/MySQL Client Libraries/Patches/001-cpp-dependency.diff
  2. +15 −0 Frameworks/SPMySQLFramework/MySQL Client Libraries/Patches/002-new-types.diff
  3. +9 −2 Frameworks/SPMySQLFramework/MySQL Client Libraries/include/mysql.h
  4. +2 −1 Frameworks/SPMySQLFramework/MySQL Client Libraries/include/mysql_com.h
  5. +2 −2 Frameworks/SPMySQLFramework/MySQL Client Libraries/include/mysql_version.h
  6. BIN Frameworks/SPMySQLFramework/MySQL Client Libraries/lib/libmysqlclient.a
  7. +14 −0 Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Conversion.h
  8. +9 −5 Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Conversion.m
  9. +28 −10 Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.m
  10. +6 −3 Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.m
  11. +71 −16 Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m
  12. +8 −2 Frameworks/SPMySQLFramework/build-mysql-client.sh
  13. +1 −1 Source/SPAppController.m
  14. +28 −9 Source/SPCopyTable.m
  15. +3 −5 Source/SPCustomQuery.h
  16. +12 −0 Source/SPCustomQuery.m
  17. +1 −0 Source/SPDataAdditions.h
  18. +134 −0 Source/SPDataAdditions.m
  19. +26 −32 Source/SPDataImport.m
  20. +103 −56 Source/SPDataStorage.m
  21. +3 −3 Source/SPDatabaseDocument.m
  22. +2 −2 Source/SPExportInitializer.m
  23. +3 −2 Source/SPExtendedTableInfo.m
  24. +2 −2 Source/SPFileHandle.h
  25. +40 −26 Source/SPFileHandle.m
  26. +105 −58 Source/SPIndexesController.m
  27. +34 −13 Source/SPProcessListController.m
  28. +0 −1 Source/SPTableContent.h
  29. +49 −30 Source/SPTableContent.m
  30. +2 −0 Source/SPTableContentDataSource.h
  31. +18 −6 Source/SPTableContentDataSource.m
  32. +33 −12 Source/SPTableContentDelegate.m
  33. +107 −98 Source/SPTableData.m
  34. +5 −2 Source/SPTablesList.m
  35. +3 −4 Source/SPWindowController.m
  36. +7 −9 Source/SPWindowControllerDelegate.m
  37. +76 −0 UnitTests/SPDataAdditionsTests.m
  38. +7 −0 readme.md
@@ -0,0 +1,13 @@
--- mysql-5.5.56-dist/extra/yassl/taocrypt/include/runtime.hpp 2017-04-27 09:12:30.000000000 +0200
+++ mysql-5.5.56/extra/yassl/taocrypt/include/runtime.hpp 2017-05-20 23:27:14.000000000 +0200
@@ -53,8 +53,8 @@
#endif
/* Disallow inline __cxa_pure_virtual() */
-static int __cxa_pure_virtual() __attribute__((noinline, used));
-static int __cxa_pure_virtual()
+int __cxa_pure_virtual() __attribute__((noinline, used));
+int __cxa_pure_virtual()
{
// oops, pure virtual called!
return 0;
@@ -0,0 +1,15 @@
--- mysql-5.5.56-dist/include/mysql_com.h 2017-04-27 09:12:30.000000000 +0200
+++ mysql-5.5.56/include/mysql_com.h 2017-05-21 01:46:44.000000000 +0200
@@ -349,7 +349,11 @@
MYSQL_TYPE_DATETIME, MYSQL_TYPE_YEAR,
MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR,
MYSQL_TYPE_BIT,
- MYSQL_TYPE_NEWDECIMAL=246,
+ MYSQL_TYPE_TIMESTAMP2,
+ MYSQL_TYPE_DATETIME2,
+ MYSQL_TYPE_TIME2,
+ MYSQL_TYPE_JSON=245,
+ MYSQL_TYPE_NEWDECIMAL=246,
MYSQL_TYPE_ENUM=247,
MYSQL_TYPE_SET=248,
MYSQL_TYPE_TINY_BLOB=249,
@@ -1,4 +1,4 @@
/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
/* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -167,7 +167,9 @@ enum mysql_option
MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH,
MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT,
MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH,
MYSQL_ENABLE_CLEARTEXT_PLUGIN
MYSQL_ENABLE_CLEARTEXT_PLUGIN,
/* Set MYSQL_OPT_SSL_MODE to be the same as in 5.6 (ABI compatibility). */
MYSQL_OPT_SSL_MODE= 38
};
/**
@@ -224,6 +226,11 @@ enum mysql_protocol_type
MYSQL_PROTOCOL_PIPE, MYSQL_PROTOCOL_MEMORY
};
enum mysql_ssl_mode
{
SSL_MODE_REQUIRED= 3
};
typedef struct character_set
{
unsigned int number; /* character set number */
@@ -1,4 +1,4 @@
/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -26,6 +26,7 @@
#define USERNAME_CHAR_LENGTH 16
#define NAME_LEN (NAME_CHAR_LEN*SYSTEM_CHARSET_MBMAXLEN)
#define USERNAME_LENGTH (USERNAME_CHAR_LENGTH*SYSTEM_CHARSET_MBMAXLEN)
#define CONNECT_STRING_MAXLEN 1024
#define MYSQL_AUTODETECT_CHARSET_NAME "auto"
@@ -11,11 +11,11 @@
#include <custom_conf.h>
#else
#define PROTOCOL_VERSION 10
#define MYSQL_SERVER_VERSION "5.5.42"
#define MYSQL_SERVER_VERSION "5.5.56"
#define MYSQL_BASE_VERSION "mysqld-5.5"
#define MYSQL_SERVER_SUFFIX_DEF ""
#define FRM_VER 6
#define MYSQL_VERSION_ID 50542
#define MYSQL_VERSION_ID 50556
#define MYSQL_PORT 3306
#define MYSQL_PORT_DEFAULT 0
#define MYSQL_UNIX_ADDR "/tmp/mysql.sock"
@@ -34,6 +34,7 @@
@interface SPMySQLConnection (Conversion)
+ (const char *)_cStringForString:(NSString *)aString usingEncoding:(NSStringEncoding)anEncoding returningLengthAs:(NSUInteger *)cStringLengthPointer;
+ (NSString *)_stringForCString:(const char *)cString usingEncoding:(NSStringEncoding)encoding;
- (const char *)_cStringForString:(NSString *)aString;
- (NSString *)_stringForCString:(const char *)cString;
@@ -56,3 +57,16 @@ static inline const char* _cStringForStringWithEncoding(NSString* aString, NSStr
return (const char *)(*cachedMethodPointer)(cachedClass, cachedSelector, aString, anEncoding, cStringLengthPointer);
}
/**
* Converts a C string (NUL-terminated) to an NSString using the supplied encoding.
*
* Unlike +[NSString stringWithCString:encoding:] which will crash on a NULL pointer, this method will return nil instead.
*/
static inline NSString * _stringForCStringWithEncoding(const char *aString, NSStringEncoding inputEncoding)
{
//This implementation is smaller than the cached selector voodoo above, so let's do it inline
//NSString will crash on NULL ptr
return (aString == NULL)? nil : [NSString stringWithCString:aString encoding:inputEncoding];
}
@@ -79,19 +79,23 @@ - (const char *)_cStringForString:(NSString *)aString
}
/**
* Converts a C string to an NSString using the supplied encoding.
* Converts a C string to an NSString using the current connection encoding.
* This method *will not* correctly preserve nul characters within c strings; instead
* the first nul character within the string will be treated as the line ending. This
* is unavoidable without supplying a string length, so this method should not be widely
* used for actual data conversion.
*/
- (NSString *)_stringForCString:(const char *)cString
{
return _stringForCStringWithEncoding(cString, stringEncoding);
}
// Don't try and convert null strings
if (cString == NULL) return nil;
return [NSString stringWithCString:cString encoding:stringEncoding];
/**
* @see _stringForCStringWithEncoding()
*/
+ (NSString *)_stringForCString:(const char *)cString usingEncoding:(NSStringEncoding)encoding
{
return _stringForCStringWithEncoding(cString, encoding);
}
@end
@@ -85,9 +85,9 @@ - (void)_threadedKeepAlive
if(keepAliveThread) {
NSLog(@"warning: overwriting existing keepAliveThread: %@, results may be unpredictable!",keepAliveThread);
}
keepAliveThread = [NSThread currentThread];
}
keepAliveThread = [NSThread currentThread];
[keepAliveThread setName:[NSString stringWithFormat:@"SPMySQL connection keepalive monitor thread (id=%p)", self]];
// If the maximum number of ping failures has been reached, determine whether to reconnect.
@@ -159,19 +159,21 @@ - (BOOL)_pingConnectionUsingLoopDelay:(NSUInteger)loopDelay
if (timeout > 0) pingTimeout = timeout;
// Set up a struct containing details the ping task will need
SPMySQLConnectionPingDetails *pingDetails = malloc(sizeof(SPMySQLConnectionPingDetails));
pingDetails->mySQLConnection = mySQLConnection;
pingDetails->keepAliveLastPingSuccessPointer = &keepAliveLastPingSuccess;
pingDetails->keepAlivePingThreadActivePointer = &keepAlivePingThreadActive;
pingDetails->parentId = self;
// we can do this on the stack since this method makes sure to outlive the ping thread
SPMySQLConnectionPingDetails pingDetails = {
.mySQLConnection = mySQLConnection,
.keepAliveLastPingSuccessPointer = &keepAliveLastPingSuccess,
.keepAlivePingThreadActivePointer = &keepAlivePingThreadActive,
.parentId = self
};
// Create a pthread for the ping
pthread_t keepAlivePingThread_t;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&keepAlivePingThread_t, &attr, (void *)&_backgroundPingTask, pingDetails);
pthread_create(&keepAlivePingThread_t, &attr, (void *)&_backgroundPingTask, &pingDetails);
// Record the ping start time
pingStartTime_t = mach_absolute_time();
@@ -200,13 +202,12 @@ - (BOOL)_pingConnectionUsingLoopDelay:(NSUInteger)loopDelay
}
} while (keepAlivePingThreadActive);
//wait for thread to go away, otherwise our free() below might run before _pingThreadCleanup()
//wait for thread to go away, otherwise pingDetails may go away before _pingThreadCleanup() finishes
pthread_join(keepAlivePingThread_t, NULL);
// Clean up
keepAlivePingThread_t = NULL;
pthread_attr_destroy(&attr);
free(pingDetails);
// Unlock the connection
[self _unlockConnection];
@@ -282,7 +283,24 @@ - (BOOL)_cancelKeepAlives
if (keepAliveThread) {
// Mark the thread as cancelled
[keepAliveThread cancel];
@synchronized(self) {
// the synchronized is neccesary here, because we don't retain keepAliveThread.
// If it were ommitted, for example this could happen:
//
// this thread keepalive thread
// -------------- -----------------
// 1 fetch value of keepAliveThread to register
// 2 keepAliveThread = nil
// 3 [[NSThread currentThread] release]
// 4 objc_msgSend() <-- invalid memory accessed
//
// With synchronized we are guaranteed to either message nil or block the keepAliveThread from exiting
// (and thus releasing the NSThread object) until this call finishes.
//
// We can omit it in the other 2 cases, since keepAliveThread is already volatile and we are only
// checking for NULL, not dereferencing it.
[keepAliveThread cancel];
}
// Wait inside a time limit of ten seconds for it to exit
uint64_t threadCancelStartTime_t = mach_absolute_time();
@@ -323,7 +323,8 @@ - (id)queryString:(NSString *)theQueryString usingEncoding:(NSStringEncoding)the
// Store the error state
theErrorMessage = [self _stringForCString:mysql_error(mySQLConnection)];
theErrorID = mysql_errno(mySQLConnection);
theSqlstate = [self _stringForCString:mysql_sqlstate(mySQLConnection)];
// sqlstate is always an ASCII string, regardless of charset (but use latin1 anyway as that is less picky about invalid bytes)
theSqlstate = _stringForCStringWithEncoding(mysql_sqlstate(mySQLConnection), NSISOLatin1StringEncoding);
// Prevent retries if the query was cancelled or not a connection error
if (lastQueryWasCancelled || ![SPMySQLConnection isErrorIDConnectionError:theErrorID]) {
@@ -382,7 +383,8 @@ - (id)queryString:(NSString *)theQueryString usingEncoding:(NSStringEncoding)the
// Update the error message, if appropriate, to reflect result store errors or overall success
theErrorMessage = [self _stringForCString:mysql_error(mySQLConnection)];
theErrorID = mysql_errno(mySQLConnection);
theSqlstate = [self _stringForCString:mysql_sqlstate(mySQLConnection)];
// sqlstate is always an ASCII string, regardless of charset (but use latin1 anyway as that is less picky about invalid bytes)
theSqlstate = _stringForCStringWithEncoding(mysql_sqlstate(mySQLConnection), NSISOLatin1StringEncoding);
} else {
theResult = [[SPMySQLEmptyResult alloc] init];
}
@@ -735,7 +737,8 @@ - (void)_updateLastSqlstate:(NSString *)theSqlstate
{
// If a SQLSTATE wasn't supplied, select one from the connection
if(!theSqlstate) {
theSqlstate = [self _stringForCString:mysql_sqlstate(mySQLConnection)];
// sqlstate is always an ASCII string, regardless of charset (but use latin1 anyway as that is less picky about invalid bytes)
theSqlstate = _stringForCStringWithEncoding(mysql_sqlstate(mySQLConnection), NSISOLatin1StringEncoding);
}
// Clear the last SQLSTATE stored on the instance
@@ -606,6 +606,7 @@ - (MYSQL *)_makeRawMySQLConnectionWithEncoding:(NSString *)encodingName isMaster
mysql_options(theConnection, MYSQL_OPT_CONNECT_TIMEOUT, (const void *)&timeout);
// Set the connection encoding
NSStringEncoding connectEncodingNS = [SPMySQLConnection stringEncodingForMySQLCharset:[encodingName UTF8String]];
mysql_options(theConnection, MYSQL_SET_CHARSET_NAME, [encodingName UTF8String]);
// Set up the connection variables in the format MySQL needs, from the class-wide variables
@@ -614,22 +615,36 @@ - (MYSQL *)_makeRawMySQLConnectionWithEncoding:(NSString *)encodingName isMaster
const char *thePassword = NULL;
const char *theSocket = NULL;
if (host) theHost = [self _cStringForString:host];
if (username) theUsername = [self _cStringForString:username];
if (host) theHost = [host UTF8String]; //mysql calls getaddrinfo on the hostname. Apples code uses -UTF8String in that situation.
if (username) theUsername = _cStringForStringWithEncoding(username, connectEncodingNS, NULL); //during connect this is in MYSQL_SET_CHARSET_NAME encoding
// If a password was supplied, use it; otherwise ask the delegate if appropriate
// If a password was supplied, use it; otherwise ask the delegate if appropriate.
//
// Note that password has no charset in mysql: If a user password is set to 'ü' on a latin1 connection
// and you later try to connect on an UTF-8 terminal (or vice versa) it will fail. The MySQL (5.5) manual wrongly states that
// MYSQL_SET_CHARSET_NAME has influence over that, but it does not and could not, since the password is hashed by the client
// before transmitting it to the server and the (5.5) client has no charset support, effectively treating password as
// a NUL-terminated byte array.
// There is one exception, though: The "mysql_clear_password" auth plugin sends the password in plaintext and the server side
// MAY choose to do a charset conversion as appropriate before handing it to whatever backend is used.
// Since we don't know which auth plugin server and client will agree upon, we'll do as the manual says...
if (password) {
thePassword = [self _cStringForString:password];
thePassword = _cStringForStringWithEncoding(password, connectEncodingNS, NULL);
} else if ([delegate respondsToSelector:@selector(keychainPasswordForConnection:)]) {
thePassword = [self _cStringForString:[delegate keychainPasswordForConnection:self]];
thePassword = _cStringForStringWithEncoding([delegate keychainPasswordForConnection:self], connectEncodingNS, NULL);
}
// If set to use a socket and a socket was supplied, use it; otherwise, search for a socket to use
if (useSocket) {
if ([socketPath length]) {
theSocket = [self _cStringForString:socketPath];
} else {
theSocket = [self _cStringForString:[SPMySQLConnection findSocketPath]];
//default to user supplied path
NSString *mySocketPath = socketPath;
//if none was given, search in the default locations instead
if (![mySocketPath length]) {
mySocketPath = [SPMySQLConnection findSocketPath];
}
//get C string if we have a path (danger: method will throw on empty/nil string!)
if([mySocketPath length]) {
theSocket = [mySocketPath fileSystemRepresentation];
}
}
@@ -640,20 +655,39 @@ - (MYSQL *)_makeRawMySQLConnectionWithEncoding:(NSString *)encodingName isMaster
const char *theCACertificatePath = NULL;
const char *theSSLCiphers = SPMySQLSSLPermissibleCiphers;
if (sslKeyFilePath) {
theSSLKeyFilePath = [[sslKeyFilePath stringByExpandingTildeInPath] UTF8String];
if ([sslKeyFilePath length]) {
theSSLKeyFilePath = [[sslKeyFilePath stringByExpandingTildeInPath] fileSystemRepresentation];
}
if (sslCertificatePath) {
theSSLCertificatePath = [[sslCertificatePath stringByExpandingTildeInPath] UTF8String];
if ([sslCertificatePath length]) {
theSSLCertificatePath = [[sslCertificatePath stringByExpandingTildeInPath] fileSystemRepresentation];
}
if (sslCACertificatePath) {
theCACertificatePath = [[sslCACertificatePath stringByExpandingTildeInPath] UTF8String];
if ([sslCACertificatePath length]) {
theCACertificatePath = [[sslCACertificatePath stringByExpandingTildeInPath] fileSystemRepresentation];
}
if(sslCipherList) {
theSSLCiphers = [sslCipherList UTF8String];
}
// Calling mysql_ssl_set() to libmysqlclient only means that connecting with SSL would be nice.
// If the server doesn't support SSL though, it will *silently* fall back to plaintext and in the worst case even transmit
// the password in cleartext.
//
// Setting MYSQL_OPT_SSL_MODE is required, to actually make it abort the connection if the server doesn't signal SSL support.
//
// mysql 5.5.55+
// mysql 5.6.36+
// mysql 5.7.11+ (5.7.3 - 5.7.10 with a different name)
// mysql 8.0+
mysql_ssl_set(theConnection, theSSLKeyFilePath, theSSLCertificatePath, theCACertificatePath, NULL, theSSLCiphers);
enum mysql_ssl_mode opt_ssl_mode = SSL_MODE_REQUIRED;
if(mysql_options(theConnection, MYSQL_OPT_SSL_MODE, (void *)&opt_ssl_mode)) {
if(isMaster) {
[self _updateLastErrorMessage:@"libmysqlclient is missing support for MYSQL_OPT_SSL_MODE"];
[self _updateLastSqlstate:@"HY000"];
[self _updateLastErrorID:2026];
}
return NULL;
}
}
MYSQL *connectionStatus = mysql_real_connect(theConnection, theHost, theUsername, thePassword, NULL, (unsigned int)port, theSocket, [self clientFlags]);
@@ -663,9 +697,30 @@ - (MYSQL *)_makeRawMySQLConnectionWithEncoding:(NSString *)encodingName isMaster
// If the connection is the master connection, record the error state
if (isMaster) {
// <TODO>
// this is tricky: mysql_error() is supposed to return data encoded in character_set_results (in mysql 5.5+),
// yet the whole API treats it as if it were a plain C string.
// So if the charset is e.g. utf16 the mysql server will itself fall over that and return an empty error message
// (5.5, 5.7: the message is really missing at the network layer).
// (Side Note: There is a workaround for server generated error messages: "show warnings" will also include errors
// and because it uses a regular results table it can contain the actual error message)
//
// Before 5.5 things are much worse, because the charset of the message depends on the language of the error messages
// (which can be changed at runtime per session (or at launch time in 4.1)) plus all arguments in the template string
// will retain their original encoding.
// So if you connect with utf8 to a server with russian locale the error message will be in koi8r and contain the name of
// an erroneus value in utf8...
//
// On the other hand mysql_error() may also return errors generated by the client locally.
// The client has no charset support and simply assumes the local charset is ASCII-compatible.
// The english messages are compiled into the client (see libmysql/errmsg.c and include/errmsg.h).
// We could use a little trick, though: client errors are in the exclusive range 2000 to 2999 (CR_MIN_ERROR/CR_MAX_ERROR)
// and all their string arguments are either hostnames or file system paths, which on OS X use UTF-8.
[self _updateLastErrorMessage:[self _stringForCString:mysql_error(theConnection)]];
// </TODO>
[self _updateLastErrorID:mysql_errno(theConnection)];
[self _updateLastSqlstate:[self _stringForCString:mysql_sqlstate(theConnection)]];
// sqlstate is always an ASCII string, regardless of charset (but use latin1 anyway as that is less picky about invalid bytes)
[self _updateLastSqlstate:_stringForCStringWithEncoding(mysql_sqlstate(theConnection),NSISOLatin1StringEncoding)];
}
return NULL;
Oops, something went wrong.

0 comments on commit ebf7d8b

Please sign in to comment.