aboutsummaryrefslogtreecommitdiffstats
path: root/Source/SPCustomQuery.m
diff options
context:
space:
mode:
Diffstat (limited to 'Source/SPCustomQuery.m')
-rw-r--r--Source/SPCustomQuery.m189
1 files changed, 84 insertions, 105 deletions
diff --git a/Source/SPCustomQuery.m b/Source/SPCustomQuery.m
index 686e700b..27fc11c6 100644
--- a/Source/SPCustomQuery.m
+++ b/Source/SPCustomQuery.m
@@ -69,8 +69,7 @@
@interface SPCustomQuery (PrivateAPI)
-- (id)_resultDataItemAtRow:(NSInteger)row columnIndex:(NSUInteger)column;
-- (id)_convertResultDataValueToDisplayableRepresentation:(id)value whilePreservingNULLs:(BOOL)preserveNULLs truncateDataFields:(BOOL)truncate;
+- (id)_resultDataItemAtRow:(NSInteger)row columnIndex:(NSUInteger)column preserveNULLs:(BOOL)preserveNULLs asPreview:(BOOL)asPreview;
+ (NSString *)linkToHelpTopic:(NSString *)aTopic;
@end
@@ -581,7 +580,7 @@
{
NSAutoreleasePool *queryRunningPool = [[NSAutoreleasePool alloc] init];
NSArray *queries = [taskArguments objectForKey:@"queries"];
- SPMySQLFastStreamingResult *streamingResult = nil;
+ SPMySQLStreamingResultStore *resultStore = nil;
NSMutableString *errors = [NSMutableString string];
SEL callbackMethod = NULL;
NSString *taskButtonString;
@@ -652,8 +651,8 @@
[tempQueries addObject:query];
// Run the query, timing execution (note this also includes network and overhead)
- streamingResult = [[mySQLConnection streamingQueryString:query] retain];
- executionTime += [streamingResult queryExecutionTime];
+ resultStore = [[mySQLConnection resultStoreFromQueryString:query] retain];
+ executionTime += [resultStore queryExecutionTime];
totalQueriesRun++;
// If this is the last query, retrieve and store the result; otherwise,
@@ -662,7 +661,7 @@
// Retrieve and cache the column definitions for the result array
if (cqColumnDefinition) [cqColumnDefinition release];
- cqColumnDefinition = [[streamingResult fieldDefinitions] retain];
+ cqColumnDefinition = [[resultStore fieldDefinitions] retain];
if(!reloadingExistingResult) {
[[self onMainThread] updateTableView];
@@ -683,18 +682,18 @@
// Init copyTable with necessary information for copying selected rows as SQL INSERT
[customQueryView setTableInstance:self withTableData:resultData withColumns:cqColumnDefinition withTableName:resultTableName withConnection:mySQLConnection];
- [self processResultIntoDataStorage:streamingResult];
+ [self updateResultStore:resultStore];
} else {
- [streamingResult cancelResultLoad];
+ [resultStore cancelResultLoad];
}
// Record any affected rows
if ( [mySQLConnection rowsAffectedByLastQuery] != (unsigned long long)~0 )
totalAffectedRows += (NSUInteger)[mySQLConnection rowsAffectedByLastQuery];
- else if ( [streamingResult numberOfRows] )
- totalAffectedRows += (NSUInteger)[streamingResult numberOfRows];
+ else if ( [resultStore numberOfRows] )
+ totalAffectedRows += (NSUInteger)[resultStore numberOfRows];
- [streamingResult release];
+ [resultStore release];
// Store any error messages
if ([mySQLConnection queryErrored] || [mySQLConnection lastQueryWasCancelled]) {
@@ -804,8 +803,8 @@
// Perform empty query if no query is given
if ( !queryCount ) {
- streamingResult = [mySQLConnection streamingQueryString:@""];
- [streamingResult cancelResultLoad];
+ resultStore = [mySQLConnection resultStoreFromQueryString:@""];
+ [resultStore cancelResultLoad];
[errors setString:[mySQLConnection lastErrorMessage]];
}
@@ -944,55 +943,38 @@
}
/**
- * Processes a supplied streaming result set, loading it into the data array.
+ * Processes a supplied streaming result store, monitoring the load and updating
+ * the data displayed during download.
*/
-- (void)processResultIntoDataStorage:(SPMySQLFastStreamingResult *)theResult
+- (void)updateResultStore:(SPMySQLStreamingResultStore *)theResultStore
{
- NSAutoreleasePool *dataLoadingPool;
// Remove all items from the table
resultDataCount = 0;
[customQueryView performSelectorOnMainThread:@selector(noteNumberOfRowsChanged) withObject:nil waitUntilDone:YES];
pthread_mutex_lock(&resultDataLock);
[resultData removeAllRows];
+
+ // Add the new store
+ [resultData setDataStorage:theResultStore updatingExisting:NO];
pthread_mutex_unlock(&resultDataLock);
- // Set the column count on the data store before setting up anything else -
- // ensures that SPDataStorage is set up for timer-driven data loads
- [resultData setColumnCount:[theResult numberOfFields]];
+ // Start the data downloading
+ [theResultStore startDownload];
- // Set up the table updates timer
+ // Set up the table updates timer and wait for it to notify this thread about completion
[[self onMainThread] initQueryLoadTimer];
- // Set up an autorelease pool for row processing
- dataLoadingPool = [[NSAutoreleasePool alloc] init];
-
- // Loop through the result rows as they become available
- for (NSArray *eachRow in theResult) {
-
- pthread_mutex_lock(&resultDataLock);
- SPDataStorageAddRow(resultData, eachRow);
- resultDataCount++;
- pthread_mutex_unlock(&resultDataLock);
-
- // Drain and reset the autorelease pool every ~1024 rows
- if (!(resultDataCount % 1024)) {
- [dataLoadingPool drain];
- dataLoadingPool = [[NSAutoreleasePool alloc] init];
- }
+ [resultLoadingCondition lock];
+ while (![resultData dataDownloaded]) {
+ [resultLoadingCondition waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.05]];
}
-
- // Clean up the interface update timer
- [[self onMainThread] clearQueryLoadTimer];
+ [resultLoadingCondition unlock];
// If the final column autoresize wasn't performed, perform it
if (queryLoadLastRowCount < 200) [[self onMainThread] autosizeColumns];
[customQueryView performSelectorOnMainThread:@selector(noteNumberOfRowsChanged) withObject:nil waitUntilDone:NO];
- [customQueryView setNeedsDisplay:YES];
-
- // Clean up the autorelease pool
- [dataLoadingPool drain];
}
/**
@@ -1483,11 +1465,20 @@
*/
- (void) queryLoadUpdate:(NSTimer *)theTimer
{
+ resultDataCount = [resultData count];
+
if (queryLoadTimerTicksSinceLastUpdate < queryLoadInterfaceUpdateInterval) {
queryLoadTimerTicksSinceLastUpdate++;
return;
}
+ if ([resultData dataDownloaded]) {
+ [resultLoadingCondition lock];
+ [resultLoadingCondition signal];
+ [self clearQueryLoadTimer];
+ [resultLoadingCondition unlock];
+ }
+
// Check whether a table update is required, based on whether new rows are
// available to display.
if (resultDataCount == (NSInteger)queryLoadLastRowCount) {
@@ -1496,7 +1487,6 @@
// Update the table display
[customQueryView noteNumberOfRowsChanged];
- if (!queryLoadLastRowCount) [customQueryView setNeedsDisplay:YES];
// Update column widths in two cases: on very first rows displayed, and once
// more than 200 rows are present.
@@ -1574,9 +1564,7 @@
while ((tableColumn = [enumerator nextObject]))
{
- id value = [self _resultDataItemAtRow:i columnIndex:[[tableColumn identifier] integerValue]];
-
- [tempRow addObject:[self _convertResultDataValueToDisplayableRepresentation:value whilePreservingNULLs:includeNULLs truncateDataFields:truncate]];
+ [tempRow addObject:[self _resultDataItemAtRow:i columnIndex:[[tableColumn identifier] integerValue] preserveNULLs:includeNULLs asPreview:truncate]];
}
[currentResult addObject:[NSArray arrayWithArray:tempRow]];
@@ -1682,7 +1670,6 @@
[dataCell setLineBreakMode:NSLineBreakByTruncatingTail];
[dataCell setFormatter:[[SPDataCellFormatter new] autorelease]];
- [[dataCell formatter] setDisplayLimit:150];
// Set field length limit if field is a varchar to match varchar length
if ([[columnDefinition objectForKey:@"typegrouping"] isEqualToString:@"string"]
@@ -2045,7 +2032,7 @@
} else {
#endif
// otherwise, just update the data in the data storage
- SPDataStorageReplaceObjectAtRowAndColumn(resultData, rowIndex, [[aTableColumn identifier] intValue], anObject);
+ [resultData replaceObjectInRow:rowIndex column:[[aTableColumn identifier] intValue] withObject:anObject];
#ifndef SP_CODA
}
#endif
@@ -2075,35 +2062,34 @@
{
if (aTableView == customQueryView) {
+ if (![cell respondsToSelector:@selector(setTextColor:)]) {
+ return;
+ }
+
// For NULL cell's display the user's NULL value placeholder in grey to easily distinguish it from other values
- if ([cell respondsToSelector:@selector(setTextColor:)]) {
-
- id value = nil;
- NSUInteger columnIndex = [[aTableColumn identifier] integerValue];
-
- // While the table is being loaded, additional validation is required - data
- // locks must be used to avoid crashes, and indexes higher than the available
- // rows or columns may be requested. Use gray to show loading in these cases.
- if (isWorking) {
- pthread_mutex_lock(&resultDataLock);
-
- if (rowIndex < resultDataCount && columnIndex < [resultData columnCount]) {
- value = SPDataStorageObjectAtRowAndColumn(resultData, rowIndex, columnIndex);
- }
-
- pthread_mutex_unlock(&resultDataLock);
+ BOOL showCellAsGray = NO;
- if (!value) {
- [cell setTextColor:[NSColor lightGrayColor]];
- return;
- }
- }
- else {
- value = SPDataStorageObjectAtRowAndColumn(resultData, rowIndex, columnIndex);
+ NSUInteger columnIndex = [[aTableColumn identifier] integerValue];
+
+ // While the table is being loaded, additional validation is required - data
+ // locks must be used to avoid crashes, and indexes higher than the available
+ // rows or columns may be requested. Use gray to show loading in these cases.
+ if (isWorking) {
+ pthread_mutex_lock(&resultDataLock);
+
+ if (rowIndex < resultDataCount && columnIndex < [resultData columnCount]) {
+ showCellAsGray = [resultData cellIsNullOrUnloadedAtRow:rowIndex column:columnIndex];
+ } else {
+ showCellAsGray = YES;
}
- [cell setTextColor:[value isNSNull] ? [NSColor lightGrayColor] : [NSColor blackColor]];
+ pthread_mutex_unlock(&resultDataLock);
}
+ else {
+ showCellAsGray = [resultData cellIsNullOrUnloadedAtRow:rowIndex column:columnIndex];
+ }
+
+ [cell setTextColor:showCellAsGray ? [NSColor lightGrayColor] : [NSColor blackColor]];
}
}
@@ -2113,8 +2099,7 @@
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex
{
if (aTableView == customQueryView) {
-
- return [self _convertResultDataValueToDisplayableRepresentation:[self _resultDataItemAtRow:rowIndex columnIndex:[[tableColumn identifier] integerValue]] whilePreservingNULLs:NO truncateDataFields:YES];
+ return [self _resultDataItemAtRow:rowIndex columnIndex:[[tableColumn identifier] integerValue] preserveNULLs:NO asPreview:YES];
}
return @"";
@@ -3768,6 +3753,7 @@
runPrimaryActionButtonAsSelection = nil;
queryLoadTimer = nil;
+ resultLoadingCondition = [NSCondition new];
prefs = [NSUserDefaults standardUserDefaults];
@@ -3988,12 +3974,13 @@
/**
* Retrieves the value from the underlying data storage at the supplied row and column indices.
*
- * @param row The row index
- * @param column The column index
+ * @param row The row index
+ * @param column The column index
+ * @param preserveNULLs Whether t
*
* @return The value from the data storage
*/
-- (id)_resultDataItemAtRow:(NSInteger)row columnIndex:(NSUInteger)column
+- (id)_resultDataItemAtRow:(NSInteger)row columnIndex:(NSUInteger)column preserveNULLs:(BOOL)preserveNULLs asPreview:(BOOL)asPreview;
{
id value = nil;
@@ -4005,7 +3992,11 @@
pthread_mutex_lock(&resultDataLock);
if (row < resultDataCount && column < [resultData columnCount]) {
- value = [[SPDataStorageObjectAtRowAndColumn(resultData, row, column) copy] autorelease];
+ if (asPreview) {
+ value = SPDataStoragePreviewAtRowAndColumn(resultData, row, column, 150);
+ } else {
+ value = SPDataStorageObjectAtRowAndColumn(resultData, row, column);
+ }
}
pthread_mutex_unlock(&resultDataLock);
@@ -4013,36 +4004,23 @@
if (!value) value = @"...";
}
else {
- value = SPDataStorageObjectAtRowAndColumn(resultData, row, column);
+ if (asPreview) {
+ value = SPDataStoragePreviewAtRowAndColumn(resultData, row, column, 150);
+ } else {
+ value = SPDataStorageObjectAtRowAndColumn(resultData, row, column);
+ }
}
-
- return value;
-}
-/**
- * Converts the supplied value into it's displayable representation.
- *
- * @param value The value to convert
- * @param preserveNULLs Whether or not NULLs should be preserved or converted to the
- * user's NULL placeholder preference.
- * @param truncate Whether or not data fields should be truncates for display purposes.
- *
- * @return The converted value
- */
-- (id)_convertResultDataValueToDisplayableRepresentation:(id)value whilePreservingNULLs:(BOOL)preserveNULLs truncateDataFields:(BOOL)truncate
-{
+ if ([value isKindOfClass:[SPMySQLGeometryData class]])
+ return [value wktString];
+
+ if ([value isNSNull])
+ return preserveNULLs ? value : [prefs objectForKey:SPNullValue];
+
if ([value isKindOfClass:[NSData class]]) {
- value = truncate ? [value shortStringRepresentationUsingEncoding:[mySQLConnection stringEncoding]] : [value stringRepresentationUsingEncoding:[mySQLConnection stringEncoding]];
+ return [value stringRepresentationUsingEncoding:[mySQLConnection stringEncoding]];
}
-
- if ([value isNSNull] && !preserveNULLs) {
- value = [prefs objectForKey:SPNullValue];
- }
-
- if ([value isKindOfClass:[SPMySQLGeometryData class]]) {
- value = [value wktString];
- }
-
+
return value;
}
@@ -4057,6 +4035,7 @@
[NSObject cancelPreviousPerformRequestsWithTarget:customQueryView];
[self clearQueryLoadTimer];
+ [resultLoadingCondition release];
[usedQuery release];
[lastExecutedQuery release];
[resultData release];