aboutsummaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/SPTableData.h2
-rw-r--r--Source/SPTableData.m114
-rw-r--r--Source/TableDocument.h2
-rw-r--r--Source/TableDocument.m22
-rw-r--r--Source/TableRelations.h72
-rw-r--r--Source/TableRelations.m219
6 files changed, 430 insertions, 1 deletions
diff --git a/Source/SPTableData.h b/Source/SPTableData.h
index 099b1e22..d1398844 100644
--- a/Source/SPTableData.h
+++ b/Source/SPTableData.h
@@ -30,6 +30,7 @@
NSMutableArray *columns;
NSMutableArray *columnNames;
+ NSMutableArray *constraints;
NSMutableDictionary *status;
NSString *tableEncoding;
@@ -42,6 +43,7 @@
- (NSDictionary *) columnWithName:(NSString *)colName;
- (NSArray *) columnNames;
- (NSDictionary *) columnAtIndex:(int)index;
+- (NSArray *) getConstraints;
- (BOOL) columnIsBlobOrText:(NSString *)colName;
- (NSString *) statusValueForKey:(NSString *)aKey;
- (NSDictionary *) statusValues;
diff --git a/Source/SPTableData.m b/Source/SPTableData.m
index 4ed5823a..23f3f396 100644
--- a/Source/SPTableData.m
+++ b/Source/SPTableData.m
@@ -39,6 +39,7 @@
if ((self = [super init])) {
columns = [[NSMutableArray alloc] init];
columnNames = [[NSMutableArray alloc] init];
+ constraints = [[NSMutableArray alloc] init];
status = [[NSMutableDictionary alloc] init];
tableEncoding = nil;
mySQLConnection = nil;
@@ -89,6 +90,10 @@
return columns;
}
+- (NSArray *) getConstraints
+{
+ return constraints;
+}
/*
* Retrieve a column with a specified name, using or refreshing the cache as appropriate.
@@ -225,6 +230,7 @@
if (tableData == nil ) {
[columns removeAllObjects];
[columnNames removeAllObjects];
+ [constraints removeAllObjects];
return FALSE;
}
@@ -260,6 +266,8 @@
NSString *encodingString;
unsigned i, stringStart;
+ [constraints removeAllObjects];
+
// Catch unselected tables and return nil
if ([tableName isEqualToString:@""] || !tableName) return nil;
@@ -342,7 +350,109 @@
// TODO: Otherwise it's a key definition, constraint, check, or other 'metadata'. Would be useful to parse/display these!
} else {
-
+ NSArray *parts = [fieldsParser splitStringByCharacter:' ' skippingBrackets:YES ignoringQuotedStrings:YES];
+ NSCharacterSet *junk = [NSCharacterSet characterSetWithCharactersInString:@"`()"];
+ // constraints
+ if( [[parts objectAtIndex:0] hasPrefix:@"CONSTRAINT"] ) {
+ NSMutableDictionary *constraintDetails = [[NSMutableDictionary alloc] init];
+ /*
+ NSLog( @"constraint %@ on %@ ref %@.%@",
+ [[parts objectAtIndex:1] stringByTrimmingCharactersInSet:junk],
+ [[parts objectAtIndex:4] stringByTrimmingCharactersInSet:junk],
+ [[parts objectAtIndex:6] stringByTrimmingCharactersInSet:junk],
+ [[parts objectAtIndex:7] stringByTrimmingCharactersInSet:junk] );
+ */
+ [constraintDetails setObject:[[parts objectAtIndex:1] stringByTrimmingCharactersInSet:junk]
+ forKey:@"name"];
+ [constraintDetails setObject:[[parts objectAtIndex:4] stringByTrimmingCharactersInSet:junk]
+ forKey:@"columns"];
+ [constraintDetails setObject:[[parts objectAtIndex:6] stringByTrimmingCharactersInSet:junk]
+ forKey:@"ref_table"];
+ [constraintDetails setObject:[[parts objectAtIndex:7] stringByTrimmingCharactersInSet:junk]
+ forKey:@"ref_columns"];
+
+ int nextOffs = 12;
+ if( [parts count] > 8 ) {
+ // NOTE: this won't get SET NULL | NO ACTION
+ if( [[parts objectAtIndex:9] hasPrefix:@"UPDATE"] ) {
+ //NSLog( @"update: %@", [parts objectAtIndex:10] );
+ if( [[parts objectAtIndex:10] hasPrefix:@"SET"] ) {
+ [constraintDetails setObject:@"SET NULL"
+ forKey:@"update"];
+ nextOffs = 13;
+ } else if( [[parts objectAtIndex:10] hasPrefix:@"NO"] ) {
+ [constraintDetails setObject:@"NO ACTION"
+ forKey:@"update"];
+ nextOffs = 13;
+ } else {
+ [constraintDetails setObject:[parts objectAtIndex:10]
+ forKey:@"update"];
+ }
+ }
+ else if( [[parts objectAtIndex:9] hasPrefix:@"DELETE"] ) {
+ //NSLog( @"delete: %@", [parts objectAtIndex:10] );
+ if( [[parts objectAtIndex:10] hasPrefix:@"SET"] ) {
+ [constraintDetails setObject:@"SET NULL"
+ forKey:@"delete"];
+ nextOffs = 13;
+ } else if( [[parts objectAtIndex:10] hasPrefix:@"NO"] ) {
+ [constraintDetails setObject:@"NO ACTION"
+ forKey:@"delete"];
+ nextOffs = 13;
+ } else {
+ [constraintDetails setObject:[parts objectAtIndex:10]
+ forKey:@"delete"];
+ }
+ }
+ }
+ if( [parts count] > nextOffs - 1 ) {
+ if( [[parts objectAtIndex:nextOffs] hasPrefix:@"UPDATE"] ) {
+ //NSLog( @"update: %@", [parts objectAtIndex:13] );
+ if( [[parts objectAtIndex:nextOffs+1] hasPrefix:@"SET"] ) {
+ [constraintDetails setObject:@"SET NULL"
+ forKey:@"update"];
+ nextOffs = 13;
+ } else if( [[parts objectAtIndex:nextOffs+1] hasPrefix:@"NO"] ) {
+ [constraintDetails setObject:@"NO ACTION"
+ forKey:@"update"];
+ nextOffs = 13;
+ } else {
+ [constraintDetails setObject:[parts objectAtIndex:nextOffs+1]
+ forKey:@"update"];
+ }
+ }
+ else if( [[parts objectAtIndex:nextOffs] hasPrefix:@"DELETE"] ) {
+ //NSLog( @"delete: %@", [parts objectAtIndex:13] );
+ if( [[parts objectAtIndex:nextOffs+1] hasPrefix:@"SET"] ) {
+ [constraintDetails setObject:@"SET NULL"
+ forKey:@"delete"];
+ nextOffs = 13;
+ } else if( [[parts objectAtIndex:nextOffs+1] hasPrefix:@"NO"] ) {
+ [constraintDetails setObject:@"NO ACTION"
+ forKey:@"delete"];
+ nextOffs = 13;
+ } else {
+ [constraintDetails setObject:[parts objectAtIndex:nextOffs+1]
+ forKey:@"delete"];
+ }
+ }
+ }
+ [constraints addObject:constraintDetails];
+ }
+ // primary key
+ else if( [[parts objectAtIndex:0] hasPrefix:@"PRIMARY"] ) {
+ NSLog( @"pkey is %@", [[parts objectAtIndex:2] stringByTrimmingCharactersInSet:junk] );
+ }
+ // key
+ else if( [[parts objectAtIndex:0] hasPrefix:@"KEY"] ) {
+ NSLog( @"key %@.%@",
+ [[parts objectAtIndex:1] stringByTrimmingCharactersInSet:junk],
+ [[parts objectAtIndex:2] stringByTrimmingCharactersInSet:junk] );
+ }
+ // who knows
+ else {
+ NSLog( @"not parsed: %@", [parts objectAtIndex:0] );
+ }
}
}
[fieldStrings release];
@@ -400,6 +510,7 @@
if (viewData == nil) {
[columns removeAllObjects];
[columnNames removeAllObjects];
+ [constraints removeAllObjects];
return FALSE;
}
@@ -718,6 +829,7 @@
{
[columns release];
[columnNames release];
+ [constraints release];
[status release];
if (tableEncoding != nil) [tableEncoding release];
diff --git a/Source/TableDocument.h b/Source/TableDocument.h
index 33a70e90..b24977f5 100644
--- a/Source/TableDocument.h
+++ b/Source/TableDocument.h
@@ -39,6 +39,7 @@
IBOutlet id tablesListInstance;
IBOutlet id tableSourceInstance;
IBOutlet id tableContentInstance;
+ IBOutlet id tableRelationsInstance;
IBOutlet id customQueryInstance;
IBOutlet id tableDumpInstance;
IBOutlet id tableDataInstance;
@@ -188,6 +189,7 @@
- (IBAction)viewContent:(id)sender;
- (IBAction)viewQuery:(id)sender;
- (IBAction)viewStatus:(id)sender;
+- (IBAction)viewRelations:(id)sender;
- (IBAction)addConnectionToFavorites:(id)sender;
//toolbar methods
diff --git a/Source/TableDocument.m b/Source/TableDocument.m
index 3e666cfd..f292e691 100644
--- a/Source/TableDocument.m
+++ b/Source/TableDocument.m
@@ -333,6 +333,7 @@ NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocum
[tablesListInstance setConnection:mySQLConnection];
[tableSourceInstance setConnection:mySQLConnection];
[tableContentInstance setConnection:mySQLConnection];
+ [tableRelationsInstance setConnection:mySQLConnection];
[customQueryInstance setConnection:mySQLConnection];
[customQueryInstance setMySQLversion:mySQLVersion];
[tableDumpInstance setConnection:mySQLConnection];
@@ -1622,6 +1623,27 @@ NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocum
[mainToolbar setSelectedItemIdentifier:@"SwitchToTableStatusToolbarItemIdentifier"];
}
+- (IBAction)viewRelations:(id)sender
+{
+ // Cancel the selection if currently editing structure/a field and unable to save
+ if ([tableTabView indexOfTabViewItem:[tableTabView selectedTabViewItem]] == 0
+ && ![tableSourceInstance saveRowOnDeselect]) {
+ [mainToolbar setSelectedItemIdentifier:@"SwitchToTableStructureToolbarItemIdentifier"];
+ return;
+ }
+
+ // Cancel the selection if currently editing a content row and unable to save
+ if ([tableTabView indexOfTabViewItem:[tableTabView selectedTabViewItem]] == 1
+ && ![tableContentInstance saveRowOnDeselect]) {
+ [mainToolbar setSelectedItemIdentifier:@"SwitchToTableContentToolbarItemIdentifier"];
+ return;
+ }
+
+ [tableTabView selectTabViewItemAtIndex:4];
+ [mainToolbar setSelectedItemIdentifier:@"SwitchToTableStatusToolbarItemIdentifier"];
+}
+
+
/**
* Adds the current database connection details to the user's favorites if it doesn't already exist.
*/
diff --git a/Source/TableRelations.h b/Source/TableRelations.h
new file mode 100644
index 00000000..9e385e95
--- /dev/null
+++ b/Source/TableRelations.h
@@ -0,0 +1,72 @@
+//
+// TableRelations.h
+// sequel-pro
+//
+// Created by J Knight on 13/05/09.
+// Copyright 2009 TalonEdge Ltd.. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+#import <MCPKit_bundled/MCPKit_bundled.h>
+
+@class CMMCPConnection, CMMCPResult, CMCopyTable;
+
+@interface TableRelations : NSObject {
+
+ IBOutlet id tableDocumentInstance;
+ IBOutlet id tablesListInstance;
+ IBOutlet id tableList;
+ IBOutlet id tableWindow;
+ IBOutlet id tableDataInstance;
+ IBOutlet id addButton;
+ IBOutlet id removeButton;
+ IBOutlet id labelText;
+ IBOutlet id relationsView;
+ IBOutlet id relationSheet;
+
+ IBOutlet id tableBox;
+ IBOutlet id columnSelect;
+ IBOutlet id refTableSelect;
+ IBOutlet id refColumnSelect;
+ IBOutlet id onUpdateSelect;
+ IBOutlet id onDeleteSelect;
+
+
+ CMMCPConnection *mySQLConnection;
+
+ NSMutableArray *relData;
+}
+
+- (void)setConnection:(CMMCPConnection *)theConnection;
+
+//edit methods
+- (IBAction)addRow:(id)sender;
+- (IBAction)removeRow:(id)sender;
+- (IBAction)closeRelationSheet:(id)sender;
+- (IBAction)addRelation:(id)sender;
+- (IBAction)chooseRefTable:(id)sender;
+
+- (IBAction)refresh:(id)sender;
+
+- (void)tableChanged:(NSNotification *)notification;
+
+//tableView datasource methods
+- (int)numberOfRowsInTableView:(NSTableView *)aTableView;
+- (id)tableView:(NSTableView *)aTableView
+objectValueForTableColumn:(NSTableColumn *)aTableColumn
+ row:(int)rowIndex;
+- (void)tableView:(NSTableView *)aTableView
+ setObjectValue:(id)anObject
+ forTableColumn:(NSTableColumn *)aTableColumn
+ row:(int)rowIndex;
+
+//tableView delegate methods
+- (void)tableView:(NSTableView*)tableView didClickTableColumn:(NSTableColumn *)tableColumn;
+- (void)tableViewSelectionDidChange:(NSNotification *)aNotification;
+- (void)tableViewSelectionIsChanging:(NSNotification *)aNotification;
+- (void)tableViewColumnDidResize:(NSNotification *)aNotification;
+- (BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex;
+- (BOOL)tableView:(NSTableView *)tableView writeRows:(NSArray*)rows toPasteboard:(NSPasteboard*)pboard;
+- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command;
+
+@end
diff --git a/Source/TableRelations.m b/Source/TableRelations.m
new file mode 100644
index 00000000..60f19aca
--- /dev/null
+++ b/Source/TableRelations.m
@@ -0,0 +1,219 @@
+//
+// TableRelations.m
+// sequel-pro
+//
+// Created by J Knight on 13/05/09.
+// Copyright 2009 TalonEdge Ltd.. All rights reserved.
+//
+
+#import "TableRelations.h"
+#import "TableDocument.h"
+#import "TablesList.h"
+#import "CMMCPConnection.h"
+#import "CMMCPResult.h"
+#import "SPTableData.h"
+
+@implementation TableRelations
+
+- (id)init
+{
+ if (![super init])
+ return nil;
+
+ relData = [[NSMutableArray alloc] init];
+
+ return self;
+}
+
+- (void)dealloc
+{
+ [relData release], relData = nil;
+
+ [super dealloc];
+}
+
+- (void)awakeFromNib
+{
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(tableChanged:)
+ name:NSTableViewSelectionDidChangeNotification
+ object:tableList];
+}
+
+- (void)setConnection:(CMMCPConnection *)theConnection
+{
+ mySQLConnection = theConnection;
+}
+
+- (IBAction)closeRelationSheet:(id)sender
+{
+ [NSApp stopModalWithCode:1];
+}
+
+- (IBAction)addRelation:(id)sender
+{
+ [NSApp stopModalWithCode:0];
+}
+
+// user choose a reference table
+- (IBAction)chooseRefTable:(id)sender
+{
+ NSString *table = [refTableSelect titleOfSelectedItem];
+
+ [refColumnSelect removeAllItems];
+
+ NSDictionary *info = [tableDataInstance informationForTable:table];
+ NSArray *cols = [info objectForKey:@"columns"];
+ NSMutableArray *colNames = [[NSMutableArray alloc] init];
+ for( int i = 0; i < [cols count]; i++ ) {
+ [colNames addObject:[[cols objectAtIndex:i] objectForKey:@"name"]];
+ }
+ [refColumnSelect addItemsWithTitles:colNames];
+ [colNames release];
+}
+
+- (IBAction)addRow:(id)sender
+{
+ // set up the controls
+ [tableBox setTitle:[NSString stringWithFormat:@"Table: %@",[tablesListInstance tableName] ]];
+ [columnSelect removeAllItems];
+ [columnSelect addItemsWithTitles:[tableDataInstance columnNames]];
+ [refTableSelect removeAllItems];
+ // grab only real tables
+ NSArray *tables = [tablesListInstance tables];
+ NSArray *types = [tablesListInstance tableTypes];
+ NSMutableArray *validTables = [[NSMutableArray alloc] init];
+ for( int i = 0; i < [tables count]; i++ ) {
+ NSLog( @"%@ %@", [tables objectAtIndex:i], [types objectAtIndex:i] );
+ if( [[types objectAtIndex:i] intValue] == SP_TABLETYPE_TABLE ) {
+ [validTables addObject:[tables objectAtIndex:i]];
+ }
+ }
+ [refTableSelect addItemsWithTitles:validTables];
+ [validTables release];
+ [self chooseRefTable:nil];
+
+ [NSApp beginSheet:relationSheet
+ modalForWindow:tableWindow
+ modalDelegate:self
+ didEndSelector:nil
+ contextInfo:nil];
+
+
+ [NSApp runModalForWindow:relationSheet];
+
+ [NSApp endSheet:relationSheet];
+ [relationSheet orderOut:nil];
+}
+
+- (IBAction)removeRow:(id)sender
+{
+ if ( [relationsView numberOfSelectedRows] ) {
+ int resp = NSRunAlertPanel(@"Remove Relations",
+ @"Are you sure you want to remove the selected relations?",
+ @"OK", @"Cancel", nil );
+ if( resp == NSAlertDefaultReturn ) {
+
+ }
+ }
+}
+
+- (IBAction)refresh:(id)sender
+{
+
+ [relData removeAllObjects];
+
+ if( [tablesListInstance tableType] == SP_TABLETYPE_TABLE ) {
+ [labelText setStringValue:[NSString stringWithFormat:@"Relations for table: %@",[tablesListInstance tableName]]];
+ [tableDataInstance updateInformationForCurrentTable];
+ NSArray *constraints = [tableDataInstance getConstraints];
+ for( int i = 0; i < [constraints count]; i++ ) {
+ [relData addObject:[NSDictionary dictionaryWithObjectsAndKeys:
+ [tablesListInstance tableName], @"table",
+ [[constraints objectAtIndex:i] objectForKey:@"name"], @"name",
+ [[constraints objectAtIndex:i] objectForKey:@"columns"], @"columns",
+ [[constraints objectAtIndex:i] objectForKey:@"ref_table"], @"fk_table",
+ [[constraints objectAtIndex:i] objectForKey:@"ref_columns"], @"fk_columns",
+ [[constraints objectAtIndex:i] objectForKey:@"update"], @"on_update",
+ [[constraints objectAtIndex:i] objectForKey:@"delete"], @"on_delete",
+ nil]];
+
+ }
+ } else {
+ [labelText setStringValue:@""];
+ }
+
+ [relationsView reloadData];
+
+}
+
+- (void)tableChanged:(NSNotification *)notification
+{
+ if( [tablesListInstance tableType] == SP_TABLETYPE_TABLE ) {
+ [addButton setEnabled:YES];
+ } else {
+ [addButton setEnabled:NO];
+ }
+
+ [self refresh:nil];
+}
+
+
+//tableView datasource methods
+- (int)numberOfRowsInTableView:(NSTableView *)aTableView
+{
+ return [relData count];
+}
+
+- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn
+ row:(int)rowIndex
+{
+ //NSNumber *theIdentifier = [aTableColumn identifier];
+ NSDictionary *theRow = [relData objectAtIndex:rowIndex];
+ return [theRow objectForKey:[aTableColumn identifier]];
+}
+
+- (void)tableView:(NSTableView *)aTableView
+ setObjectValue:(id)anObject
+ forTableColumn:(NSTableColumn *)aTableColumn
+ row:(int)rowIndex
+{
+
+}
+
+//tableView delegate methods
+- (void)tableView:(NSTableView*)tableView didClickTableColumn:(NSTableColumn *)tableColumn
+{
+
+}
+- (void)tableViewSelectionDidChange:(NSNotification *)aNotification
+{
+ if ( [relationsView numberOfSelectedRows] ) {
+ [removeButton setEnabled:YES];
+ } else {
+ [removeButton setEnabled:NO];
+ }
+}
+- (void)tableViewSelectionIsChanging:(NSNotification *)aNotification
+{
+
+}
+- (void)tableViewColumnDidResize:(NSNotification *)aNotification
+{
+
+}
+- (BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
+{
+ return NO;
+}
+- (BOOL)tableView:(NSTableView *)tableView writeRows:(NSArray*)rows toPasteboard:(NSPasteboard*)pboard
+{
+ return FALSE;
+}
+- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command
+{
+ return FALSE;
+}
+
+
+@end