aboutsummaryrefslogtreecommitdiffstats
path: root/Frameworks/SPMySQLFramework/Source/SPMySQLFastStreamingResult.m
diff options
context:
space:
mode:
Diffstat (limited to 'Frameworks/SPMySQLFramework/Source/SPMySQLFastStreamingResult.m')
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLFastStreamingResult.m104
1 files changed, 46 insertions, 58 deletions
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLFastStreamingResult.m b/Frameworks/SPMySQLFramework/Source/SPMySQLFastStreamingResult.m
index f084dee0..8ba55134 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLFastStreamingResult.m
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLFastStreamingResult.m
@@ -32,8 +32,11 @@
#import "SPMySQLFastStreamingResult.h"
#import "SPMySQL Private APIs.h"
+#import "SPMySQLArrayAdditions.h"
#include <pthread.h>
+static id NSNullPointer;
+
/**
* This type of streaming result operates in a multithreaded fashion - a worker
* thread is set up to download the results as fast as possible in the background,
@@ -45,7 +48,7 @@
typedef struct st_spmysqlstreamingrowdata {
char *data;
- NSUInteger *dataLengths;
+ unsigned long *dataLengths;
struct st_spmysqlstreamingrowdata *nextRow;
} SPMySQLStreamingRowData;
@@ -62,6 +65,16 @@ typedef struct st_spmysqlstreamingrowdata {
#pragma mark -
/**
+ * In the one-off class initialisation, cache static variables
+ */
++ (void)initialize
+{
+
+ // Cached NSNull singleton reference
+ if (!NSNullPointer) NSNullPointer = [NSNull null];
+}
+
+/**
* Standard init method, constructing the SPMySQLStreamingResult around a MySQL
* result pointer and the encoding to use when working with the data.
* As opposed to SPMySQLResult, defaults to returning rows as arrays, as the result
@@ -137,9 +150,19 @@ typedef struct st_spmysqlstreamingrowdata {
{
NSUInteger copiedDataLength = 0;
char *theRowData;
- NSUInteger *fieldLengths;
+ unsigned long *fieldLengths;
id theReturnData;
+ // If the target type was unspecified, use the instance default
+ if (theType == SPMySQLResultRowAsDefault) theType = defaultRowReturnType;
+
+ // Set up the return data as appropriate
+ if (theType == SPMySQLResultRowAsArray) {
+ theReturnData = [NSMutableArray arrayWithCapacity:numberOfFields];
+ } else {
+ theReturnData = [NSMutableDictionary dictionaryWithCapacity:numberOfFields];
+ }
+
// Lock the data mutex for safe access of variables and counters
pthread_mutex_lock(&dataLock);
@@ -164,40 +187,32 @@ typedef struct st_spmysqlstreamingrowdata {
theRowData = currentDataStoreEntry->data;
fieldLengths = currentDataStoreEntry->dataLengths;
- // If the target type was unspecified, use the instance default
- if (theType == SPMySQLResultRowAsDefault) theType = defaultRowReturnType;
-
- // Set up the return data as appropriate
- if (theType == SPMySQLResultRowAsArray) {
- theReturnData = [NSMutableArray arrayWithCapacity:numberOfFields];
- } else {
- theReturnData = [NSMutableDictionary dictionaryWithCapacity:numberOfFields];
- }
-
// Convert each of the cells in the row in turn
+ unsigned long fieldLength;
+ id cellData;
+ char *rawCellData;
for (NSUInteger i = 0; i < numberOfFields; i++) {
- char *rawCellData;
- NSUInteger fieldLength = fieldLengths[i];
+ fieldLength = fieldLengths[i];
// If the length of this cell is NSNotFound, it's a null reference
if (fieldLength == NSNotFound) {
- rawCellData = NULL;
+ cellData = nil;
// Otherwise grab a reference to that data using pointer arithmetic
} else {
rawCellData = theRowData + copiedDataLength;
copiedDataLength += fieldLength;
- }
- // Convert to the correct object type
- id cellData = SPMySQLResultGetObject(self, rawCellData, fieldLength, fieldTypes[i], i);
+ // Convert to the correct object type
+ cellData = SPMySQLResultGetObject(self, rawCellData, fieldLength, fieldTypes[i], i);
+ }
// If object creation failed, display a null
- if (!cellData) cellData = [NSNull null];
+ if (!cellData) cellData = NSNullPointer;
// Add to the result array/dictionary
if (theType == SPMySQLResultRowAsArray) {
- [(NSMutableArray *)theReturnData addObject:cellData];
+ SPMySQLMutableArrayInsertObject(theReturnData, cellData, i);
} else {
[(NSMutableDictionary *)theReturnData setObject:cellData forKey:fieldNames[i]];
}
@@ -211,6 +226,7 @@ typedef struct st_spmysqlstreamingrowdata {
// Update the active-data pointer to the next item in the list (which may be NULL)
currentDataStoreEntry = currentDataStoreEntry->nextRow;
+ if (!currentDataStoreEntry) lastDataStoreEntry = NULL;
// Increment the processed counter and row index
processedRowCount++;
@@ -221,7 +237,6 @@ typedef struct st_spmysqlstreamingrowdata {
pthread_mutex_unlock(&dataLock);
// Free the memory for the processed row
- previousDataStoreEntry->nextRow = NULL;
free(previousDataStoreEntry->dataLengths);
if (previousDataStoreEntry->data != NULL) free(previousDataStoreEntry->data);
free(previousDataStoreEntry);
@@ -260,6 +275,7 @@ typedef struct st_spmysqlstreamingrowdata {
// Update the active-data pointer to the next item in the list (which may be NULL)
currentDataStoreEntry = currentDataStoreEntry->nextRow;
+ if (!currentDataStoreEntry) lastDataStoreEntry = NULL;
processedRowCount++;
currentRowIndex++;
@@ -269,7 +285,6 @@ typedef struct st_spmysqlstreamingrowdata {
pthread_mutex_unlock(&dataLock);
// Free the memory for the processed row
- previousDataStoreEntry->nextRow = NULL;
free(previousDataStoreEntry->dataLengths);
if (previousDataStoreEntry->data != NULL) free(previousDataStoreEntry->data);
free(previousDataStoreEntry);
@@ -287,47 +302,20 @@ typedef struct st_spmysqlstreamingrowdata {
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len
{
- // If all rows have already been processed, return 0 to stop iteration.
- if (dataDownloaded && processedRowCount == downloadedRowCount) return 0;
+ // To avoid lock issues, return one row at a time.
+ id nextRow = SPMySQLResultGetRow(self, SPMySQLResultRowAsDefault);
- // If the MySQL row pointer does not match the requested state, throw an exception
- if (state->state != currentRowIndex) {
- [NSException raise:NSRangeException format:@"SPMySQLFastStreamingResult results can only be accessed linearly"];
- }
-
- // Determine how many objects to return. Default to 128 items, or the number of items requested
- NSUInteger itemsToReturn = 128;
- if (len < 128) itemsToReturn = len;
-
- // If there are fewer items available in the downloaded-but-processed queue, limit to that
- if (downloadedRowCount - processedRowCount < itemsToReturn) {
- itemsToReturn = downloadedRowCount - processedRowCount;
- }
-
- // If no rows are available to be processed, wait for a single item to be readied.
- if (!itemsToReturn) itemsToReturn = 1;
+ // If no row was available, return 0 to stop iteration.
+ if (!nextRow) return 0;
- // Retrieve rows and add them to the result stack
- NSUInteger i, itemsRetrieved = 0;
- id eachRow;
- for (i = 0; i < itemsToReturn; i++) {
- eachRow = SPMySQLResultGetRow(self, SPMySQLResultRowAsDefault);
-
- // If nil was returned the end of the result resource has been reached
- if (!eachRow) {
- if (!itemsRetrieved) return 0;
- break;
- }
-
- stackbuf[i] = eachRow;
- itemsRetrieved++;
- }
+ // Otherwise, add the item to the buffer and return the appropriate state.
+ stackbuf[0] = nextRow;
- state->state += itemsRetrieved;
+ state->state += 1;
state->itemsPtr = stackbuf;
state->mutationsPtr = (unsigned long *)self;
- return itemsRetrieved;
+ return 1;
}
@end
@@ -349,7 +337,7 @@ typedef struct st_spmysqlstreamingrowdata {
SPMySQLStreamingRowData *newRowStore;
size_t sizeOfStreamingRowData = sizeof(SPMySQLStreamingRowData);
- size_t sizeOfDataLengths = (size_t)(sizeof(NSUInteger) * numberOfFields);
+ 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