aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m360
1 files changed, 177 insertions, 183 deletions
diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m b/Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m
index 63353056..e51785f8 100644
--- a/Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m
+++ b/Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m
@@ -60,8 +60,7 @@
*/
- (id)initWithMySQLPtr:(MYSQL *)mySQLPtr encoding:(NSStringEncoding)theEncoding timeZone:(NSTimeZone *)theTimeZone connection:(MCPConnection *)theConnection
{
- return [self initWithMySQLPtr:mySQLPtr encoding:theEncoding timeZone:theTimeZone connection:theConnection withFullStreaming:NO];
-
+ return [self initWithMySQLPtr:mySQLPtr encoding:theEncoding timeZone:theTimeZone connection:theConnection withFullStreaming:NO];
}
/**
@@ -70,64 +69,64 @@
*/
- (id)initWithMySQLPtr:(MYSQL *)mySQLPtr encoding:(NSStringEncoding)theEncoding timeZone:(NSTimeZone *)theTimeZone connection:(MCPConnection *)theConnection withFullStreaming:(BOOL)useFullStreaming
{
- if ((self = [super init])) {
- mEncoding = theEncoding;
- mTimeZone = [theTimeZone retain];
- parentConnection = theConnection;
- fullyStreaming = useFullStreaming;
-
- if (mResult) {
- mysql_free_result(mResult);
- mResult = NULL;
- }
-
- if (mNames) {
- [mNames release];
- mNames = NULL;
- }
-
- mResult = mysql_use_result(mySQLPtr);
-
- if (mResult) {
- mNumOfFields = mysql_num_fields(mResult);
- fieldDefinitions = mysql_fetch_fields(mResult);
- } else {
- mNumOfFields = 0;
- }
+ if ((self = [super init])) {
+ mEncoding = theEncoding;
+ mTimeZone = [theTimeZone retain];
+ parentConnection = theConnection;
+ fullyStreaming = useFullStreaming;
+
+ if (mResult) {
+ mysql_free_result(mResult);
+ mResult = NULL;
+ }
+
+ if (mNames) {
+ [mNames release];
+ mNames = NULL;
+ }
+
+ mResult = mysql_use_result(mySQLPtr);
+
+ if (mResult) {
+ mNumOfFields = mysql_num_fields(mResult);
+ fieldDefinitions = mysql_fetch_fields(mResult);
+ } else {
+ mNumOfFields = 0;
+ }
// If the result is opened in download-data-fast safe mode, set up the additional variables
// and threads required.
- if (!fullyStreaming) {
+ if (!fullyStreaming) {
dataDownloaded = NO;
dataFreed = NO;
- localDataStore = NULL;
+ localDataStore = NULL;
currentDataStoreEntry = NULL;
- localDataStoreLastEntry = NULL;
- localDataRows = 0;
- localDataAllocated = 0;
- downloadedRowCount = 0;
- processedRowCount = 0;
+ localDataStoreLastEntry = NULL;
+ localDataRows = 0;
+ localDataAllocated = 0;
+ downloadedRowCount = 0;
+ processedRowCount = 0;
freedRowCount = 0;
- // Start the data download thread
- [NSThread detachNewThreadSelector:@selector(_downloadAllData) toTarget:self withObject:nil];
-
+ // Start the data download thread
+ [NSThread detachNewThreadSelector:@selector(_downloadAllData) toTarget:self withObject:nil];
+
// Start the data freeing thread
[NSThread detachNewThreadSelector:@selector(_freeAllDataWhenDone) toTarget:self withObject:nil];
- }
- }
-
- return self;
+ }
+ }
+
+ return self;
}
/**
* Deallocate the result and unlock the parent connection for further use
*/
-- (void) dealloc
+ - (void) dealloc
{
- [parentConnection unlockConnection];
-
- [super dealloc];
+ [parentConnection unlockConnection];
+
+ [super dealloc];
}
#pragma mark -
@@ -139,49 +138,49 @@
*/
- (NSArray *)fetchNextRowAsArray
{
- MYSQL_ROW theRow;
+ MYSQL_ROW theRow;
char *theRowData;
- unsigned long *fieldLengths;
- int i, copiedDataLength;
- NSMutableArray *returnArray;
+ unsigned long *fieldLengths;
+ int i, copiedDataLength;
+ NSMutableArray *returnArray;
- // Retrieve the next row according to the mode this result set is in.
+ // Retrieve the next row according to the mode this result set is in.
// If fully streaming, retrieve the MYSQL_ROW
- if (fullyStreaming) {
- theRow = mysql_fetch_row(mResult);
+ if (fullyStreaming) {
+ theRow = mysql_fetch_row(mResult);
- // If no data was returned, we're at the end of the result set - return nil.
- if (theRow == NULL) return nil;
+ // If no data was returned, we're at the end of the result set - return nil.
+ if (theRow == NULL) return nil;
- // Retrieve the lengths of the returned data
- fieldLengths = mysql_fetch_lengths(mResult);
+ // Retrieve the lengths of the returned data
+ fieldLengths = mysql_fetch_lengths(mResult);
// If in cached-streaming/fast download mode, get a reference to the data for the current row
- } else {
+ } else {
copiedDataLength = 0;
-
- // Check to see whether we need to wait for the data to be availabe
+
+ // Check to see whether we need to wait for the data to be availabe
// - if so, wait 1ms before checking again
- while (!dataDownloaded && processedRowCount == downloadedRowCount) {
- usleep(1000);
- }
+ while (!dataDownloaded && processedRowCount == downloadedRowCount) {
+ usleep(1000);
+ }
- // If all rows have been processed, we're at the end of the result set - return nil
+ // If all rows have been processed, we're at the end of the result set - return nil
// once all memory has been freed
- if (processedRowCount == downloadedRowCount) {
+ if (processedRowCount == downloadedRowCount) {
while (!dataFreed) usleep(1000);
return nil;
}
- // Retrieve a reference to the data and the associated lengths
- theRowData = currentDataStoreEntry->data;
- fieldLengths = currentDataStoreEntry->dataLengths;
- }
+ // Retrieve a reference to the data and the associated lengths
+ theRowData = currentDataStoreEntry->data;
+ fieldLengths = currentDataStoreEntry->dataLengths;
+ }
- // Initialise the array to return
- returnArray = [NSMutableArray arrayWithCapacity:mNumOfFields];
- for (i = 0; i < mNumOfFields; i++) {
- id cellData = nil;
+ // Initialise the array to return
+ returnArray = [NSMutableArray arrayWithCapacity:mNumOfFields];
+ for (i = 0; i < mNumOfFields; i++) {
+ id cellData = nil;
char *theData;
// In fully streaming mode, copy across the data for the MYSQL_ROW
@@ -193,7 +192,7 @@
memcpy(theData, theRow[i], fieldLengths[i]);
theData[fieldLengths[i]] = '\0';
}
-
+
// In cached-streaming mode, use a reference to the downloaded data
} else {
if (fieldLengths[i] == NSNotFound) {
@@ -204,98 +203,97 @@
}
}
- // If the data hasn't already been detected as NULL - in which case it will have been
+ // If the data hasn't already been detected as NULL - in which case it will have been
// set to NSNull - process the data by type
- if (cellData == nil) {
-
- switch (fieldDefinitions[i].type) {
- case FIELD_TYPE_TINY:
- case FIELD_TYPE_SHORT:
- case FIELD_TYPE_INT24:
- case FIELD_TYPE_LONG:
- case FIELD_TYPE_LONGLONG:
- case FIELD_TYPE_DECIMAL:
- case FIELD_TYPE_NEWDECIMAL:
- case FIELD_TYPE_FLOAT:
- case FIELD_TYPE_DOUBLE:
- case FIELD_TYPE_TIMESTAMP:
- case FIELD_TYPE_DATE:
- case FIELD_TYPE_TIME:
- case FIELD_TYPE_DATETIME:
- case FIELD_TYPE_YEAR:
- case FIELD_TYPE_VAR_STRING:
- case FIELD_TYPE_STRING:
- case FIELD_TYPE_SET:
- case FIELD_TYPE_ENUM:
- case FIELD_TYPE_NEWDATE: // Don't know what the format for this type is...
- cellData = [NSString stringWithCString:theData encoding:mEncoding];
- break;
-
- case FIELD_TYPE_BIT:
- cellData = [NSString stringWithFormat:@"%u", theData[0]];
- break;
-
- case FIELD_TYPE_TINY_BLOB:
- case FIELD_TYPE_BLOB:
- case FIELD_TYPE_MEDIUM_BLOB:
- case FIELD_TYPE_LONG_BLOB:
-
- // For binary data, return the data
- if (fieldDefinitions[i].flags & BINARY_FLAG) {
- cellData = [NSData dataWithBytes:theData length:fieldLengths[i]];
-
- // For string data, convert to text
- } else {
- cellData = [[NSString alloc] initWithBytes:theData length:fieldLengths[i] encoding:mEncoding];
- if (cellData) [cellData autorelease];
- }
- break;
-
- case FIELD_TYPE_NULL:
- cellData = [NSNull null];
- break;
-
- default:
- NSLog(@"in fetchNextRowAsArray : Unknown type : %d for column %d, sending back a NSData object", (int)fieldDefinitions[i].type, (int)i);
- cellData = [NSData dataWithBytes:theData length:fieldLengths[i]];
- break;
- }
+ if (cellData == nil) {
+ switch (fieldDefinitions[i].type) {
+ case FIELD_TYPE_TINY:
+ case FIELD_TYPE_SHORT:
+ case FIELD_TYPE_INT24:
+ case FIELD_TYPE_LONG:
+ case FIELD_TYPE_LONGLONG:
+ case FIELD_TYPE_DECIMAL:
+ case FIELD_TYPE_NEWDECIMAL:
+ case FIELD_TYPE_FLOAT:
+ case FIELD_TYPE_DOUBLE:
+ case FIELD_TYPE_TIMESTAMP:
+ case FIELD_TYPE_DATE:
+ case FIELD_TYPE_TIME:
+ case FIELD_TYPE_DATETIME:
+ case FIELD_TYPE_YEAR:
+ case FIELD_TYPE_VAR_STRING:
+ case FIELD_TYPE_STRING:
+ case FIELD_TYPE_SET:
+ case FIELD_TYPE_ENUM:
+ case FIELD_TYPE_NEWDATE: // Don't know what the format for this type is...
+ cellData = [NSString stringWithCString:theData encoding:mEncoding];
+ break;
+
+ case FIELD_TYPE_BIT:
+ cellData = [NSString stringWithFormat:@"%u", theData[0]];
+ break;
+
+ case FIELD_TYPE_TINY_BLOB:
+ case FIELD_TYPE_BLOB:
+ case FIELD_TYPE_MEDIUM_BLOB:
+ case FIELD_TYPE_LONG_BLOB:
+
+ // For binary data, return the data
+ if (fieldDefinitions[i].flags & BINARY_FLAG) {
+ cellData = [NSData dataWithBytes:theData length:fieldLengths[i]];
+
+ // For string data, convert to text
+ } else {
+ cellData = [[NSString alloc] initWithBytes:theData length:fieldLengths[i] encoding:mEncoding];
+ if (cellData) [cellData autorelease];
+ }
+ break;
+
+ case FIELD_TYPE_NULL:
+ cellData = [NSNull null];
+ break;
+
+ default:
+ NSLog(@"in fetchNextRowAsArray : Unknown type : %d for column %d, sending back a NSData object", (int)fieldDefinitions[i].type, (int)i);
+ cellData = [NSData dataWithBytes:theData length:fieldLengths[i]];
+ break;
+ }
// Free the data if it was originally allocated
if (fullyStreaming) free(theData);
- // If a creator returned a nil object, replace with NSNull
- if (cellData == nil) cellData = [NSNull null];
- }
+ // If a creator returned a nil object, replace with NSNull
+ if (cellData == nil) cellData = [NSNull null];
+ }
- [returnArray insertObject:cellData atIndex:i];
- }
+ [returnArray insertObject:cellData atIndex:i];
+ }
// If in cached-streaming mode, update the current entry processed count
if (!fullyStreaming) {
- // Update the active-data pointer to the next item in the list, or set to NULL if no more items
+ // Update the active-data pointer to the next item in the list, or set to NULL if no more items
currentDataStoreEntry = currentDataStoreEntry->nextRow;
// Increment counter
- processedRowCount++;
+ processedRowCount++;
}
- return returnArray;
+ return returnArray;
}
#pragma mark -
#pragma mark Overrides for safety
-- (my_ulonglong) numOfRows
+- (my_ulonglong)numOfRows
{
- NSLog(@"numOfRows cannot be used with streaming results");
- return 0;
+ NSLog(@"numOfRows cannot be used with streaming results");
+ return 0;
}
-- (void) dataSeek:(my_ulonglong) row
+- (void)dataSeek:(my_ulonglong) row
{
- NSLog(@"dataSeek cannot be used with streaming results");
+ NSLog(@"dataSeek cannot be used with streaming results");
}
@end
@@ -305,65 +303,61 @@
/**
* Used internally to download results in a background thread
*/
-- (void) _downloadAllData
+ - (void)_downloadAllData
{
NSAutoreleasePool *downloadPool = [[NSAutoreleasePool alloc] init];
- MYSQL_ROW theRow;
- unsigned long *fieldLengths;
- int i, dataCopiedLength, rowDataLength;
- LOCAL_ROW_DATA *newRowStore;
+ MYSQL_ROW theRow;
+ unsigned long *fieldLengths;
+ int i, dataCopiedLength, rowDataLength;
+ LOCAL_ROW_DATA *newRowStore;
- size_t sizeOfLocalRowData = sizeof(LOCAL_ROW_DATA);
- size_t sizeOfDataLengths = (size_t)(sizeof(unsigned long) * mNumOfFields);
+ size_t sizeOfLocalRowData = sizeof(LOCAL_ROW_DATA);
+ size_t sizeOfDataLengths = (size_t)(sizeof(unsigned long) * mNumOfFields);
- // Loop through the rows until the end of the data is reached - indicated via a NULL
- while (theRow = mysql_fetch_row(mResult)) {
+ // Loop through the rows until the end of the data is reached - indicated via a NULL
+ while (theRow = mysql_fetch_row(mResult)) {
- // Retrieve the lengths of the returned data
- fieldLengths = mysql_fetch_lengths(mResult);
+ // Retrieve the lengths of the returned data
+ fieldLengths = mysql_fetch_lengths(mResult);
rowDataLength = 0;
dataCopiedLength = 0;
for (i = 0; i < mNumOfFields; i++)
rowDataLength += fieldLengths[i];
- // Initialise memory for the row and set a NULL pointer for the next item
- newRowStore = malloc(sizeOfLocalRowData);
- newRowStore->nextRow = NULL;
+ // Initialise memory for the row and set a NULL pointer for the next item
+ newRowStore = malloc(sizeOfLocalRowData);
+ newRowStore->nextRow = NULL;
// Set up the row data store - a char* - and copy in the data if there is any,
// using a null terminator for each field boundary for easier data processing later
- if (rowDataLength) {
- newRowStore->data = malloc(sizeof(char) * (rowDataLength + mNumOfFields));
- for (i = 0; i < mNumOfFields; i++) {
- if (theRow[i] != NULL) {
- memcpy(newRowStore->data+dataCopiedLength, theRow[i], fieldLengths[i]);
- newRowStore->data[dataCopiedLength+fieldLengths[i]] = '\0';
- dataCopiedLength += fieldLengths[i] + 1;
- } else {
- fieldLengths[i] = NSNotFound;
- }
+ newRowStore->data = malloc(sizeof(char) * (rowDataLength + mNumOfFields));
+ for (i = 0; i < mNumOfFields; i++) {
+ if (theRow[i] != NULL) {
+ memcpy(newRowStore->data+dataCopiedLength, theRow[i], fieldLengths[i]);
+ newRowStore->data[dataCopiedLength+fieldLengths[i]] = '\0';
+ dataCopiedLength += fieldLengths[i] + 1;
+ } else {
+ fieldLengths[i] = NSNotFound;
}
- } else {
- newRowStore->data = NULL;
}
-
+
// Set up and copy in the field lengths
newRowStore->dataLengths = memcpy(malloc(sizeOfDataLengths), fieldLengths, sizeOfDataLengths);
// Add the newly allocated row to end of the storage linked list
- if (localDataStore) {
- localDataStoreLastEntry->nextRow = newRowStore;
- } else {
- localDataStore = newRowStore;
- }
- localDataStoreLastEntry = newRowStore;
+ if (localDataStore) {
+ localDataStoreLastEntry->nextRow = newRowStore;
+ } else {
+ localDataStore = newRowStore;
+ }
+ localDataStoreLastEntry = newRowStore;
if (!currentDataStoreEntry) currentDataStoreEntry = newRowStore;
// Update the downloaded row count
- downloadedRowCount++;
- }
+ downloadedRowCount++;
+ }
- dataDownloaded = YES;
+ dataDownloaded = YES;
[downloadPool drain];
}
@@ -376,7 +370,7 @@
NSAutoreleasePool *dataFreeingPool = [[NSAutoreleasePool alloc] init];
while (!dataDownloaded || freedRowCount != downloadedRowCount) {
-
+
// If the freed row count matches the processed row count, wait before retrying
if (freedRowCount == processedRowCount) {
usleep(1000);
@@ -384,20 +378,20 @@
}
// Free a single item off the bottom of the list
- // Update the data pointer to the next item in the list, or set to NULL if no more items
- LOCAL_ROW_DATA *rowToRemove = localDataStore;
+ // Update the data pointer to the next item in the list, or set to NULL if no more items
+ LOCAL_ROW_DATA *rowToRemove = localDataStore;
localDataStore = localDataStore->nextRow;
// Free memory for the first row
- rowToRemove->nextRow = NULL;
- free(rowToRemove->dataLengths);
+ rowToRemove->nextRow = NULL;
+ free(rowToRemove->dataLengths);
if (rowToRemove->data != NULL) free(rowToRemove->data);
free(rowToRemove);
-
+
// Increment the counter
freedRowCount++;
}
-
+
dataFreed = YES;
[dataFreeingPool drain];
}