aboutsummaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/SPAppController.m1
-rw-r--r--Source/SPTableData.h1
-rw-r--r--Source/SPTableData.m81
-rw-r--r--Source/SPTableTriggers.h2
-rw-r--r--Source/SPTableTriggers.m95
-rw-r--r--Source/TableDump.m80
-rw-r--r--Source/TablesList.h3
-rw-r--r--Source/TablesList.m53
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;