Skip to content
Browse files

Fix an issue where Sequel Pro added a NUL byte to the end of every qu…

…ery (fixes #2184)

We tried to convert the query string into a c string that could contain NUL bytes - which by definition a c string cannot (making it a byte buffer with a terminating NUL byte) and then tried to pass that to mysql_real_query() which expects a byte buffer anyway.
  • Loading branch information
dmoagx committed Jul 29, 2015
1 parent c5525ba commit 26c821cf128255e89a6ff15f98891dbff1fc3840
@@ -40,9 +40,11 @@ @implementation SPMySQLConnection (Conversion)
* the current encoding, a representation will be returned rather than null.
* The returned cString will correctly preserve any nul characters within the string,
* which prevents the use of faster functions like [NSString cStringUsingEncoding:].
* Pass in the third parameter to receive the length of the converted string, or pass
* in NULL if you do not want this information.
* Pass in the third parameter to receive the length of the converted string (INCLUDING
* the terminating \0 character), or pass in NULL if you do not want this information.
#warning This method doesn't make sense. It's only addition over [str dataUsingEncoding:allowLossyConversion:] is the terminating NUL byte. \
But the "string" can already contain NUL bytes, so it's not a valid c string anyway.
+ (const char *)_cStringForString:(NSString *)aString usingEncoding:(NSStringEncoding)anEncoding returningLengthAs:(NSUInteger *)cStringLengthPointer
@@ -56,7 +58,7 @@ + (const char *)_cStringForString:(NSString *)aString usingEncoding:(NSStringEnc
// Take the converted data - not null-terminated - and copy it to a null-terminated buffer
char *cStringBytes = malloc(convertedDataLength + 1);
memcpy(cStringBytes, [convertedData bytes], convertedDataLength);
cStringBytes[convertedDataLength] = 0L;
cStringBytes[convertedDataLength] = '\0';

if (cStringLengthPointer) *cStringLengthPointer = convertedDataLength+1;

@@ -264,16 +264,17 @@ - (id)queryString:(NSString *)theQueryString usingEncoding:(NSStringEncoding)the
[delegate willQueryString:theQueryString connection:self];

// Retrieve a C-style query string from the supplied NSString
NSUInteger cQueryStringLength;
const char *cQueryString = _cStringForStringWithEncoding(theQueryString, theEncoding, &cQueryStringLength);
// Retrieve a byte buffer from the supplied NSString
NSData *queryData = [theQueryString dataUsingEncoding:theEncoding allowLossyConversion:YES];
NSUInteger queryBytesLength = [queryData length];
const char *queryBytes = [queryData bytes];

// Check the query length against the current maximum query length. If it is
// larger, the query would error (and probably cause a disconnect), so if
// the maximum size is editable, increase it and reconnect.
if (cQueryStringLength > maxQuerySize) {
if (queryBytesLength > maxQuerySize) {
queryActionShouldRestoreMaxQuerySize = maxQuerySize;
if (![self _attemptMaxQuerySizeIncreaseTo:(cQueryStringLength + 1024)]) {
if (![self _attemptMaxQuerySizeIncreaseTo:(queryBytesLength + 1024)]) {
queryActionShouldRestoreMaxQuerySize = NSNotFound;
return nil;
@@ -292,7 +293,7 @@ - (id)queryString:(NSString *)theQueryString usingEncoding:(NSStringEncoding)the
// While recording the overall execution time (including network lag!), run
// the raw query
uint64_t queryStartTime = mach_absolute_time();
queryStatus = mysql_real_query(mySQLConnection, cQueryString, cQueryStringLength);
queryStatus = mysql_real_query(mySQLConnection, queryBytes, queryBytesLength);
queryExecutionTime = _elapsedSecondsSinceAbsoluteTime(queryStartTime);
lastConnectionUsedTime = mach_absolute_time();

0 comments on commit 26c821c

Please sign in to comment.
You can’t perform that action at this time.