From b49edf67744ba6e54b7c0bdab7dc197cf8faac96 Mon Sep 17 00:00:00 2001 From: Max Date: Thu, 3 May 2018 22:26:12 +0200 Subject: Replace all non-cyclic NSAutoreleasepools with @autoreleasepool --- .../SPMySQLFramework/Source/SPMySQLConnection.m | 278 ++++++++++----------- .../Source/SPMySQLFastStreamingResult.m | 126 +++++----- .../SPMySQLResult Categories/Field Definitions.m | 2 +- .../Source/SPMySQLStreamingResultStore.m | 243 +++++++++--------- 4 files changed, 320 insertions(+), 329 deletions(-) (limited to 'Frameworks/SPMySQLFramework') diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m index 73cadd6e..70894d05 100644 --- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m +++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m @@ -735,185 +735,181 @@ asm(".desc ___crashreporter_info__, 0x10"); if (userTriggeredDisconnect) return NO; BOOL reconnectSucceeded = NO; - NSAutoreleasePool *reconnectionPool = [[NSAutoreleasePool alloc] init]; - - // Check whether a reconnection attempt is already being made - if so, wait - // and return the status of that reconnection attempt. This improves threaded - // use of the connection by preventing reconnect races. - if (reconnectingThread && !pthread_equal(reconnectingThread, pthread_self())) { - - // Loop in a panel runloop mode until the reconnection has processed; if an iteration - // takes less than the requested 0.1s, sleep instead. - while (reconnectingThread) { - uint64_t loopIterationStart_t = mach_absolute_time(); + @autoreleasepool { + // Check whether a reconnection attempt is already being made - if so, wait + // and return the status of that reconnection attempt. This improves threaded + // use of the connection by preventing reconnect races. + if (reconnectingThread && !pthread_equal(reconnectingThread, pthread_self())) { + + // Loop in a panel runloop mode until the reconnection has processed; if an iteration + // takes less than the requested 0.1s, sleep instead. + while (reconnectingThread) { + uint64_t loopIterationStart_t = mach_absolute_time(); + + [[NSRunLoop currentRunLoop] runMode:NSModalPanelRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + if (_elapsedSecondsSinceAbsoluteTime(loopIterationStart_t) < 0.1) { + usleep(100000 - (useconds_t)(1000000 * _elapsedSecondsSinceAbsoluteTime(loopIterationStart_t))); + } + } - [[NSRunLoop currentRunLoop] runMode:NSModalPanelRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - if (_elapsedSecondsSinceAbsoluteTime(loopIterationStart_t) < 0.1) { - usleep(100000 - (useconds_t)(1000000 * _elapsedSecondsSinceAbsoluteTime(loopIterationStart_t))); + // Continue only if the reconnection being waited on was a background attempt + if (!(state == SPMySQLConnectionLostInBackground && canRetry)) { + return (state == SPMySQLConnected); } } - // Continue only if the reconnection being waited on was a background attempt - if (!(state == SPMySQLConnectionLostInBackground && canRetry)) { - [reconnectionPool drain]; - return (state == SPMySQLConnected); + if ([[NSThread currentThread] isCancelled]) { + return NO; } - } - if ([[NSThread currentThread] isCancelled]) { - [reconnectionPool release]; - return NO; - } + reconnectingThread = pthread_self(); - reconnectingThread = pthread_self(); + // Store certain details about the connection, so that if the reconnection is successful + // they can be restored. This has to be treated separately from _restoreConnectionDetails + // as a full connection reinitialises certain values from the server. + if (!encodingToRestore) { + encodingToRestore = [encoding copy]; + encodingUsesLatin1TransportToRestore = encodingUsesLatin1Transport; + databaseToRestore = [database copy]; + } - // Store certain details about the connection, so that if the reconnection is successful - // they can be restored. This has to be treated separately from _restoreConnectionDetails - // as a full connection reinitialises certain values from the server. - if (!encodingToRestore) { - encodingToRestore = [encoding copy]; - encodingUsesLatin1TransportToRestore = encodingUsesLatin1Transport; - databaseToRestore = [database copy]; - } + // If there is a connection proxy, temporarily disassociate the state change action + if (proxy) proxyStateChangeNotificationsIgnored = YES; - // If there is a connection proxy, temporarily disassociate the state change action - if (proxy) proxyStateChangeNotificationsIgnored = YES; + // Close the connection if it's active + [self _disconnect]; - // Close the connection if it's active - [self _disconnect]; + // Lock the connection while waiting for network and proxy + [self _lockConnection]; - // Lock the connection while waiting for network and proxy - [self _lockConnection]; + // If no network is present, wait for a short time for one to become available + [self _waitForNetworkConnectionWithTimeout:10]; - // If no network is present, wait for a short time for one to become available - [self _waitForNetworkConnectionWithTimeout:10]; + if ([[NSThread currentThread] isCancelled]) { + [self _unlockConnection]; + reconnectingThread = NULL; + return NO; + } - if ([[NSThread currentThread] isCancelled]) { - [self _unlockConnection]; - reconnectingThread = NULL; - [reconnectionPool release]; - return NO; - } + // If there is a proxy, attempt to reconnect it in blocking fashion + if (proxy) { + uint64_t loopIterationStart_t, proxyWaitStart_t; - // If there is a proxy, attempt to reconnect it in blocking fashion - if (proxy) { - uint64_t loopIterationStart_t, proxyWaitStart_t; + // If the proxy is not yet idle after requesting a disconnect, wait for a short time + // to allow it to disconnect. + if ([proxy state] != SPMySQLProxyIdle) { - // If the proxy is not yet idle after requesting a disconnect, wait for a short time - // to allow it to disconnect. - if ([proxy state] != SPMySQLProxyIdle) { + proxyWaitStart_t = mach_absolute_time(); + while ([proxy state] != SPMySQLProxyIdle) { + loopIterationStart_t = mach_absolute_time(); + // If the connection timeout has passed, break out of the loop + if (_elapsedSecondsSinceAbsoluteTime(proxyWaitStart_t) > timeout) break; + + // Allow events to process for 0.25s, sleeping to completion on early return + [[NSRunLoop currentRunLoop] runMode:NSModalPanelRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.25]]; + if (_elapsedSecondsSinceAbsoluteTime(loopIterationStart_t) < 0.25) { + usleep(250000 - (useconds_t)(1000000 * _elapsedSecondsSinceAbsoluteTime(loopIterationStart_t))); + } + } + } + + // Request that the proxy re-establishes its connection + [proxy connect]; + + // Wait while the proxy connects proxyWaitStart_t = mach_absolute_time(); - while ([proxy state] != SPMySQLProxyIdle) { + while (1) { loopIterationStart_t = mach_absolute_time(); - // If the connection timeout has passed, break out of the loop - if (_elapsedSecondsSinceAbsoluteTime(proxyWaitStart_t) > timeout) break; + // If the proxy has connected, record the new local port and break out of the loop + if ([proxy state] == SPMySQLProxyConnected) { + port = [proxy localPort]; + break; + } + + // If the proxy connection attempt time has exceeded the timeout, break of of the loop. + if (_elapsedSecondsSinceAbsoluteTime(proxyWaitStart_t) > (timeout + 1)) { + [proxy disconnect]; + break; + } - // Allow events to process for 0.25s, sleeping to completion on early return + // Process events for a short time, allowing dialogs to be shown but waiting for + // the proxy. Capture how long this interface action took, standardising the + // overall time. [[NSRunLoop currentRunLoop] runMode:NSModalPanelRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.25]]; if (_elapsedSecondsSinceAbsoluteTime(loopIterationStart_t) < 0.25) { - usleep(250000 - (useconds_t)(1000000 * _elapsedSecondsSinceAbsoluteTime(loopIterationStart_t))); + usleep((useconds_t)(250000 - (1000000 * _elapsedSecondsSinceAbsoluteTime(loopIterationStart_t)))); + } + + // Extend the connection timeout by any interface time + if ([proxy state] == SPMySQLProxyWaitingForAuth) { + proxyWaitStart_t += mach_absolute_time() - loopIterationStart_t; } } - } - // Request that the proxy re-establishes its connection - [proxy connect]; + // Having in theory performed the proxy connect, update state + previousProxyState = [proxy state]; + proxyStateChangeNotificationsIgnored = NO; + } - // Wait while the proxy connects - proxyWaitStart_t = mach_absolute_time(); - while (1) { - loopIterationStart_t = mach_absolute_time(); + // Unlock the connection + [self _unlockConnection]; - // If the proxy has connected, record the new local port and break out of the loop - if ([proxy state] == SPMySQLProxyConnected) { - port = [proxy localPort]; - break; - } + // If not using a proxy, or if the proxy successfully connected, trigger a connection + if (!proxy || [proxy state] == SPMySQLProxyConnected) { + [self _connect]; + } - // If the proxy connection attempt time has exceeded the timeout, break of of the loop. - if (_elapsedSecondsSinceAbsoluteTime(proxyWaitStart_t) > (timeout + 1)) { - [proxy disconnect]; - break; + // If the reconnection succeeded, restore the connection state as appropriate + if (state == SPMySQLConnected && ![[NSThread currentThread] isCancelled]) { + reconnectSucceeded = YES; + if (databaseToRestore) { + [self selectDatabase:databaseToRestore]; + [databaseToRestore release], databaseToRestore = nil; } - - // Process events for a short time, allowing dialogs to be shown but waiting for - // the proxy. Capture how long this interface action took, standardising the - // overall time. - [[NSRunLoop currentRunLoop] runMode:NSModalPanelRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.25]]; - if (_elapsedSecondsSinceAbsoluteTime(loopIterationStart_t) < 0.25) { - usleep((useconds_t)(250000 - (1000000 * _elapsedSecondsSinceAbsoluteTime(loopIterationStart_t)))); - } - - // Extend the connection timeout by any interface time - if ([proxy state] == SPMySQLProxyWaitingForAuth) { - proxyWaitStart_t += mach_absolute_time() - loopIterationStart_t; + if (encodingToRestore) { + [self setEncoding:encodingToRestore]; + [self setEncodingUsesLatin1Transport:encodingUsesLatin1TransportToRestore]; + [encodingToRestore release], encodingToRestore = nil; } } + // If the connection failed and the connection is permitted to retry, + // then retry the reconnection. + else if (canRetry && ![[NSThread currentThread] isCancelled]) { - // Having in theory performed the proxy connect, update state - previousProxyState = [proxy state]; - proxyStateChangeNotificationsIgnored = NO; - } - - // Unlock the connection - [self _unlockConnection]; - - // If not using a proxy, or if the proxy successfully connected, trigger a connection - if (!proxy || [proxy state] == SPMySQLProxyConnected) { - [self _connect]; - } + // Default to attempting another reconnect + SPMySQLConnectionLostDecision connectionLostDecision = SPMySQLConnectionLostReconnect; - // If the reconnection succeeded, restore the connection state as appropriate - if (state == SPMySQLConnected && ![[NSThread currentThread] isCancelled]) { - reconnectSucceeded = YES; - if (databaseToRestore) { - [self selectDatabase:databaseToRestore]; - [databaseToRestore release], databaseToRestore = nil; - } - if (encodingToRestore) { - [self setEncoding:encodingToRestore]; - [self setEncodingUsesLatin1Transport:encodingUsesLatin1TransportToRestore]; - [encodingToRestore release], encodingToRestore = nil; - } - } - // If the connection failed and the connection is permitted to retry, - // then retry the reconnection. - else if (canRetry && ![[NSThread currentThread] isCancelled]) { + // If the delegate supports the decision process, ask it how to proceed + if (delegateSupportsConnectionLost) { + connectionLostDecision = [self _delegateDecisionForLostConnection]; + } + // Otherwise default to reconnect, but only a set number of times to prevent a runaway loop + else { + if (reconnectionRetryAttempts < 5) { + connectionLostDecision = SPMySQLConnectionLostReconnect; + } else { + connectionLostDecision = SPMySQLConnectionLostDisconnect; + } + reconnectionRetryAttempts++; + } - // Default to attempting another reconnect - SPMySQLConnectionLostDecision connectionLostDecision = SPMySQLConnectionLostReconnect; + switch (connectionLostDecision) { + case SPMySQLConnectionLostDisconnect: + [self _updateLastErrorMessage:NSLocalizedString(@"User triggered disconnection", @"User triggered disconnection")]; + userTriggeredDisconnect = YES; + break; - // If the delegate supports the decision process, ask it how to proceed - if (delegateSupportsConnectionLost) { - connectionLostDecision = [self _delegateDecisionForLostConnection]; - } - // Otherwise default to reconnect, but only a set number of times to prevent a runaway loop - else { - if (reconnectionRetryAttempts < 5) { - connectionLostDecision = SPMySQLConnectionLostReconnect; - } else { - connectionLostDecision = SPMySQLConnectionLostDisconnect; + // By default attempt a reconnect + default: + reconnectingThread = NULL; + reconnectSucceeded = [self _reconnectAllowingRetries:YES]; } - reconnectionRetryAttempts++; - } - - switch (connectionLostDecision) { - case SPMySQLConnectionLostDisconnect: - [self _updateLastErrorMessage:NSLocalizedString(@"User triggered disconnection", @"User triggered disconnection")]; - userTriggeredDisconnect = YES; - break; - - // By default attempt a reconnect - default: - reconnectingThread = NULL; - reconnectSucceeded = [self _reconnectAllowingRetries:YES]; } } reconnectingThread = NULL; - [reconnectionPool release]; return reconnectSucceeded; } @@ -923,14 +919,10 @@ asm(".desc ___crashreporter_info__, 0x10"); */ - (BOOL)_reconnectAfterBackgroundConnectionLoss { - NSAutoreleasePool *reconnectionPool = [[NSAutoreleasePool alloc] init]; - if (![self _reconnectAllowingRetries:NO]) { state = SPMySQLConnectionLostInBackground; } - [reconnectionPool release]; - return (state == SPMySQLConnected); } diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLFastStreamingResult.m b/Frameworks/SPMySQLFramework/Source/SPMySQLFastStreamingResult.m index c0131d0d..748ef2fb 100644 --- a/Frameworks/SPMySQLFramework/Source/SPMySQLFastStreamingResult.m +++ b/Frameworks/SPMySQLFramework/Source/SPMySQLFastStreamingResult.m @@ -322,80 +322,80 @@ typedef struct st_spmysqlstreamingrowdata { */ - (void)_downloadAllData { - NSAutoreleasePool *downloadPool = [[NSAutoreleasePool alloc] init]; - MYSQL_ROW theRow; - unsigned long *fieldLengths; - NSUInteger i, dataCopiedLength, rowDataLength; - SPMySQLStreamingRowData *newRowStore; - - [[NSThread currentThread] setName:@"SPMySQLFastStreamingResult data download thread"]; - - size_t sizeOfStreamingRowData = sizeof(SPMySQLStreamingRowData); - size_t sizeOfDataLengths = (size_t)(sizeof(unsigned long) * numberOfFields); - size_t sizeOfChar = sizeof(char); - - // Loop through the rows until the end of the data is reached - indicated via a NULL - while ( - (*isConnectedPtr)(parentConnection, isConnectedSelector) - && (theRow = mysql_fetch_row(resultSet)) - ) { - // Retrieve the lengths of the returned data - fieldLengths = mysql_fetch_lengths(resultSet); - rowDataLength = 0; - dataCopiedLength = 0; - for (i = 0; i < numberOfFields; i++) { - rowDataLength += fieldLengths[i]; - } + @autoreleasepool { + MYSQL_ROW theRow; + unsigned long *fieldLengths; + NSUInteger i, dataCopiedLength, rowDataLength; + SPMySQLStreamingRowData *newRowStore; + + [[NSThread currentThread] setName:@"SPMySQLFastStreamingResult data download thread"]; + + size_t sizeOfStreamingRowData = sizeof(SPMySQLStreamingRowData); + size_t sizeOfDataLengths = (size_t)(sizeof(unsigned long) * numberOfFields); + size_t sizeOfChar = sizeof(char); + + // Loop through the rows until the end of the data is reached - indicated via a NULL + while ( + (*isConnectedPtr)(parentConnection, isConnectedSelector) + && (theRow = mysql_fetch_row(resultSet)) + ) { + // Retrieve the lengths of the returned data + fieldLengths = mysql_fetch_lengths(resultSet); + rowDataLength = 0; + dataCopiedLength = 0; + for (i = 0; i < numberOfFields; i++) { + rowDataLength += fieldLengths[i]; + } - // Initialise memory for the row and set a NULL pointer for the next item - newRowStore = malloc(sizeOfStreamingRowData); - newRowStore->nextRow = NULL; - - // Set up the row data store - a char* - and copy in the data if there is any. - newRowStore->data = calloc(rowDataLength, sizeOfChar); - for (i = 0; i < numberOfFields; i++) { - if (theRow[i] != NULL) { - memcpy(newRowStore->data+dataCopiedLength, theRow[i], fieldLengths[i]); - dataCopiedLength += fieldLengths[i]; - } else { - fieldLengths[i] = NSNotFound; + // Initialise memory for the row and set a NULL pointer for the next item + newRowStore = malloc(sizeOfStreamingRowData); + newRowStore->nextRow = NULL; + + // Set up the row data store - a char* - and copy in the data if there is any. + newRowStore->data = calloc(rowDataLength, sizeOfChar); + for (i = 0; i < numberOfFields; i++) { + if (theRow[i] != NULL) { + memcpy(newRowStore->data+dataCopiedLength, theRow[i], fieldLengths[i]); + dataCopiedLength += fieldLengths[i]; + } else { + fieldLengths[i] = NSNotFound; + } } - } - // Set up the memory for, and copy in, the field lengths - newRowStore->dataLengths = memcpy(malloc(sizeOfDataLengths), fieldLengths, sizeOfDataLengths); + // Set up the memory for, and copy in, the field lengths + newRowStore->dataLengths = memcpy(malloc(sizeOfDataLengths), fieldLengths, sizeOfDataLengths); - // Lock the data mutex - pthread_mutex_lock(&dataLock); + // Lock the data mutex + pthread_mutex_lock(&dataLock); - // Add the newly allocated row to end of the storage linked list - if (lastDataStoreEntry) { - lastDataStoreEntry->nextRow = newRowStore; - } - lastDataStoreEntry = newRowStore; - if (!currentDataStoreEntry) currentDataStoreEntry = newRowStore; + // Add the newly allocated row to end of the storage linked list + if (lastDataStoreEntry) { + lastDataStoreEntry->nextRow = newRowStore; + } + lastDataStoreEntry = newRowStore; + if (!currentDataStoreEntry) currentDataStoreEntry = newRowStore; - // Update the downloaded row count - downloadedRowCount++; + // Update the downloaded row count + downloadedRowCount++; - // Unlock the mutex - pthread_mutex_unlock(&dataLock); - } + // Unlock the mutex + pthread_mutex_unlock(&dataLock); + } - // Update the connection's error statuses to reflect any errors during the content download - [parentConnection _updateLastErrorInfos]; + // Update the connection's error statuses to reflect any errors during the content download + [parentConnection _updateLastErrorInfos]; - // Unlock the parent connection now all data has been retrieved - [parentConnection _unlockConnection]; - connectionUnlocked = YES; + // Unlock the parent connection now all data has been retrieved + [parentConnection _unlockConnection]; + connectionUnlocked = YES; - // If the connection query may have been cancelled with a query kill, double-check connection - if ([parentConnection lastQueryWasCancelled] && [parentConnection serverMajorVersion] < 5) { - [parentConnection checkConnection]; - } + // If the connection query may have been cancelled with a query kill, double-check connection + if ([parentConnection lastQueryWasCancelled] && [parentConnection serverMajorVersion] < 5) { + [parentConnection checkConnection]; + } - dataDownloaded = YES; - [downloadPool drain]; + dataDownloaded = YES; + } } @end diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLResult Categories/Field Definitions.m b/Frameworks/SPMySQLFramework/Source/SPMySQLResult Categories/Field Definitions.m index cf7e8a1a..c478006f 100644 --- a/Frameworks/SPMySQLFramework/Source/SPMySQLResult Categories/Field Definitions.m +++ b/Frameworks/SPMySQLFramework/Source/SPMySQLResult Categories/Field Definitions.m @@ -77,7 +77,7 @@ const SPMySQLResultCharset SPMySQLCharsetMap[] = {30, "latin5", "latin5_turkish_ci", 1, 1}, {31, "latin1", "latin1_german2_ci", 1, 1}, {32, "armscii8", "armscii8_general_ci", 1, 1}, - {33, "utf8", "utf8_general_ci", 1, 3}, + {33, "utf8", "utf8_general_ci", 1, 3}, //mb3 {34, "cp1250", "cp1250_czech_cs", 1, 1}, {35, "ucs2", "ucs2_general_ci", 2, 2}, {36, "cp866", "cp866_general_ci", 1, 1}, diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLStreamingResultStore.m b/Frameworks/SPMySQLFramework/Source/SPMySQLStreamingResultStore.m index 1a0b6b25..fdabe2e2 100644 --- a/Frameworks/SPMySQLFramework/Source/SPMySQLStreamingResultStore.m +++ b/Frameworks/SPMySQLFramework/Source/SPMySQLStreamingResultStore.m @@ -672,148 +672,147 @@ static inline void SPMySQLStreamingResultStoreFreeRowData(SPMySQLStreamingResult */ - (void)_downloadAllData { - NSAutoreleasePool *downloadPool = [[NSAutoreleasePool alloc] init]; - MYSQL_ROW theRow; - unsigned long *fieldLengths; - NSUInteger i, dataCopiedLength, rowDataLength; - SPMySQLStreamingResultStoreRowData *newRowStore; - - [[NSThread currentThread] setName:@"SPMySQLStreamingResultStore data download thread"]; - - size_t sizeOfMetadata, lengthOfMetadata; - size_t lengthOfNullRecords = (size_t)(sizeof(BOOL) * numberOfFields); - size_t sizeOfChar = sizeof(char); - - // Loop through the rows until the end of the data is reached - indicated via a NULL - while ( - (*isConnectedPtr)(parentConnection, isConnectedSelector) - && (theRow = mysql_fetch_row(resultSet)) - ) { - // If the load has been cancelled, skip any processing - we're only interested - // in ensuring that mysql_fetch_row is called for all rows. - if (loadCancelled) { - continue; - } + @autoreleasepool { + MYSQL_ROW theRow; + unsigned long *fieldLengths; + NSUInteger i, dataCopiedLength, rowDataLength; + SPMySQLStreamingResultStoreRowData *newRowStore; + + [[NSThread currentThread] setName:@"SPMySQLStreamingResultStore data download thread"]; + + size_t sizeOfMetadata, lengthOfMetadata; + size_t lengthOfNullRecords = (size_t)(sizeof(BOOL) * numberOfFields); + size_t sizeOfChar = sizeof(char); + + // Loop through the rows until the end of the data is reached - indicated via a NULL + while ( + (*isConnectedPtr)(parentConnection, isConnectedSelector) + && (theRow = mysql_fetch_row(resultSet)) + ) { + // If the load has been cancelled, skip any processing - we're only interested + // in ensuring that mysql_fetch_row is called for all rows. + if (loadCancelled) { + continue; + } - // The row store is a single block of memory. It's made up of four blocks of data: - // Firstly, a single char containing the type of data used to store positions. - // Secondly, a series of those types recording the *end position* of each field - // Thirdly, a series of BOOLs recording whether the fields are NULLS - which can't just be from length - // Finally, a char sequence comprising the actual cell data, which can be looked up by position/length. - - // Retrieve the lengths of the returned data, and calculate the overall length of data - fieldLengths = mysql_fetch_lengths(resultSet); - rowDataLength = 0; - for (i = 0; i < numberOfFields; i++) { - rowDataLength += fieldLengths[i]; - } + // The row store is a single block of memory. It's made up of four blocks of data: + // Firstly, a single char containing the type of data used to store positions. + // Secondly, a series of those types recording the *end position* of each field + // Thirdly, a series of BOOLs recording whether the fields are NULLS - which can't just be from length + // Finally, a char sequence comprising the actual cell data, which can be looked up by position/length. - // Depending on the length of the row, vary the metadata size appropriately. This - // makes defining the data processing much lengthier, but is worth it to reduce the - // overhead for small rows. - if (rowDataLength <= UCHAR_MAX) { - sizeOfMetadata = SPMySQLStoreMetadataAsChar; - } else if (rowDataLength <= USHRT_MAX) { - sizeOfMetadata = SPMySQLStoreMetadataAsShort; - } else { - sizeOfMetadata = SPMySQLStoreMetadataAsLong; - } - lengthOfMetadata = sizeOfMetadata * numberOfFields; + // Retrieve the lengths of the returned data, and calculate the overall length of data + fieldLengths = mysql_fetch_lengths(resultSet); + rowDataLength = 0; + for (i = 0; i < numberOfFields; i++) { + rowDataLength += fieldLengths[i]; + } - // Allocate the memory for the row and set the type marker - newRowStore = malloc_zone_malloc(storageMallocZone, 1 + lengthOfMetadata + lengthOfNullRecords + (rowDataLength * sizeOfChar)); - newRowStore[0] = sizeOfMetadata; + // Depending on the length of the row, vary the metadata size appropriately. This + // makes defining the data processing much lengthier, but is worth it to reduce the + // overhead for small rows. + if (rowDataLength <= UCHAR_MAX) { + sizeOfMetadata = SPMySQLStoreMetadataAsChar; + } else if (rowDataLength <= USHRT_MAX) { + sizeOfMetadata = SPMySQLStoreMetadataAsShort; + } else { + sizeOfMetadata = SPMySQLStoreMetadataAsLong; + } + lengthOfMetadata = sizeOfMetadata * numberOfFields; + + // Allocate the memory for the row and set the type marker + newRowStore = malloc_zone_malloc(storageMallocZone, 1 + lengthOfMetadata + lengthOfNullRecords + (rowDataLength * sizeOfChar)); + newRowStore[0] = sizeOfMetadata; + + // Set the data end positions. Manually unroll the logic for the different cases; messy + // but again worth the large memory savings for smaller rows + rowDataLength = 0; + switch (sizeOfMetadata) { + case SPMySQLStoreMetadataAsLong: + for (i = 0; i < numberOfFields; i++) { + rowDataLength += fieldLengths[i]; + ((unsigned long *)(newRowStore + 1))[i] = rowDataLength; + ((BOOL *)(newRowStore + 1 + lengthOfMetadata))[i] = (theRow[i] == NULL); + } + break; + case SPMySQLStoreMetadataAsShort: + for (i = 0; i < numberOfFields; i++) { + rowDataLength += fieldLengths[i]; + ((unsigned short *)(newRowStore + 1))[i] = rowDataLength; + ((BOOL *)(newRowStore + 1 + lengthOfMetadata))[i] = (theRow[i] == NULL); + } + break; + case SPMySQLStoreMetadataAsChar: + for (i = 0; i < numberOfFields; i++) { + rowDataLength += fieldLengths[i]; + ((unsigned char *)(newRowStore + 1))[i] = rowDataLength; + ((BOOL *)(newRowStore + 1 + lengthOfMetadata))[i] = (theRow[i] == NULL); + } + break; + } - // Set the data end positions. Manually unroll the logic for the different cases; messy - // but again worth the large memory savings for smaller rows - rowDataLength = 0; - switch (sizeOfMetadata) { - case SPMySQLStoreMetadataAsLong: - for (i = 0; i < numberOfFields; i++) { - rowDataLength += fieldLengths[i]; - ((unsigned long *)(newRowStore + 1))[i] = rowDataLength; - ((BOOL *)(newRowStore + 1 + lengthOfMetadata))[i] = (theRow[i] == NULL); - } - break; - case SPMySQLStoreMetadataAsShort: - for (i = 0; i < numberOfFields; i++) { - rowDataLength += fieldLengths[i]; - ((unsigned short *)(newRowStore + 1))[i] = rowDataLength; - ((BOOL *)(newRowStore + 1 + lengthOfMetadata))[i] = (theRow[i] == NULL); - } - break; - case SPMySQLStoreMetadataAsChar: + // If the row has content, copy it in + if (rowDataLength) { + dataCopiedLength = 1 + lengthOfMetadata + lengthOfNullRecords; for (i = 0; i < numberOfFields; i++) { - rowDataLength += fieldLengths[i]; - ((unsigned char *)(newRowStore + 1))[i] = rowDataLength; - ((BOOL *)(newRowStore + 1 + lengthOfMetadata))[i] = (theRow[i] == NULL); - } - break; - } - - // If the row has content, copy it in - if (rowDataLength) { - dataCopiedLength = 1 + lengthOfMetadata + lengthOfNullRecords; - for (i = 0; i < numberOfFields; i++) { - if (theRow[i] != NULL) { - memcpy(newRowStore + dataCopiedLength, theRow[i], fieldLengths[i]); - dataCopiedLength += fieldLengths[i]; + if (theRow[i] != NULL) { + memcpy(newRowStore + dataCopiedLength, theRow[i], fieldLengths[i]); + dataCopiedLength += fieldLengths[i]; + } } } - } - // Lock the data mutex - pthread_mutex_lock(&dataLock); + // Lock the data mutex + pthread_mutex_lock(&dataLock); - // Ensure that sufficient capacity is available - SPMySQLStreamingResultStoreEnsureCapacityForAdditionalRowCount(self, 1); + // Ensure that sufficient capacity is available + SPMySQLStreamingResultStoreEnsureCapacityForAdditionalRowCount(self, 1); - // Add the newly allocated row to the storage - if (rowDownloadIterator < numberOfRows) { - SPMySQLStreamingResultStoreFreeRowData(dataStorage[rowDownloadIterator]); - } - dataStorage[rowDownloadIterator] = newRowStore; - rowDownloadIterator++; + // Add the newly allocated row to the storage + if (rowDownloadIterator < numberOfRows) { + SPMySQLStreamingResultStoreFreeRowData(dataStorage[rowDownloadIterator]); + } + dataStorage[rowDownloadIterator] = newRowStore; + rowDownloadIterator++; - // Update the total row count if exceeded - if (rowDownloadIterator > numberOfRows) { - numberOfRows++; - } + // Update the total row count if exceeded + if (rowDownloadIterator > numberOfRows) { + numberOfRows++; + } - // Unlock the mutex - pthread_mutex_unlock(&dataLock); - } + // Unlock the mutex + pthread_mutex_unlock(&dataLock); + } - // Update the total number of rows in the result set now download - // is complete, freeing extra rows from a previous result set - if (numberOfRows > rowDownloadIterator) { - pthread_mutex_lock(&dataLock); - while (numberOfRows > rowDownloadIterator) { - SPMySQLStreamingResultStoreFreeRowData(dataStorage[--numberOfRows]); + // Update the total number of rows in the result set now download + // is complete, freeing extra rows from a previous result set + if (numberOfRows > rowDownloadIterator) { + pthread_mutex_lock(&dataLock); + while (numberOfRows > rowDownloadIterator) { + SPMySQLStreamingResultStoreFreeRowData(dataStorage[--numberOfRows]); + } + pthread_mutex_unlock(&dataLock); } - pthread_mutex_unlock(&dataLock); - } - // Update the connection's error statuses to reflect any errors during the content download - [parentConnection _updateLastErrorInfos]; + // Update the connection's error statuses to reflect any errors during the content download + [parentConnection _updateLastErrorInfos]; - // Unlock the parent connection now all data has been retrieved - [parentConnection _unlockConnection]; - connectionUnlocked = YES; + // Unlock the parent connection now all data has been retrieved + [parentConnection _unlockConnection]; + connectionUnlocked = YES; - // If the connection query may have been cancelled with a query kill, double-check connection - if ([parentConnection lastQueryWasCancelled] && [parentConnection serverMajorVersion] < 5) { - [parentConnection checkConnection]; - } + // If the connection query may have been cancelled with a query kill, double-check connection + if ([parentConnection lastQueryWasCancelled] && [parentConnection serverMajorVersion] < 5) { + [parentConnection checkConnection]; + } - dataDownloaded = YES; + dataDownloaded = YES; - // Inform the delegate the download was completed - if ([delegate respondsToSelector:@selector(resultStoreDidFinishLoadingData:)]) { - [delegate resultStoreDidFinishLoadingData:self]; + // Inform the delegate the download was completed + if ([delegate respondsToSelector:@selector(resultStoreDidFinishLoadingData:)]) { + [delegate resultStoreDidFinishLoadingData:self]; + } } - - [downloadPool drain]; } /** -- cgit v1.2.3