diff options
Diffstat (limited to 'Source')
-rw-r--r-- | Source/SPAppController.m | 1 | ||||
-rw-r--r-- | Source/SPTableData.h | 1 | ||||
-rw-r--r-- | Source/SPTableData.m | 81 | ||||
-rw-r--r-- | Source/SPTableTriggers.h | 2 | ||||
-rw-r--r-- | Source/SPTableTriggers.m | 95 | ||||
-rw-r--r-- | Source/TableDump.m | 80 | ||||
-rw-r--r-- | Source/TablesList.h | 3 | ||||
-rw-r--r-- | Source/TablesList.m | 53 |
8 files changed, 172 insertions, 144 deletions
diff --git a/Source/SPAppController.m b/Source/SPAppController.m index f0d4c9bf..f793b93c 100644 --- a/Source/SPAppController.m +++ b/Source/SPAppController.m @@ -441,6 +441,7 @@ @"queryHistory", @"tableColumnWidths", @"savePath", + @"NSRecentDocumentRecords", nil]]; return preferences; diff --git a/Source/SPTableData.h b/Source/SPTableData.h index a63f31dc..88b0a78f 100644 --- a/Source/SPTableData.h +++ b/Source/SPTableData.h @@ -64,6 +64,7 @@ - (BOOL) updateInformationForCurrentView; - (NSDictionary *) informationForView:(NSString *)viewName; - (BOOL) updateStatusInformationForCurrentTable; +- (BOOL) updateTriggersForCurrentTable; - (NSDictionary *) parseFieldDefinitionStringParts:(NSArray *)definitionParts; - (NSArray *) primaryKeyColumnNames; diff --git a/Source/SPTableData.m b/Source/SPTableData.m index 51d490d9..ab1857f6 100644 --- a/Source/SPTableData.m +++ b/Source/SPTableData.m @@ -42,8 +42,8 @@ columnNames = [[NSMutableArray alloc] init]; constraints = [[NSMutableArray alloc] init]; status = [[NSMutableDictionary alloc] init]; - triggers = [[NSMutableArray alloc] init]; - + + triggers = nil; tableEncoding = nil; tableCreateSyntax = nil; mySQLConnection = nil; @@ -121,6 +121,19 @@ - (NSArray *) triggers { + + // If triggers is nil, the triggers need to be loaded - if a table is selected on MySQL >= 5.0.2 + if (!triggers) { + if ([tableListInstance tableType] == SPTableTypeTable + && [mySQLConnection serverMajorVersion] >= 5 + && [mySQLConnection serverMinorVersion] >= 0) + { + [self updateTriggersForCurrentTable]; + } else { + return [NSArray array]; + } + } + return (NSArray *)triggers; } @@ -234,6 +247,11 @@ [columnNames removeAllObjects]; [status removeAllObjects]; + if (triggers != nil) { + [triggers release]; + triggers = nil; + } + if (tableEncoding != nil) { [tableEncoding release]; tableEncoding = nil; @@ -608,39 +626,12 @@ [createTableParser release]; [fieldParser release]; - // Triggers - theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"/*!50003 SHOW TRIGGERS WHERE `Table` = %@ */", - [tableName tickQuotedString]]]; - [theResult setReturnDataAsStrings:YES]; - - // Check for any errors, but only display them if a connection still exists - if ([mySQLConnection queryErrored]) { - if ([mySQLConnection isConnected]) { - SPBeginAlertSheet(NSLocalizedString(@"Error retrieving table information", @"error retrieving table information message"), NSLocalizedString(@"OK", @"OK button"), - nil, nil, [NSApp mainWindow], self, nil, nil, nil, - [NSString stringWithFormat:NSLocalizedString(@"An error occurred while retrieving the information for table '%@'. Please try again.\n\nMySQL said: %@", @"error retrieving table information informative message"), - tableName, [mySQLConnection getLastErrorMessage]]); - } - [tableColumns release]; - if (encodingString) [encodingString release]; - - return nil; - } - - [triggers removeAllObjects]; - if( [theResult numOfRows] ) { - for(i=0; i<[theResult numOfRows]; i++){ - [triggers addObject:[theResult fetchRowAsDictionary]]; - } - } - // this will be 'Table' or 'View' [tableData setObject:[resultFieldNames objectAtIndex:0] forKey:@"type"]; [tableData setObject:[NSString stringWithString:encodingString] forKey:@"encoding"]; [tableData setObject:[NSArray arrayWithArray:tableColumns] forKey:@"columns"]; [tableData setObject:[NSArray arrayWithArray:constraints] forKey:@"constraints"]; - [tableData setObject:[NSArray arrayWithArray:triggers] forKey:@"triggers"]; [encodingString release]; [tableColumns release]; @@ -878,6 +869,36 @@ return TRUE; } +/** + * Retrieve the triggers for the current table and add to local cache for reuse. + */ +- (BOOL) updateTriggersForCurrentTable +{ + MCPResult *theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"/*!50003 SHOW TRIGGERS WHERE `Table` = %@ */", + [[tableListInstance tableName] tickQuotedString]]]; + [theResult setReturnDataAsStrings:YES]; + + // Check for any errors, but only display them if a connection still exists + if ([mySQLConnection queryErrored]) { + if ([mySQLConnection isConnected]) { + SPBeginAlertSheet(NSLocalizedString(@"Error retrieving trigger information", @"error retrieving trigger information message"), NSLocalizedString(@"OK", @"OK button"), + nil, nil, [NSApp mainWindow], self, nil, nil, nil, + [NSString stringWithFormat:NSLocalizedString(@"An error occurred while retrieving the trigger information for table '%@'. Please try again.\n\nMySQL said: %@", @"error retrieving table information informative message"), + [tableListInstance tableName], [mySQLConnection getLastErrorMessage]]); + if (triggers) [triggers release], triggers = nil; + } + + return NO; + } + + if (triggers) [triggers release]; + triggers = [[NSMutableArray alloc] init]; + for (int i=0; i<[theResult numOfRows]; i++) { + [triggers addObject:[theResult fetchRowAsDictionary]]; + } + + return YES; +} /* * Parse an array of field definition parts - not including name but including type and optionally unsigned/zerofill/null @@ -1122,9 +1143,9 @@ [columns release]; [columnNames release]; [constraints release]; - [triggers release]; [status release]; + if (triggers) [triggers release]; if (tableEncoding) [tableEncoding release]; if (tableCreateSyntax) [tableCreateSyntax release]; if (mySQLConnection) [mySQLConnection release]; diff --git a/Source/SPTableTriggers.h b/Source/SPTableTriggers.h index d492253b..8e97908a 100644 --- a/Source/SPTableTriggers.h +++ b/Source/SPTableTriggers.h @@ -57,6 +57,8 @@ @property (readwrite, assign) MCPConnection *connection; +- (void)loadTriggers; + // IB action methods - (IBAction)addTrigger:(id)sender; - (IBAction)removeTrigger:(id)sender; diff --git a/Source/SPTableTriggers.m b/Source/SPTableTriggers.m index dde516a8..c202e9c9 100644 --- a/Source/SPTableTriggers.m +++ b/Source/SPTableTriggers.m @@ -77,12 +77,7 @@ selector:@selector(triggerStatementTextDidChange:) name:NSTextStorageDidProcessEditingNotification object:[triggerStatementTextView textStorage]]; - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(tableSelectionChanged:) - name:SPTableChangedNotification - object:tableDocumentInstance]; - + // Add observers for document task activity [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(startDocumentTaskForTab:) @@ -94,6 +89,46 @@ object:tableDocumentInstance]; } +/** + * Called whenever the user selects the triggers tab for the first time, + * or switches between tables with the triggers tab active. + */ +- (void)loadTriggers +{ + BOOL enableInteraction = ((![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:SPMainToolbarTableTriggers]) || (![tableDocumentInstance isWorking])); + + // Disable all interface elements by default + [addTriggerButton setEnabled:NO]; + [refreshTriggersButton setEnabled:NO]; + [triggersTableView setEnabled:NO]; + [labelTextField setStringValue:@""]; + + // Show a warning if the version of MySQL is too low to support triggers + if ([connection serverMajorVersion] < 5 + || ([connection serverMajorVersion] == 5 + && [connection serverMinorVersion] == 0 + && [connection serverReleaseVersion] < 2)) + { + [labelTextField setStringValue:NSLocalizedString(@"This version of MySQL does not support triggers. Support for triggers was added in MySQL 5.0.2", @"triggers not supported label")]; + return; + } + + // If no item is selected, or the item selected is not a table, return. + if (![tablesListInstance tableName] || [tablesListInstance tableType] != SPTableTypeTable) + return; + + // Update the text label + [labelTextField setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Triggers for table: %@", @"triggers for table label"), [tablesListInstance tableName]]]; + + // Enable interface elements + [addTriggerButton setEnabled:enableInteraction]; + [refreshTriggersButton setEnabled:enableInteraction]; + [triggersTableView setEnabled:YES]; + + // Ensure trigger data is loaded + [self _refreshTriggerDataForcingCacheRefresh:NO]; +} + #pragma mark - #pragma mark IB action methods @@ -185,49 +220,6 @@ [self _refreshTriggerDataForcingCacheRefresh:YES]; } -/** - * Called whenever the user selects a different table. - */ -- (void)tableSelectionChanged:(NSNotification *)notification -{ - BOOL enableInteraction = ((![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:SPMainToolbarTableTriggers]) || (![tableDocumentInstance isWorking])); - - // To begin enable all interface elements - [addTriggerButton setEnabled:enableInteraction]; - [refreshTriggersButton setEnabled:enableInteraction]; - [triggersTableView setEnabled:YES]; - - if (([connection serverMajorVersion] >= 5) && - ([connection serverMinorVersion] >= 0) && - ([connection serverReleaseVersion] >= 2)) { - - // Update the text label - [labelTextField setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Triggers for table: %@", @"triggers for table label"), [tablesListInstance tableName]]]; - - [addTriggerButton setEnabled:enableInteraction]; - [refreshTriggersButton setEnabled:enableInteraction]; - [triggersTableView setEnabled:YES]; - - [self _refreshTriggerDataForcingCacheRefresh:NO]; - } - else { - [addTriggerButton setEnabled:NO]; - [refreshTriggersButton setEnabled:NO]; - [triggersTableView setEnabled:NO]; - - [labelTextField setStringValue:NSLocalizedString(@"This version of MySQL does not support triggers. Support for triggers was added in MySQL 5.0.2", @"triggers not supported label")]; - } - - // If a proc or function is selected disable everything. - if (([tablesListInstance tableType] == SPTableTypeProc) || ([tablesListInstance tableType] == SPTableTypeFunc)) { - [addTriggerButton setEnabled:NO]; - [refreshTriggersButton setEnabled:NO]; - [triggersTableView setEnabled:NO]; - - [labelTextField setStringValue:@""]; - } -} - #pragma mark - #pragma mark Tableview datasource methods @@ -479,7 +471,10 @@ if ([tablesListInstance tableType] == SPTableTypeTable) { - if (clearAllCaches) [tableDataInstance updateInformationForCurrentTable]; + if (clearAllCaches) { + [tableDataInstance resetAllData]; + [tableDataInstance updateTriggersForCurrentTable]; + } NSArray *triggers = [tableDataInstance triggers]; diff --git a/Source/TableDump.m b/Source/TableDump.m index 9f40d90e..004a8e61 100644 --- a/Source/TableDump.m +++ b/Source/TableDump.m @@ -1921,52 +1921,52 @@ // Release the result set [streamingResult release]; + } + + // Export triggers, if any + queryResult = [mySQLConnection queryString:[NSString stringWithFormat:@"/*!50003 SHOW TRIGGERS WHERE `Table` = %@ */;", + [tableName tickQuotedString]]]; + [queryResult setReturnDataAsStrings:YES]; + if ( [queryResult numOfRows] ) { + [metaString setString:@"\n"]; + [metaString appendString:@"DELIMITER ;;\n"]; - queryResult = [mySQLConnection queryString:[NSString stringWithFormat:@"/*!50003 SHOW TRIGGERS WHERE `Table` = %@ */;", - [tableName tickQuotedString]]]; - [queryResult setReturnDataAsStrings:YES]; - if ( [queryResult numOfRows] ) { - [metaString setString:@"\n"]; - [metaString appendString:@"DELIMITER ;;\n"]; + for (int s=0; s<[queryResult numOfRows]; s++) { + NSDictionary *triggers = [[NSDictionary alloc] initWithDictionary:[queryResult fetchRowAsDictionary]]; - for (int s=0; s<[queryResult numOfRows]; s++) { - NSDictionary *triggers = [[NSDictionary alloc] initWithDictionary:[queryResult fetchRowAsDictionary]]; - - //Definer is user@host but we need to escape it to `user`@`host` - NSArray *triggersDefiner = [[triggers objectForKey:@"Definer"] componentsSeparatedByString:@"@"]; - NSString *escapedDefiner = [NSString stringWithFormat:@"%@@%@", - [[triggersDefiner objectAtIndex:0] backtickQuotedString], - [[triggersDefiner objectAtIndex:1] backtickQuotedString] - ]; - - [metaString appendString:[NSString stringWithFormat:@"/*!50003 SET SESSION SQL_MODE=\"%@\" */;;\n", - [triggers objectForKey:@"sql_mode"]]]; - [metaString appendString:@"/*!50003 CREATE */ "]; - [metaString appendString:[NSString stringWithFormat:@"/*!50017 DEFINER=%@ */ ", - escapedDefiner]]; - [metaString appendString:[NSString stringWithFormat:@"/*!50003 TRIGGER %@ %@ %@ ON %@ FOR EACH ROW %@ */;;\n", - [[triggers objectForKey:@"Trigger"] backtickQuotedString], - [triggers objectForKey:@"Timing"], - [triggers objectForKey:@"Event"], - [[triggers objectForKey:@"Table"] backtickQuotedString], - [triggers objectForKey:@"Statement"] - ]]; - [triggers release]; - } + //Definer is user@host but we need to escape it to `user`@`host` + NSArray *triggersDefiner = [[triggers objectForKey:@"Definer"] componentsSeparatedByString:@"@"]; + NSString *escapedDefiner = [NSString stringWithFormat:@"%@@%@", + [[triggersDefiner objectAtIndex:0] backtickQuotedString], + [[triggersDefiner objectAtIndex:1] backtickQuotedString] + ]; - [metaString appendString:@"DELIMITER ;\n"]; - [metaString appendString:@"/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE */;\n"]; - [fileHandle writeData:[metaString dataUsingEncoding:NSUTF8StringEncoding]]; + [metaString appendString:[NSString stringWithFormat:@"/*!50003 SET SESSION SQL_MODE=\"%@\" */;;\n", + [triggers objectForKey:@"sql_mode"]]]; + [metaString appendString:@"/*!50003 CREATE */ "]; + [metaString appendString:[NSString stringWithFormat:@"/*!50017 DEFINER=%@ */ ", + escapedDefiner]]; + [metaString appendString:[NSString stringWithFormat:@"/*!50003 TRIGGER %@ %@ %@ ON %@ FOR EACH ROW %@ */;;\n", + [[triggers objectForKey:@"Trigger"] backtickQuotedString], + [triggers objectForKey:@"Timing"], + [triggers objectForKey:@"Event"], + [[triggers objectForKey:@"Table"] backtickQuotedString], + [triggers objectForKey:@"Statement"] + ]]; + [triggers release]; } - if ([mySQLConnection queryErrored]) { - [errors appendString:[NSString stringWithFormat:@"%@\n", [mySQLConnection getLastErrorMessage]]]; - if ( [addErrorsSwitch state] == NSOnState ) { - [fileHandle writeData:[[NSString stringWithFormat:@"# Error: %@\n", [mySQLConnection getLastErrorMessage]] - dataUsingEncoding:NSUTF8StringEncoding]]; - } + [metaString appendString:@"DELIMITER ;\n"]; + [metaString appendString:@"/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE */;\n"]; + [fileHandle writeData:[metaString dataUsingEncoding:NSUTF8StringEncoding]]; + } + + if ([mySQLConnection queryErrored]) { + [errors appendString:[NSString stringWithFormat:@"%@\n", [mySQLConnection getLastErrorMessage]]]; + if ( [addErrorsSwitch state] == NSOnState ) { + [fileHandle writeData:[[NSString stringWithFormat:@"# Error: %@\n", [mySQLConnection getLastErrorMessage]] + dataUsingEncoding:NSUTF8StringEncoding]]; } - } // Add an additional separator between tables diff --git a/Source/TablesList.h b/Source/TablesList.h index 5c6ccf96..36d3ccaa 100644 --- a/Source/TablesList.h +++ b/Source/TablesList.h @@ -48,6 +48,7 @@ IBOutlet id extendedTableInfoInstance; IBOutlet id databaseDataInstance; IBOutlet id tableInfoInstance; + IBOutlet id tableTriggersInstance; IBOutlet SPHistoryController *spHistoryControllerInstance; IBOutlet id tableWindow; @@ -102,7 +103,7 @@ BOOL tableListIsSelectable; BOOL tableListContainsViews; - BOOL structureLoaded, contentLoaded, statusLoaded, alertSheetOpened; + BOOL structureLoaded, contentLoaded, statusLoaded, triggersLoaded, alertSheetOpened; } // IBAction methods diff --git a/Source/TablesList.m b/Source/TablesList.m index e39da649..15def773 100644 --- a/Source/TablesList.m +++ b/Source/TablesList.m @@ -693,40 +693,35 @@ // Restore view states as appropriate [spHistoryControllerInstance restoreViewStates]; + structureLoaded = NO; + contentLoaded = NO; + statusLoaded = NO; + triggersLoaded = NO; if( selectedTableType == SPTableTypeView || selectedTableType == SPTableTypeTable) { if ( [tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 0 ) { [tableSourceInstance loadTable:selectedTableName]; structureLoaded = YES; - contentLoaded = NO; - statusLoaded = NO; } else if ( [tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 1 ) { if(tableEncoding == nil) { [tableContentInstance loadTable:nil]; } else { [tableContentInstance loadTable:selectedTableName]; } - structureLoaded = NO; contentLoaded = YES; - statusLoaded = NO; } else if ( [tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 3 ) { - [extendedTableInfoInstance performSelectorOnMainThread:@selector(loadTable:) withObject:selectedTableName waitUntilDone:YES]; - structureLoaded = NO; - contentLoaded = NO; + [[extendedTableInfoInstance onMainThread] loadTable:selectedTableName]; statusLoaded = YES; - } else { - structureLoaded = NO; - contentLoaded = NO; - statusLoaded = NO; + } else if ( [tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 5 ) { + [[tableTriggersInstance onMainThread] loadTriggers]; + triggersLoaded = YES; } } else { // if we are not looking at a table or view, clear these [tableSourceInstance loadTable:nil]; [tableContentInstance loadTable:nil]; - [extendedTableInfoInstance performSelectorOnMainThread:@selector(loadTable:) withObject:nil waitUntilDone:YES]; - structureLoaded = NO; - contentLoaded = NO; - statusLoaded = NO; + [[extendedTableInfoInstance onMainThread] loadTable:nil]; + [[tableTriggersInstance onMainThread] loadTriggers]; } // Update the "Show Create Syntax" window if it's already opened @@ -769,10 +764,12 @@ [tableSourceInstance loadTable:nil]; [tableContentInstance loadTable:nil]; [extendedTableInfoInstance loadTable:nil]; + [tableTriggersInstance loadTriggers]; structureLoaded = NO; contentLoaded = NO; statusLoaded = NO; + triggersLoaded = NO; // Set gear menu items Remove/Duplicate table/view according to the table types // if at least one item is selected @@ -1358,24 +1355,27 @@ // if the 'table' is a view or a table, reload the currently selected view if (selectedTableType == SPTableTypeTable || selectedTableType == SPTableTypeView) { + statusLoaded = NO; + structureLoaded = NO; + contentLoaded = NO; + triggersLoaded = NO; switch ([tabView indexOfTabViewItem:[tabView selectedTabViewItem]]) { case 0: [tableSourceInstance loadTable:newTableName]; structureLoaded = YES; - contentLoaded = statusLoaded = NO; break; case 1: [tableContentInstance loadTable:newTableName]; contentLoaded = YES; - structureLoaded = statusLoaded = NO; break; case 3: [extendedTableInfoInstance loadTable:newTableName]; statusLoaded = YES; - structureLoaded = contentLoaded = NO; break; - default: - statusLoaded = structureLoaded = contentLoaded = NO; + case 5: + [tableTriggersInstance loadTriggers]; + triggersLoaded = YES; + break; } } } @@ -1560,8 +1560,9 @@ { NSAutoreleasePool *tabLoadPool = [[NSAutoreleasePool alloc] init]; - if ( [tablesListView numberOfSelectedRows] == 1 && - ([self tableType] == SPTableTypeTable || [self tableType] == SPTableTypeView) ) { + if ([tablesListView numberOfSelectedRows] == 1 + && ([self tableType] == SPTableTypeTable || [self tableType] == SPTableTypeView) ) + { if ( ([tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 0) && !structureLoaded ) { [tableSourceInstance loadTable:selectedTableName]; @@ -1574,9 +1575,14 @@ } if ( ([tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 3) && !statusLoaded ) { - [extendedTableInfoInstance performSelectorOnMainThread:@selector(loadTable:) withObject:selectedTableName waitUntilDone:YES]; + [[extendedTableInfoInstance onMainThread] loadTable:selectedTableName]; statusLoaded = YES; } + + if ( ([tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 5) && !triggersLoaded ) { + [[tableTriggersInstance onMainThread] loadTriggers]; + triggersLoaded = YES; + } } else { [tableSourceInstance loadTable:nil]; @@ -1805,6 +1811,7 @@ structureLoaded = NO; contentLoaded = NO; statusLoaded = NO; + triggersLoaded = NO; isTableListFiltered = NO; tableListIsSelectable = YES; tableListContainsViews = NO; |