diff options
Diffstat (limited to 'Frameworks')
13 files changed, 177 insertions, 43 deletions
diff --git a/Frameworks/SPMySQLFramework/MySQL Client Libraries/Patches/001-cpp-dependency.diff b/Frameworks/SPMySQLFramework/MySQL Client Libraries/Patches/001-cpp-dependency.diff new file mode 100644 index 00000000..06c20001 --- /dev/null +++ b/Frameworks/SPMySQLFramework/MySQL Client Libraries/Patches/001-cpp-dependency.diff @@ -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; diff --git a/Frameworks/SPMySQLFramework/MySQL Client Libraries/Patches/002-new-types.diff b/Frameworks/SPMySQLFramework/MySQL Client Libraries/Patches/002-new-types.diff new file mode 100644 index 00000000..bb42f9d9 --- /dev/null +++ b/Frameworks/SPMySQLFramework/MySQL Client Libraries/Patches/002-new-types.diff @@ -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, diff --git a/Frameworks/SPMySQLFramework/MySQL Client Libraries/include/mysql.h b/Frameworks/SPMySQLFramework/MySQL Client Libraries/include/mysql.h index da29cb34..3a27ab41 100644 --- a/Frameworks/SPMySQLFramework/MySQL Client Libraries/include/mysql.h +++ b/Frameworks/SPMySQLFramework/MySQL Client Libraries/include/mysql.h @@ -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 */ diff --git a/Frameworks/SPMySQLFramework/MySQL Client Libraries/include/mysql_com.h b/Frameworks/SPMySQLFramework/MySQL Client Libraries/include/mysql_com.h index 8a8c019d..a3800c41 100644 --- a/Frameworks/SPMySQLFramework/MySQL Client Libraries/include/mysql_com.h +++ b/Frameworks/SPMySQLFramework/MySQL Client Libraries/include/mysql_com.h @@ -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" diff --git a/Frameworks/SPMySQLFramework/MySQL Client Libraries/include/mysql_version.h b/Frameworks/SPMySQLFramework/MySQL Client Libraries/include/mysql_version.h index 7a8578ad..8c18116a 100644 --- a/Frameworks/SPMySQLFramework/MySQL Client Libraries/include/mysql_version.h +++ b/Frameworks/SPMySQLFramework/MySQL Client Libraries/include/mysql_version.h @@ -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" diff --git a/Frameworks/SPMySQLFramework/MySQL Client Libraries/lib/libmysqlclient.a b/Frameworks/SPMySQLFramework/MySQL Client Libraries/lib/libmysqlclient.a Binary files differindex aa0d6109..0fccae22 100644 --- a/Frameworks/SPMySQLFramework/MySQL Client Libraries/lib/libmysqlclient.a +++ b/Frameworks/SPMySQLFramework/MySQL Client Libraries/lib/libmysqlclient.a diff --git a/Frameworks/SPMySQLFramework/SPMySQLFramework.xcodeproj/project.pbxproj b/Frameworks/SPMySQLFramework/SPMySQLFramework.xcodeproj/project.pbxproj index d0195914..aa7989fc 100644 --- a/Frameworks/SPMySQLFramework/SPMySQLFramework.xcodeproj/project.pbxproj +++ b/Frameworks/SPMySQLFramework/SPMySQLFramework.xcodeproj/project.pbxproj @@ -8,7 +8,6 @@ /* Begin PBXBuildFile section */ 177916A21E88733000EE3043 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 177916A01E88733000EE3043 /* LICENSE */; }; - 177916A31E88733000EE3043 /* README.md in Sources */ = {isa = PBXBuildFile; fileRef = 177916A11E88733000EE3043 /* README.md */; }; 17E3A57B1885A286009CF372 /* SPMySQLDataTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 17E3A5791885A286009CF372 /* SPMySQLDataTypes.h */; settings = {ATTRIBUTES = (Public, ); }; }; 17E3A57C1885A286009CF372 /* SPMySQLDataTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = 17E3A57A1885A286009CF372 /* SPMySQLDataTypes.m */; }; 507FF1E51BC0D82300104523 /* DataConversion_Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 507FF1811BC0C64100104523 /* DataConversion_Tests.m */; }; @@ -571,7 +570,6 @@ 584294FF14CB8002000F8438 /* Server Info.m in Sources */, 5884142814CCF5190078027F /* Conversion.m in Sources */, 5884159514D1A6880078027F /* Querying & Preparation.m in Sources */, - 177916A31E88733000EE3043 /* README.md in Sources */, 5884159414D1A6760078027F /* Locking.m in Sources */, 17E3A57C1885A286009CF372 /* SPMySQLDataTypes.m in Sources */, 5884165614D2306A0078027F /* SPMySQLResult.m in Sources */, diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Conversion.h b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Conversion.h index 6f7b1a9a..77b70bf9 100644 --- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Conversion.h +++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Conversion.h @@ -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]; +} diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Conversion.m b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Conversion.m index 676684ca..a7d293ea 100644 --- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Conversion.m +++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Conversion.m @@ -79,7 +79,7 @@ } /** - * 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 @@ -87,11 +87,15 @@ */ - (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 diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.m b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.m index d46b5552..65a7ae02 100644 --- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.m +++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.m @@ -85,9 +85,9 @@ 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,11 +159,13 @@ end_cleanup: 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; @@ -171,7 +173,7 @@ end_cleanup: 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 @@ end_cleanup: } } 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 @@ void _pingThreadCleanup(void *pingDetails) 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(); diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.m b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.m index 594756be..ef98a21c 100644 --- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.m +++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.m @@ -323,7 +323,8 @@ // 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 @@ // 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 @@ { // 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 diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m index e8692895..f581c03c 100644 --- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m +++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m @@ -606,6 +606,7 @@ static uint64_t _elapsedMicroSecondsSinceAbsoluteTime(uint64_t comparisonTime) 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 @@ static uint64_t _elapsedMicroSecondsSinceAbsoluteTime(uint64_t comparisonTime) 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 @@ static uint64_t _elapsedMicroSecondsSinceAbsoluteTime(uint64_t comparisonTime) 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 @@ static uint64_t _elapsedMicroSecondsSinceAbsoluteTime(uint64_t comparisonTime) // 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; diff --git a/Frameworks/SPMySQLFramework/build-mysql-client.sh b/Frameworks/SPMySQLFramework/build-mysql-client.sh index 2e7c4fc9..5475b0a0 100755 --- a/Frameworks/SPMySQLFramework/build-mysql-client.sh +++ b/Frameworks/SPMySQLFramework/build-mysql-client.sh @@ -156,9 +156,15 @@ then exit 1 fi +# For CMake 3.0+ use CMAKE_OSX_SYSROOT and CMAKE_OSX_DEPLOYMENT_TARGET to set SDK path and minimum version +CONFIGURE_OPTIONS="${CONFIGURE_OPTIONS} -DCMAKE_OSX_SYSROOT='${SDK_PATH}' -DCMAKE_OSX_DEPLOYMENT_TARGET=${MIN_OS_X_VERSION}" + +# For CMake 2 add these parameters to the CFLAGS/CXXFLAGS: +# -isysroot ${SDK_PATH} -mmacosx-version-min=${MIN_OS_X_VERSION} + # C/C++ compiler flags -export CFLAGS="-isysroot ${SDK_PATH} ${ARCHITECTURES} -O3 -fno-omit-frame-pointer -fno-exceptions -mmacosx-version-min=${MIN_OS_X_VERSION}" -export CXXFLAGS="-isysroot ${SDK_PATH} ${ARCHITECTURES} -O3 -fno-omit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti -mmacosx-version-min=${MIN_OS_X_VERSION}" +export CFLAGS="${ARCHITECTURES} -O3 -fno-omit-frame-pointer -fno-exceptions" +export CXXFLAGS="${ARCHITECTURES} -O3 -fno-omit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti" echo "$ESC[1mConfiguring MySQL source...$ESC[0m" |