aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--English.lproj/Credits.rtf2
-rw-r--r--English.lproj/DBView.xib53
-rw-r--r--Info.plist4
-rw-r--r--SPTableInfo.m30
-rw-r--r--TableContent.h5
-rw-r--r--TableContent.m83
-rw-r--r--TableDocument.h7
-rw-r--r--TableDocument.m52
-rw-r--r--TableDump.h2
-rw-r--r--TableDump.m538
-rw-r--r--TablesList.h4
-rw-r--r--TablesList.m14
12 files changed, 464 insertions, 330 deletions
diff --git a/English.lproj/Credits.rtf b/English.lproj/Credits.rtf
index 6763d3ce..f162315c 100644
--- a/English.lproj/Credits.rtf
+++ b/English.lproj/Credits.rtf
@@ -50,7 +50,7 @@ City of Cairns.com (http://cityofcairns.com), for allowing Abhi and Matt to work
\b GPL
\b0 \
-Copyright (C) 2002-2008 Lorenz Textor, Abhi Beckert, Matt Langtree, Ben Perry. All rights reserved.\
+Copyright (C) 2002-2008 Sequel Pro and CocoaMySQL teams. All rights reserved.\
\
This program is free software; you can redistribute it and/or modify\
it under the terms of the GNU General Public License as published by\
diff --git a/English.lproj/DBView.xib b/English.lproj/DBView.xib
index 6a3f5332..c8102000 100644
--- a/English.lproj/DBView.xib
+++ b/English.lproj/DBView.xib
@@ -1,18 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
-<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.02">
+<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.03">
<data>
<int key="IBDocument.SystemTarget">1050</int>
<string key="IBDocument.SystemVersion">9F33</string>
- <string key="IBDocument.InterfaceBuilderVersion">672</string>
+ <string key="IBDocument.InterfaceBuilderVersion">677</string>
<string key="IBDocument.AppKitVersion">949.34</string>
<string key="IBDocument.HIToolboxVersion">352.00</string>
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
<bool key="EncodedWithXMLCoder">YES</bool>
+ <integer value="27"/>
</object>
<object class="NSArray" key="IBDocument.PluginDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
</object>
+ <object class="NSMutableDictionary" key="IBDocument.Metadata">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
<object class="NSMutableArray" key="IBDocument.RootObjects" id="105205302">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSCustomObject" id="427689665">
@@ -35,7 +45,7 @@
<string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string>
<string key="NSWindowContentMinSize">{780, 480}</string>
<object class="NSView" key="NSWindowView" id="579726586">
- <nil key="NSNextResponder"/>
+ <reference key="NSNextResponder"/>
<int key="NSvFlags">256</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -963,6 +973,7 @@
</object>
<string key="NSFrame">{{1, 1}, {194, 396}}</string>
<reference key="NSSuperview" ref="233472824"/>
+ <reference key="NSNextKeyView" ref="251040077"/>
<reference key="NSDocView" ref="251040077"/>
<reference key="NSBGColor" ref="1024678221"/>
<int key="NScvFlags">4</int>
@@ -989,6 +1000,7 @@
</object>
<string key="NSFrameSize">{196, 398}</string>
<reference key="NSSuperview" ref="355288374"/>
+ <reference key="NSNextKeyView" ref="73685676"/>
<int key="NSsFlags">530</int>
<reference key="NSVScroller" ref="693168867"/>
<reference key="NSHScroller" ref="656188692"/>
@@ -1073,6 +1085,7 @@
</object>
<string key="NSFrame">{{1, 1}, {194, 123}}</string>
<reference key="NSSuperview" ref="298226231"/>
+ <reference key="NSNextKeyView" ref="347093764"/>
<reference key="NSDocView" ref="347093764"/>
<reference key="NSBGColor" ref="1024678221"/>
<int key="NScvFlags">4</int>
@@ -1099,6 +1112,7 @@
</object>
<string key="NSFrame">{{0, 407}, {196, 125}}</string>
<reference key="NSSuperview" ref="355288374"/>
+ <reference key="NSNextKeyView" ref="685057119"/>
<int key="NSsFlags">530</int>
<reference key="NSVScroller" ref="245346414"/>
<reference key="NSHScroller" ref="353686052"/>
@@ -1129,7 +1143,7 @@
<object class="NSTabViewItem" id="831053945">
<string key="NSIdentifier">source</string>
<object class="NSView" key="NSView" id="461236772">
- <reference key="NSNextResponder" ref="714795046"/>
+ <nil key="NSNextResponder"/>
<int key="NSvFlags">256</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -1851,6 +1865,7 @@
</object>
<string key="NSFrame">{{1, 17}, {626, 282}}</string>
<reference key="NSSuperview" ref="22340145"/>
+ <reference key="NSNextKeyView" ref="715508012"/>
<reference key="NSDocView" ref="715508012"/>
<reference key="NSBGColor" ref="1024678221"/>
<int key="NScvFlags">4</int>
@@ -1883,6 +1898,7 @@
</object>
<string key="NSFrame">{{1, 0}, {626, 17}}</string>
<reference key="NSSuperview" ref="22340145"/>
+ <reference key="NSNextKeyView" ref="926883367"/>
<reference key="NSDocView" ref="926883367"/>
<reference key="NSBGColor" ref="1024678221"/>
<int key="NScvFlags">4</int>
@@ -1891,6 +1907,7 @@
</object>
<string key="NSFrame">{{-1, 24}, {628, 300}}</string>
<reference key="NSSuperview" ref="220777809"/>
+ <reference key="NSNextKeyView" ref="16936123"/>
<int key="NSsFlags">562</int>
<reference key="NSVScroller" ref="943144555"/>
<reference key="NSHScroller" ref="456666876"/>
@@ -2321,6 +2338,7 @@
</object>
<string key="NSFrame">{{1, 17}, {626, 138}}</string>
<reference key="NSSuperview" ref="376224367"/>
+ <reference key="NSNextKeyView" ref="584834515"/>
<reference key="NSDocView" ref="584834515"/>
<reference key="NSBGColor" ref="1024678221"/>
<int key="NScvFlags">4</int>
@@ -2353,6 +2371,7 @@
</object>
<string key="NSFrame">{{1, 0}, {626, 17}}</string>
<reference key="NSSuperview" ref="376224367"/>
+ <reference key="NSNextKeyView" ref="459548655"/>
<reference key="NSDocView" ref="459548655"/>
<reference key="NSBGColor" ref="1024678221"/>
<int key="NScvFlags">4</int>
@@ -2361,6 +2380,7 @@
</object>
<string key="NSFrame">{{-1, 22}, {628, 156}}</string>
<reference key="NSSuperview" ref="1063281455"/>
+ <reference key="NSNextKeyView" ref="794929378"/>
<int key="NSsFlags">562</int>
<reference key="NSVScroller" ref="1019209947"/>
<reference key="NSHScroller" ref="328951385"/>
@@ -2469,7 +2489,6 @@
</object>
</object>
<string key="NSFrame">{{10, 7}, {638, 544}}</string>
- <reference key="NSSuperview" ref="714795046"/>
</object>
<string key="NSLabel">Structure</string>
<reference key="NSColor" ref="62854682"/>
@@ -2478,7 +2497,7 @@
<object class="NSTabViewItem" id="624106058">
<string key="NSIdentifier">content</string>
<object class="NSView" key="NSView" id="1013108064">
- <nil key="NSNextResponder"/>
+ <reference key="NSNextResponder" ref="714795046"/>
<int key="NSvFlags">256</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -3069,6 +3088,7 @@
</object>
</object>
<string key="NSFrame">{{10, 7}, {638, 544}}</string>
+ <reference key="NSSuperview" ref="714795046"/>
</object>
<string key="NSLabel">Content</string>
<reference key="NSColor" ref="62854682"/>
@@ -3933,14 +3953,14 @@
<reference key="NSTabView" ref="714795046"/>
</object>
</object>
- <reference key="NSSelectedTabViewItem" ref="831053945"/>
+ <reference key="NSSelectedTabViewItem" ref="624106058"/>
<reference key="NSFont" ref="26"/>
<int key="NSTvFlags">134217731</int>
<bool key="NSAllowTruncatedLabels">YES</bool>
<bool key="NSDrawsBackground">YES</bool>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="461236772"/>
+ <reference ref="1013108064"/>
</object>
</object>
</object>
@@ -3974,6 +3994,7 @@
</object>
</object>
<string key="NSFrameSize">{863, 550}</string>
+ <reference key="NSSuperview"/>
</object>
<string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
<string key="NSMinSize">{780, 502}</string>
@@ -11728,6 +11749,14 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
</object>
<int key="connectionID">4683</int>
</object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleFilterField:</string>
+ <reference key="source" ref="392169872"/>
+ <reference key="destination" ref="744029762"/>
+ </object>
+ <int key="connectionID">4685</int>
+ </object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
@@ -19251,8 +19280,8 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
</object>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
- <string>{{774, 505}, {863, 550}}</string>
- <string>{{774, 505}, {863, 550}}</string>
+ <string>{{299, 286}, {863, 550}}</string>
+ <string>{{299, 286}, {863, 550}}</string>
<reference ref="9"/>
<reference ref="9"/>
<string>{{62, 352}, {845, 504}}</string>
@@ -19665,7 +19694,7 @@ Y2hhbmdlIHRoZSBvcmRlcg</string>
</object>
</object>
<nil key="sourceID"/>
- <int key="maxID">4683</int>
+ <int key="maxID">4685</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
@@ -19877,6 +19906,7 @@ Y2hhbmdlIHRoZSBvcmRlcg</string>
<string>setCompareTypes:</string>
<string>showAll:</string>
<string>stepLimitRows:</string>
+ <string>toggleFilterField:</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -19893,6 +19923,7 @@ Y2hhbmdlIHRoZSBvcmRlcg</string>
<string>id</string>
<string>id</string>
<string>id</string>
+ <string>id</string>
</object>
</object>
<object class="NSMutableDictionary" key="outlets">
diff --git a/Info.plist b/Info.plist
index 053e09e2..f1235006 100644
--- a/Info.plist
+++ b/Info.plist
@@ -44,11 +44,11 @@
<key>CFBundleShortVersionString</key>
<string>0.9.3</string>
<key>CFBundleVersion</key>
- <string>236</string>
+ <string>254</string>
<key>NSAppleScriptEnabled</key>
<string>YES</string>
<key>NSHumanReadableCopyright</key>
- <string>0.9.3 (236)</string>
+ <string>0.9.3 (254)</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
diff --git a/SPTableInfo.m b/SPTableInfo.m
index 5e777429..b2b81c05 100644
--- a/SPTableInfo.m
+++ b/SPTableInfo.m
@@ -114,27 +114,37 @@ objectValueForTableColumn:(NSTableColumn *)aTableColumn
// Process result
theRow = [[theResult fetch2DResultAsType:MCPTypeDictionary] lastObject];
- // Add the table name to the infoTable
- [info addObject:[NSString stringWithFormat:@"name: %@", [tableListInstance table]]];
-
// Check for "Create_time" == NULL
if (![[theRow objectForKey:@"Create_time"] isNSNull]) {
// Setup our data formatter
- NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
- [dateFormatter setDateStyle:NSDateFormatterShortStyle];
- [dateFormatter setTimeStyle:NSDateFormatterNoStyle];
+ NSDateFormatter *createDateFormatter = [[[NSDateFormatter alloc] init] autorelease];
+ [createDateFormatter setDateStyle:NSDateFormatterShortStyle];
+ [createDateFormatter setTimeStyle:NSDateFormatterNoStyle];
- // Convert our string dates from the results to NSDates.
+ // Convert our string date from the result to an NSDate.
NSDate *create_date = [NSDate dateWithNaturalLanguageString:[theRow objectForKey:@"Create_time"]];
+
+ // Add the creation date to the infoTable
+ [info addObject:[NSString stringWithFormat:@"created: %@", [createDateFormatter stringFromDate:create_date]]];
+ }
+
+ // Check for "Update_time" == NULL - InnoDB tables don't have an update time
+ if (![[theRow objectForKey:@"Update_time"] isNSNull]) {
+ // Setup our data formatter
+ NSDateFormatter *updateDateFormatter = [[[NSDateFormatter alloc] init] autorelease];
+ [updateDateFormatter setDateStyle:NSDateFormatterShortStyle];
+ [updateDateFormatter setTimeStyle:NSDateFormatterNoStyle];
+
+ // Convert our string date from the result to an NSDate.
NSDate *update_date = [NSDate dateWithNaturalLanguageString:[theRow objectForKey:@"Update_time"]];
- // Add the create date and update date to the infoTable
- [info addObject:[NSString stringWithFormat:@"created: %@", [dateFormatter stringFromDate:create_date]]];
- [info addObject:[NSString stringWithFormat:@"updated: %@", [dateFormatter stringFromDate:update_date]]];
+ // Add the update date to the infoTable
+ [info addObject:[NSString stringWithFormat:@"updated: %@", [updateDateFormatter stringFromDate:update_date]]];
}
[info addObject:[NSString stringWithFormat:@"rows: %@", [theRow objectForKey:@"Rows"]]];
[info addObject:[NSString stringWithFormat:@"size: %@", [self sizeFromBytes:[[theRow objectForKey:@"Data_length"] intValue]]]];
+ [info addObject:[NSString stringWithFormat:@"encoding: %@", [[[theRow objectForKey:@"Collation"] componentsSeparatedByString:@"_"] objectAtIndex:0]]];
[info addObject:[NSString stringWithFormat:@"auto_increment: %@", [theRow objectForKey:@"Auto_increment"]]];
// Notify that we've finished performing the query
diff --git a/TableContent.h b/TableContent.h
index 64a57060..54ad2481 100644
--- a/TableContent.h
+++ b/TableContent.h
@@ -78,6 +78,7 @@
- (IBAction)reloadTableValues:(id)sender;
- (IBAction)filterTable:(id)sender;
- (IBAction)showAll:(id)sender;
+- (IBAction)toggleFilterField:(id)sender;
//edit methods
- (IBAction)addRow:(id)sender;
@@ -131,8 +132,4 @@ objectValueForTableColumn:(NSTableColumn *)aTableColumn
//textView delegate methods
- (BOOL)textView:(NSTextView *)aTextView doCommandBySelector:(SEL)aSelector;
-//last but not least
-- (id)init;
-- (void)dealloc;
-
@end
diff --git a/TableContent.m b/TableContent.m
index 1e5e898a..c3238a3c 100644
--- a/TableContent.m
+++ b/TableContent.m
@@ -420,7 +420,8 @@
NSString *queryString;
int i;
- if ([argument length] == 0) {
+ // If the filter field is empty or the selected filter is not looking for NULLs or 'not' NULLs, then don't allow filtering.
+ if (([argument length] == 0) && (![[[compareField selectedItem] title] hasSuffix:@"NULL"])) {
[argument release];
[self showAll:sender];
return;
@@ -430,6 +431,7 @@
[[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryWillBePerformed" object:self];
BOOL doQuote = YES;
+ BOOL ignoreArgument = NO;
if ( ![compareType isEqualToString:@""] ) {
if ( [compareType isEqualToString:@"string"] ) {
@@ -454,6 +456,16 @@
doQuote = NO;
[argument setString:[[@"(" stringByAppendingString:argument] stringByAppendingString:@")"]];
break;
+ case 5:
+ compareOperator = @"IS NULL";
+ doQuote = NO;
+ ignoreArgument = YES;
+ break;
+ case 6:
+ compareOperator = @"IS NOT NULL";
+ doQuote = NO;
+ ignoreArgument = YES;
+ break;
}
} else if ( [compareType isEqualToString:@"number"] ) {
//number comparision
@@ -481,6 +493,16 @@
doQuote = NO;
[argument setString:[[@"(" stringByAppendingString:argument] stringByAppendingString:@")"]];
break;
+ case 7:
+ compareOperator = @"IS NULL";
+ doQuote = NO;
+ ignoreArgument = YES;
+ break;
+ case 8:
+ compareOperator = @"IS NOT NULL";
+ doQuote = NO;
+ ignoreArgument = YES;
+ break;
}
} else if ( [compareType isEqualToString:@"date"] ) {
//date comparision
@@ -503,12 +525,19 @@
case 5:
compareOperator = @">=";
break;
+ case 6:
+ compareOperator = @"IS NULL";
+ doQuote = NO;
+ ignoreArgument = YES;
+ break;
+ case 7:
+ compareOperator = @"IS NOT NULL";
+ doQuote = NO;
+ ignoreArgument = YES;
+ break;
}
}
- // queryString = [NSString stringWithFormat:@"SELECT %@ FROM `%@` WHERE `%@` %@ '%@'",
- // [self fieldListForQuery], selectedTable, [fieldField titleOfSelectedItem],
- // compareOperator, argument];
if (doQuote) {
//escape special characters
for ( i = 0 ; i < [argument length] ; i++ ) {
@@ -524,7 +553,7 @@
} else {
queryString = [NSString stringWithFormat:@"SELECT %@ FROM `%@` WHERE `%@` %@ %@",
[self fieldListForQuery], selectedTable, [fieldField titleOfSelectedItem],
- compareOperator, argument];
+ compareOperator, (ignoreArgument) ? @"" : argument];
}
if ( sortField ) {
// queryString = [queryString stringByAppendingString:[NSString stringWithFormat:@" ORDER BY `%@`", sortField]];
@@ -544,7 +573,7 @@
NSLog(@"ERROR: unknown compare type %@", compareType);
queryString = @"";
}
-
+
theResult = [mySQLConnection queryString:queryString];
[filteredResult setArray:[self fetchResultAsArray:theResult]];
@@ -570,6 +599,15 @@
[countText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"%d rows in table", @"text showing how many rows are in the result"), numRows]];
}
+/**
+ * Enables or disables the filter input field based on the selected filter type.
+ */
+- (IBAction)toggleFilterField:(id)sender
+{
+ // If the user is filtering for NULLs then disabled the filter field, otherwise enable it.
+ [argumentField setEnabled:(![[[compareField selectedItem] title] hasSuffix:@"NULL"])];
+}
+
//edit methods
- (IBAction)addRow:(id)sender
@@ -921,28 +959,24 @@
}
}
-- (IBAction)setCompareTypes:(id)sender
-/*
- sets the compare types for the filter and the appropriate formatter for the textField
+/**
+ * Sets the compare types for the filter and the appropriate formatter for the textField
*/
+- (IBAction)setCompareTypes:(id)sender
{
NSArray *stringFields = [NSArray arrayWithObjects:@"varstring", @"string", @"tinyblob", @"blob", @"mediumblob", @"longblob", @"set", @"enum", nil];
- NSArray *stringTypes = [NSArray arrayWithObjects:NSLocalizedString(@"is", @"popup menuitem for field IS value"), NSLocalizedString(@"is not", @"popup menuitem for field IS NOT value"), NSLocalizedString(@"contains", @"popup menuitem for field CONTAINS value"), NSLocalizedString(@"contains not", @"popup menuitem for field CONTAINS NOT value"), @"IN", nil];
+ NSArray *stringTypes = [NSArray arrayWithObjects:NSLocalizedString(@"is", @"popup menuitem for field IS value"), NSLocalizedString(@"is not", @"popup menuitem for field IS NOT value"), NSLocalizedString(@"contains", @"popup menuitem for field CONTAINS value"), NSLocalizedString(@"contains not", @"popup menuitem for field CONTAINS NOT value"), @"IN", nil];
NSArray *numberFields = [NSArray arrayWithObjects:@"tiny", @"short", @"long", @"int24", @"longlong", @"decimal", @"float", @"double", nil];
- NSArray *numberTypes = [NSArray arrayWithObjects:@"=", @"≠", @">", @"<", @"≥", @"≤", @"IN", nil];
- NSArray *dateFields = [NSArray arrayWithObjects:@"timestamp", @"date", @"time", @"datetime", @"year", nil];
- NSArray *dateTypes = [NSArray arrayWithObjects:NSLocalizedString(@"is", @"popup menuitem for field IS value"), NSLocalizedString(@"is not", @"popup menuitem for field IS NOT value"), NSLocalizedString(@"older than", @"popup menuitem for field OLDER THAN value"), NSLocalizedString(@"younger than", @"popup menuitem for field YOUNGER THAN value"), NSLocalizedString(@"older than or equal to", @"popup menuitem for field OLDER THAN OR EQUAL TO value"), NSLocalizedString(@"younger than or equal to", @"popup menuitem for field YOUNGER THAN OR EQUAL TO value"), nil];
- NSString *fieldType = [NSString stringWithString:[fieldTypes objectAtIndex:[[fieldField selectedItem] tag]]];
- // NSNumberFormatter *numberFormatter;
- int i;
+ NSArray *numberTypes = [NSArray arrayWithObjects:@"=", @"≠", @">", @"<", @"≥", @"≤", @"IN", nil];
+ NSArray *dateFields = [NSArray arrayWithObjects:@"timestamp", @"date", @"time", @"datetime", @"year", nil];
+ NSArray *dateTypes = [NSArray arrayWithObjects:NSLocalizedString(@"is", @"popup menuitem for field IS value"), NSLocalizedString(@"is not", @"popup menuitem for field IS NOT value"), NSLocalizedString(@"older than", @"popup menuitem for field OLDER THAN value"), NSLocalizedString(@"younger than", @"popup menuitem for field YOUNGER THAN value"), NSLocalizedString(@"older than or equal to", @"popup menuitem for field OLDER THAN OR EQUAL TO value"), NSLocalizedString(@"younger than or equal to", @"popup menuitem for field YOUNGER THAN OR EQUAL TO value"), nil];
+ NSString *fieldType = [NSString stringWithString:[fieldTypes objectAtIndex:[[fieldField selectedItem] tag]]];
- // numberFormatter = [[[NSNumberFormatter alloc] init] autorelease];
- // [numberFormatter setFormat:@"0.####################"];
+ int i;
[compareField removeAllItems];
- // [argumentField setStringValue:@""];
- //why do we get "string" for enum fields? (error in framework?)
+ // Why do we get "string" for enum fields? (error in framework?)
if ( [stringFields containsObject:fieldType] ) {
[compareField addItemsWithTitles:stringTypes];
compareType = @"string";
@@ -976,10 +1010,17 @@
NSLog(@"ERROR: unknown type for comparision: %@", fieldType);
}
+ // Add IS NULL and IS NOT NULL as they should always be available
+ [compareField addItemWithTitle:@"IS NULL"];
+ [compareField addItemWithTitle:@"IS NOT NULL"];
+
for ( i = 0 ; i < [compareField numberOfItems] ; i++ ) {
[[compareField itemAtIndex:i] setTag:i];
}
-
+
+ // Update the argumentField enabled state
+ [self toggleFilterField:self];
+
// set focus on argumentField
[argumentField selectText:self];
}
diff --git a/TableDocument.h b/TableDocument.h
index 2a54a37c..62798b2d 100644
--- a/TableDocument.h
+++ b/TableDocument.h
@@ -81,7 +81,6 @@
NSMutableArray *favorites;
NSArray *variables;
NSString *selectedDatabase;
- NSString *selectedFavorite;
NSString *mySQLVersion;
NSUserDefaults *prefs;
@@ -135,7 +134,8 @@
//encoding methods
- (void)setEncoding:(NSString *)encoding;
-- (void)detectEncoding;
+- (void)detectDatabaseEncoding;
+- (void)detectTableEncodingForTable:(NSString *)table;
- (IBAction)chooseEncoding:(id)sender;
- (BOOL)supportsEncoding;
- (void)updateEncodingMenuWithSelectedEncoding:(NSString *)encoding;
@@ -215,9 +215,6 @@
objectValueForTableColumn:(NSTableColumn *)aTableColumn
row:(int)rowIndex;
-//for freeing up memory
-- (void)dealloc;
-
@end
extern NSString *TableDocumentFavoritesControllerSelectionIndexDidChange;
diff --git a/TableDocument.m b/TableDocument.m
index 59aad2e0..2dcb5f1a 100644
--- a/TableDocument.m
+++ b/TableDocument.m
@@ -182,7 +182,7 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocumentFa
// set encoding
NSString *encodingName = [prefs objectForKey:@"encoding"];
if ( [encodingName isEqualToString:@"Autodetect"] ) {
- [self detectEncoding];
+ [self detectDatabaseEncoding];
} else {
[self setEncoding:[self mysqlEncodingFromDisplayEncoding:encodingName]];
}
@@ -260,9 +260,6 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocumentFa
[portField setStringValue:[self valueForKeyPath:@"selectedFavorite.port"]];
[databaseField setStringValue:[self valueForKeyPath:@"selectedFavorite.database"]];
[passwordField setStringValue:[self selectedFavoritePassword]];
-
- [selectedFavorite release];
- selectedFavorite = [[favoritesButton titleOfSelectedItem] retain];
}
/**
@@ -368,7 +365,7 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocumentFa
[self willChangeValueForKey:@"favorites"];
// write favorites and password
- NSDictionary *newFavorite = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:favoriteName, host, socket, user, port, database, nil]
+ NSMutableDictionary *newFavorite = [NSMutableDictionary dictionaryWithObjects:[NSArray arrayWithObjects:favoriteName, host, socket, user, port, database, nil]
forKeys:[NSArray arrayWithObjects:@"name", @"host", @"socket", @"user", @"port", @"database", nil]];
[favorites addObject:newFavorite];
@@ -378,9 +375,6 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocumentFa
account:[NSString stringWithFormat:@"%@@%@/%@", user, host, database]];
}
- // select new favorite
- selectedFavorite = [favoriteName retain];
-
[self didChangeValueForKey:@"favorites"];
[favoritesController setSelectedObjects:[NSArray arrayWithObject:newFavorite]];
}
@@ -638,14 +632,15 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocumentFa
{
// set encoding of connection and client
[mySQLConnection queryString:[NSString stringWithFormat:@"SET NAMES '%@'", mysqlEncoding]];
+
if ( [[mySQLConnection getLastErrorMessage] isEqualToString:@""] ) {
[mySQLConnection setEncoding:[CMMCPConnection encodingForMySQLEncoding:[mysqlEncoding UTF8String]]];
[_encoding autorelease];
_encoding = [mysqlEncoding retain];
} else {
- [self detectEncoding];
+ [self detectDatabaseEncoding];
}
-
+
// update the selected menu item
[self updateEncodingMenuWithSelectedEncoding:[self encodingNameFromMySQLEncoding:mysqlEncoding]];
@@ -748,9 +743,9 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocumentFa
/**
* Autodetect the connection encoding and select the relevant encoding menu item in Database -> Database Encoding
*/
-- (void)detectEncoding
+- (void)detectDatabaseEncoding
{
- // mysql > 4.0
+ // MySQL > 4.0
id mysqlEncoding = [[[mySQLConnection queryString:@"SHOW VARIABLES LIKE 'character_set_connection'"] fetchRowAsDictionary] objectForKey:@"Value"];
_supportsEncoding = (mysqlEncoding != nil);
@@ -761,9 +756,10 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocumentFa
mysqlEncoding = [[[mySQLConnection queryString:@"SHOW VARIABLES LIKE 'character_set'"] fetchRowAsDictionary] objectForKey:@"Value"];
}
if ( !mysqlEncoding ) { // older version? -> set encoding to mysql default encoding latin1
- NSLog(@"error: no character encoding found, mysql version is %@", [self mySQLVersion]);
+ NSLog(@"Error: no character encoding found, mysql version is %@", [self mySQLVersion]);
mysqlEncoding = @"latin1";
}
+
[mySQLConnection setEncoding:[CMMCPConnection encodingForMySQLEncoding:[mysqlEncoding cString]]];
// save the encoding
@@ -775,7 +771,29 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocumentFa
}
/**
- * when sent by an NSMenuItem, will set the encoding based on the title of the menu item
+ * Detects and sets the character set encoding of the supplied table name.
+ */
+- (void)detectTableEncodingForTable:(NSString *)table;
+{
+ NSString *tableCollation = [[[mySQLConnection queryString:[NSString stringWithFormat:@"SHOW TABLE STATUS WHERE NAME = '%@'", table]] fetchRowAsDictionary] objectForKey:@"Collation"];
+
+ if (tableCollation != nil) {
+ // Split up the collation string so we can get the encoding
+ NSArray *encodingComponents = [tableCollation componentsSeparatedByString:@"_"];
+
+ if ([encodingComponents count] > 0) {
+ NSString *tableEncoding = [encodingComponents objectAtIndex:0];
+
+ [self setEncoding:tableEncoding];
+ }
+ }
+ else {
+ NSLog(@"Error: unable to determine table collation and thus character encoding for table '%@'", table);
+ }
+}
+
+/**
+ * When sent by an NSMenuItem, will set the encoding based on the title of the menu item
*/
- (IBAction)chooseEncoding:(id)sender
{
@@ -1428,7 +1446,6 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocumentFa
// [tableWindow makeKeyAndOrderFront:self];
prefs = [[NSUserDefaults standardUserDefaults] retain];
- selectedFavorite = [[NSString alloc] initWithString:NSLocalizedString(@"Custom", @"menu item for custom connection")];
//register for notifications
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willPerformQuery:)
@@ -1593,6 +1610,10 @@ objectValueForTableColumn:(NSTableColumn *)aTableColumn
- (IBAction)terminate:(id)sender
{
[[NSApp orderedDocuments] makeObjectsPerformSelector:@selector(cancelConnectSheet:) withObject:nil];
+
+ // Save the favourites - commits any unsaved changes ie favourite renames
+ [prefs setObject:[self favorites] forKey:@"favorites"];
+
[NSApp terminate:sender];
}
@@ -1603,7 +1624,6 @@ objectValueForTableColumn:(NSTableColumn *)aTableColumn
[favorites release];
[variables release];
[selectedDatabase release];
- [selectedFavorite release];
[mySQLVersion release];
[prefs release];
diff --git a/TableDump.h b/TableDump.h
index a382e082..22b123af 100644
--- a/TableDump.h
+++ b/TableDump.h
@@ -89,6 +89,7 @@
NSMutableArray *tables;
NSArray *importArray;
NSMutableArray *fieldMappingArray;
+ NSMutableArray *fieldMappingButtonOptions;
int currentRow;
NSString *savePath;
NSString *openPath;
@@ -114,6 +115,7 @@
- (IBAction)changeTable:(id)sender;
- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(NSString *)contextInfo;
- (void)setupFieldMappingArray;
+- (void)updateFieldMappingButtonCell;
- (NSArray *)arrayForCSV:(NSString *)csv terminatedBy:(NSString *)terminated
enclosedBy:(NSString *)enclosed escapedBy:(NSString *)escaped lineEnds:(NSString *)lineEnds;
- (NSArray *)arrayForString:(NSString *)string enclosed:(NSString *)enclosed
diff --git a/TableDump.m b/TableDump.m
index a40458d0..277ed3e7 100644
--- a/TableDump.m
+++ b/TableDump.m
@@ -110,55 +110,55 @@
[savePanel setAccessoryView:exportDumpView];
contextInfo = @"exportDump";
break;
-
- // Export the full resultset for the currently selected table to a file in CSV format
+
+ // Export the full resultset for the currently selected table to a file in CSV format
case 6:
file = [NSString stringWithFormat:@"%@.csv", [tableDocumentInstance table]];
[savePanel setAccessoryView:exportCSVView];
contextInfo = @"exportTableContentAsCSV";
break;
-
- // Export the full resultset for the currently selected table to a file in XML format
+
+ // Export the full resultset for the currently selected table to a file in XML format
case 7:
file = [NSString stringWithFormat:@"%@.xml", [tableDocumentInstance table]];
contextInfo = @"exportTableContentAsXML";
break;
-
- // Export the current "browse" view to a file in CSV format
+
+ // Export the current "browse" view to a file in CSV format
case 8:
file = [NSString stringWithFormat:@"%@ view.csv", [tableDocumentInstance table]];
[savePanel setAccessoryView:exportCSVView];
contextInfo = @"exportBrowseViewAsCSV";
break;
-
- // Export the current "browse" view to a file in XML format
+
+ // Export the current "browse" view to a file in XML format
case 9:
file = [NSString stringWithFormat:@"%@ view.xml", [tableDocumentInstance table]];
contextInfo = @"exportBrowseViewAsXML";
break;
-
- // Export the current custom query result set to a file in CSV format
+
+ // Export the current custom query result set to a file in CSV format
case 10:
file = @"customresult.csv";
[savePanel setAccessoryView:exportCSVView];
contextInfo = @"exportCustomResultAsCSV";
break;
-
- // Export the current custom query result set to a file in XML format
+
+ // Export the current custom query result set to a file in XML format
case 11:
file = @"customresult.xml";
contextInfo = @"exportCustomResultAsXML";
break;
-
- // Export multiple tables to a file in CSV format
+
+ // Export multiple tables to a file in CSV format
case 12:
[self reloadTables:self];
file = [NSString stringWithFormat:@"%@.csv", [tableDocumentInstance database]];
[savePanel setAccessoryView:exportMultipleCSVView];
contextInfo = @"exportMultipleTablesAsCSV";
break;
-
- // Export multiple tables to a file in XML format
+
+ // Export multiple tables to a file in XML format
case 13:
[self reloadTables:self];
file = [NSString stringWithFormat:@"%@.xml", [tableDocumentInstance database]];
@@ -173,8 +173,8 @@
// Open the savePanel
[savePanel beginSheetForDirectory:[prefs objectForKey:@"savePath"]
- file:file modalForWindow:tableWindow modalDelegate:self
- didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:) contextInfo:contextInfo];
+ file:file modalForWindow:tableWindow modalDelegate:self
+ didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:) contextInfo:contextInfo];
}
/*
@@ -189,10 +189,10 @@
if ( returnCode != NSOKButton )
return;
-
+
// Save path to preferences
[prefs setObject:[sheet directory] forKey:@"savePath"];
-
+
// Error if the file already exists and is not writable, and get a fileHandle to it.
if ( [[NSFileManager defaultManager] fileExistsAtPath:[sheet filename]] ) {
if ( ![[NSFileManager defaultManager] isWritableFileAtPath:[sheet filename]]
@@ -204,21 +204,21 @@
// Truncate the file to zero bytes
[fileHandle truncateFileAtOffset:0];
-
- // Otherwise attempt to create a file
+
+ // Otherwise attempt to create a file
} else {
if ( ![[NSFileManager defaultManager] createFileAtPath:[sheet filename] contents:[NSData data] attributes:nil] ) {
NSBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, nil,
NSLocalizedString(@"Couldn't write to file. Be sure that you have the necessary privileges.", @"message of panel when file cannot be written"));
return;
}
-
+
// Retrieve a filehandle for the file, attempting to delete it on failure.
fileHandle = [NSFileHandle fileHandleForWritingAtPath:[sheet filename]];
if ( !fileHandle ) {
[[NSFileManager defaultManager] removeFileAtPath:[sheet filename] handler:nil];
NSBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, nil,
- NSLocalizedString(@"Couldn't write to file. Be sure that you have the necessary privileges.", @"message of panel when file cannot be written"));
+ NSLocalizedString(@"Couldn't write to file. Be sure that you have the necessary privileges.", @"message of panel when file cannot be written"));
return;
}
}
@@ -226,62 +226,62 @@
// Export the tables selected in the MySQL export sheet to a file
if ( [contextInfo isEqualToString:@"exportDump"] ) {
success = [self dumpSelectedTablesAsSqlToFileHandle:fileHandle];
-
- // Export the full resultset for the currently selected table to a file in CSV format
+
+ // Export the full resultset for the currently selected table to a file in CSV format
} else if ( [contextInfo isEqualToString:@"exportTableContentAsCSV"] ) {
success = [self exportTables:[NSArray arrayWithObject:[tableDocumentInstance table]] toFileHandle:fileHandle usingFormat:@"csv"];
-
- // Export the full resultset for the currently selected table to a file in XML format
+
+ // Export the full resultset for the currently selected table to a file in XML format
} else if ( [contextInfo isEqualToString:@"exportTableContentAsXML"] ) {
success = [self exportTables:[NSArray arrayWithObject:[tableDocumentInstance table]] toFileHandle:fileHandle usingFormat:@"xml"];
-
- // Export the current "browse" view to a file in CSV format
+
+ // Export the current "browse" view to a file in CSV format
} else if ( [contextInfo isEqualToString:@"exportBrowseViewAsCSV"] ) {
success = [self writeCsvForArray:[tableContentInstance currentResult] orQueryResult:nil
toFileHandle:fileHandle
- outputFieldNames:[exportFieldNamesSwitch state]
+ outputFieldNames:[exportFieldNamesSwitch state]
terminatedBy:[exportFieldsTerminatedField stringValue]
- enclosedBy:[exportFieldsEnclosedField stringValue]
- escapedBy:[exportFieldsEscapedField stringValue]
- lineEnds:[exportLinesTerminatedField stringValue]
- silently:NO];
-
- // Export the current "browse" view to a file in XML format
+ enclosedBy:[exportFieldsEnclosedField stringValue]
+ escapedBy:[exportFieldsEscapedField stringValue]
+ lineEnds:[exportLinesTerminatedField stringValue]
+ silently:NO];
+
+ // Export the current "browse" view to a file in XML format
} else if ( [contextInfo isEqualToString:@"exportBrowseViewAsXML"] ) {
success = [self writeXmlForArray:[tableContentInstance currentResult] orQueryResult:nil
toFileHandle:fileHandle
- tableName:[tableDocumentInstance table]
- withHeader:YES
- silently:NO];
-
- // Export the current custom query result set to a file in CSV format
+ tableName:[tableDocumentInstance table]
+ withHeader:YES
+ silently:NO];
+
+ // Export the current custom query result set to a file in CSV format
} else if ( [contextInfo isEqualToString:@"exportCustomResultAsCSV"] ) {
success = [self writeCsvForArray:[customQueryInstance currentResult] orQueryResult:nil
toFileHandle:fileHandle
- outputFieldNames:[exportFieldNamesSwitch state]
+ outputFieldNames:[exportFieldNamesSwitch state]
terminatedBy:[exportFieldsTerminatedField stringValue]
- enclosedBy:[exportFieldsEnclosedField stringValue]
- escapedBy:[exportFieldsEscapedField stringValue]
- lineEnds:[exportLinesTerminatedField stringValue]
- silently:NO];
-
- // Export the current custom query result set to a file in XML format
+ enclosedBy:[exportFieldsEnclosedField stringValue]
+ escapedBy:[exportFieldsEscapedField stringValue]
+ lineEnds:[exportLinesTerminatedField stringValue]
+ silently:NO];
+
+ // Export the current custom query result set to a file in XML format
} else if ( [contextInfo isEqualToString:@"exportCustomResultAsXML"] ) {
success = [self writeXmlForArray:[customQueryInstance currentResult] orQueryResult:nil
toFileHandle:fileHandle
- tableName:@"custom"
- withHeader:YES
- silently:NO];
-
- // Export multiple tables to a file in CSV format
+ tableName:@"custom"
+ withHeader:YES
+ silently:NO];
+
+ // Export multiple tables to a file in CSV format
} else if ( [contextInfo isEqualToString:@"exportMultipleTablesAsCSV"] ) {
success = [self exportSelectedTablesToFileHandle:fileHandle usingFormat:@"csv"];
-
- // Export multiple tables to a file in XML format
+
+ // Export multiple tables to a file in XML format
} else if ( [contextInfo isEqualToString:@"exportMultipleTablesAsXML"] ) {
success = [self exportSelectedTablesToFileHandle:fileHandle usingFormat:@"xml"];
-
- // Unknown operation
+
+ // Unknown operation
} else {
NSLog(@"Unknown export operation: %@", [contextInfo description]);
return;
@@ -289,10 +289,10 @@
// Close the file handle
[fileHandle closeFile];
-
+
if ( !success ) {
NSBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, nil,
- NSLocalizedString(@"Couldn't write to file. Be sure that you have the necessary privileges.", @"message of panel when file cannot be written"));
+ NSLocalizedString(@"Couldn't write to file. Be sure that you have the necessary privileges.", @"message of panel when file cannot be written"));
}
// Export finished Growl notification
@@ -327,9 +327,7 @@
}
- (IBAction)changeTable:(id)sender
-{
- NSPopUpButtonCell *buttonCell = [[NSPopUpButtonCell alloc] init];
-
+{
[tableListView selectRowIndexes:[NSIndexSet indexSetWithIndex:[[tablesListInstance tables] indexOfObject:[fieldMappingPopup titleOfSelectedItem]]] byExtendingSelection:NO];
//set up tableView
@@ -340,14 +338,7 @@
[rowUpButton setEnabled:([importArray count] > 1)];
[recordCountLabel setStringValue:[NSString stringWithFormat:@"%i of %i records", currentRow+1, [importArray count]]];
- //set up tableView buttons
- [buttonCell setControlSize:NSSmallControlSize];
- [buttonCell setFont:[NSFont labelFontOfSize:[NSFont smallSystemFontSize]]];
- [buttonCell setBordered:NO];
- [buttonCell addItemWithTitle:NSLocalizedString(@"Do not import", @"text for csv import drop downs")];
- [buttonCell addItemsWithTitles:[importArray objectAtIndex:currentRow]];
-
- [[fieldMappingTableView tableColumnWithIdentifier:@"value"] setDataCell:buttonCell];
+ [self updateFieldMappingButtonCell];
[fieldMappingTableView reloadData];
}
@@ -403,7 +394,7 @@
//import dump file
NSArray *queries;
int i;
-
+
//open progress sheet
[NSApp beginSheet:singleProgressSheet
modalForWindow:tableWindow
@@ -417,7 +408,7 @@
//get array with an object for each mysql-query
queries = [self splitQueries:dumpFile];
-
+
[singleProgressBar stopAnimation:self];
[singleProgressBar setUsesThreadedAnimation:NO];
[singleProgressBar setIndeterminate:NO];
@@ -452,9 +443,9 @@
[errorsSheet orderOut:nil];
}
- ////////////////
- // IMPORT CSV //
- ////////////////
+ ////////////////
+ // IMPORT CSV //
+ ////////////////
} else if ( [fileType isEqualToString:@"CSV"] ) {
//import csv file
@@ -518,11 +509,10 @@
[buttonCell setControlSize:NSSmallControlSize];
[buttonCell setFont:[NSFont labelFontOfSize:[NSFont smallSystemFontSize]]];
[buttonCell setBordered:NO];
- [buttonCell addItemWithTitle:NSLocalizedString(@"Do not import", @"text for csv import drop downs")];
- [buttonCell addItemsWithTitles:[tableSourceInstance fieldNames]];
+ [[fieldMappingTableView tableColumnWithIdentifier:@"value"] setDataCell:buttonCell];
+ [self updateFieldMappingButtonCell];
+ [fieldMappingTableView reloadData];
- [[fieldMappingTableView tableColumnWithIdentifier:@"1"] setDataCell:buttonCell];
-
// show fieldMapping sheet
[NSApp beginSheet:fieldMappingSheet
modalForWindow:tableWindow
@@ -574,7 +564,7 @@
if ([[fieldMappingArray objectAtIndex:j] intValue] > 0) {
if ( [fValues length] )
[fValues appendString:@","];
-
+
if ([[[importArray objectAtIndex:i] objectAtIndex:([[fieldMappingArray objectAtIndex:j] intValue] - 1)] isMemberOfClass:[NSNull class]] ) {
[fValues appendString:@"NULL"];
} else {
@@ -637,15 +627,15 @@
if ( fieldMappingArray ) {
-// for ( i = 0 ; i < [fieldMappingArray count] ; i++ ) {
-//
-// if ( [[[importArray objectAtIndex:currentRow] objectAtIndex:i] isKindOfClass:[NSNull class]] ) {
-// [fieldMappingArray replaceObjectAtIndex:i withObject:0];
-//
-// } else {
-// [fieldMappingArray replaceObjectAtIndex:i withObject:[[importArray objectAtIndex:currentRow] objectAtIndex:0]];
-// }
-// }
+ // for ( i = 0 ; i < [fieldMappingArray count] ; i++ ) {
+ //
+ // if ( [[[importArray objectAtIndex:currentRow] objectAtIndex:i] isKindOfClass:[NSNull class]] ) {
+ // [fieldMappingArray replaceObjectAtIndex:i withObject:0];
+ //
+ // } else {
+ // [fieldMappingArray replaceObjectAtIndex:i withObject:[[importArray objectAtIndex:currentRow] objectAtIndex:0]];
+ // }
+ // }
} else {
fieldMappingArray = [NSMutableArray array];
@@ -656,7 +646,7 @@
} else {
value = 0;
}
-
+
[fieldMappingArray addObject:[NSNumber numberWithInt:value]];
}
@@ -666,6 +656,22 @@
[fieldMappingTableView reloadData];
}
+/*
+ * Update the NSButtonCell items for use in the field mapping display
+ */
+- (void)updateFieldMappingButtonCell
+{
+ int i;
+
+ [fieldMappingButtonOptions setArray:[importArray objectAtIndex:currentRow]];
+ for (i = 0; i < [fieldMappingButtonOptions count]; i++) {
+ if ([[fieldMappingButtonOptions objectAtIndex:i] isNSNull]) {
+ [fieldMappingButtonOptions replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%i. %@", i+1, [prefs objectForKey:@"nullValue"]]];
+ } else {
+ [fieldMappingButtonOptions replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%i. %@", i+1, [fieldMappingButtonOptions objectAtIndex:i]]];
+ }
+ }
+}
- (IBAction)stepRow:(id)sender
/*
@@ -677,6 +683,7 @@
} else {
currentRow++;
}
+ [self updateFieldMappingButtonCell];
//-----------[self setupFieldMappingArray];
[fieldMappingTableView reloadData];
@@ -722,23 +729,23 @@
// Open the progress sheet
[NSApp beginSheet:singleProgressSheet
- modalForWindow:tableWindow modalDelegate:self
- didEndSelector:nil contextInfo:nil];
-
+ modalForWindow:tableWindow modalDelegate:self
+ didEndSelector:nil contextInfo:nil];
+
// Copy over the selected table names into a table in preparation for iteration
for ( i = 0 ; i < [tables count] ; i++ ) {
if ( [[[tables objectAtIndex:i] objectAtIndex:0] boolValue] ) {
[selectedTables addObject:[NSString stringWithString:[[tables objectAtIndex:i] objectAtIndex:1]]];
}
}
-
+
// Add the dump header to the dump file.
[headerString setString:@"# Sequel Pro dump\n"];
[headerString appendString:[NSString stringWithFormat:@"# Version %@\n",
- [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]]];
+ [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]]];
[headerString appendString:@"# http://code.google.com/p/sequel-pro\n#\n"];
[headerString appendString:[NSString stringWithFormat:@"# Host: %@ (MySQL %@)\n",
- [tableDocumentInstance host], [tableDocumentInstance mySQLVersion]]];
+ [tableDocumentInstance host], [tableDocumentInstance mySQLVersion]]];
[headerString appendString:[NSString stringWithFormat:@"# Database: %@\n", [tableDocumentInstance database]]];
[headerString appendString:[NSString stringWithFormat:@"# Generation Time: %@\n", [NSDate date]]];
[headerString appendString:@"# ************************************************************\n\n"];
@@ -747,7 +754,7 @@
// Loop through the selected tables
for ( i = 0 ; i < [selectedTables count] ; i++ ) {
lastProgressValue = 0;
-
+
// Update the progress text and reset the progress bar to indeterminate status while fetching data
tableName = [selectedTables objectAtIndex:i];
[singleProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %i of %i (%@): Fetching data...", @"text showing that app is fetching data for table dump"), (i+1), [selectedTables count], tableName]];
@@ -755,17 +762,17 @@
[singleProgressBar setIndeterminate:YES];
[singleProgressBar setUsesThreadedAnimation:YES];
[singleProgressBar startAnimation:self];
-
+
// Add the name of table
[fileHandle writeData:[[NSString stringWithFormat:@"# Dump of table %@\n# ------------------------------------------------------------\n\n", tableName]
- dataUsingEncoding:connectionEncoding]];
-
-
+ dataUsingEncoding:connectionEncoding]];
+
+
// Add a "drop table" command if specified in the export dialog
if ( [addDropTableSwitch state] == NSOnState )
[fileHandle writeData:[[NSString stringWithFormat:@"DROP TABLE IF EXISTS `%@`;\n\n", tableName]
- dataUsingEncoding:connectionEncoding]];
-
+ dataUsingEncoding:connectionEncoding]];
+
// Add the create syntax for the table if specified in the export dialog
if ( [addCreateTableSwitch state] == NSOnState ) {
queryResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW CREATE TABLE `%@`", tableName]];
@@ -784,7 +791,7 @@
}
}
}
-
+
// Add the table content if required
if ( [addTableContentSwitch state] == NSOnState ) {
queryResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SELECT * FROM `%@`", tableName]];
@@ -799,56 +806,56 @@
[singleProgressBar setIndeterminate:NO];
[singleProgressBar setDoubleValue:0];
[singleProgressBar displayIfNeeded];
-
+
if (rowCount) {
[queryResult dataSeek:0];
queryLength = 0;
-
+
// Construct the start of the insertion command
[fileHandle writeData:[[NSString stringWithFormat:@"INSERT INTO `%@` (`%@`)\nVALUES\n\t(",
- tableName, [fieldNames componentsJoinedByString:@"`,`"]] dataUsingEncoding:connectionEncoding]];
+ tableName, [fieldNames componentsJoinedByString:@"`,`"]] dataUsingEncoding:connectionEncoding]];
// Iterate through the rows to construct a VALUES group for each
for ( j = 0 ; j < rowCount ; j++ ) {
theRow = [queryResult fetchRowAsArray];
[sqlString setString:@""];
-
+
// Update the progress bar
[singleProgressBar setDoubleValue:((j+1)*100/rowCount)];
if ((int)[singleProgressBar doubleValue] > lastProgressValue) {
lastProgressValue = (int)[singleProgressBar doubleValue];
[singleProgressBar displayIfNeeded];
}
-
+
for ( t = 0 ; t < [theRow count] ; t++ ) {
-
+
// Add NULL values directly to the output row
if ( [[theRow objectAtIndex:t] isMemberOfClass:[NSNull class]] ) {
[sqlString appendString:@"NULL"];
-
- // Add data types directly as hex data
+
+ // Add data types directly as hex data
} else if ( [[theRow objectAtIndex:t] isKindOfClass:[NSData class]] ) {
[sqlString appendString:@"X'"];
[sqlString appendString:[mySQLConnection prepareBinaryData:[theRow objectAtIndex:t]]];
[sqlString appendString:@"'"];
-
+
} else {
[cellValue setString:[[theRow objectAtIndex:t] description]];
// Add empty strings as a pair of quotes
if ([cellValue length] == 0) {
[sqlString appendString:@"''"];
-
+
} else {
-
+
// Test whether this cell contains a number
sqlNumericTester = [NSScanner scannerWithString:cellValue];
// If it does contain a number, add the number directly
if ([sqlNumericTester scanFloat:nil] && [sqlNumericTester isAtEnd]) {
[sqlString appendString:cellValue];
-
- // Otherwise add a quoted string with special characters escaped
+
+ // Otherwise add a quoted string with special characters escaped
} else {
[sqlString appendString:@"'"];
[sqlString appendString:[mySQLConnection prepareString:cellValue]];
@@ -860,16 +867,16 @@
// Add the field separator if this isn't the last cell in the row
if (t != [theRow count] - 1) [sqlString appendString:@","];
}
-
+
queryLength += [sqlString length];
// Close this VALUES group and set up the next one if appropriate
if (j != rowCount - 1) {
-
+
// Add a new INSERT starter command every ~250k of data.
if (queryLength > 250000) {
[sqlString appendString:[NSString stringWithFormat:@");\n\nINSERT INTO `%@` (`%@`)\nVALUES\n\t(",
- tableName, [fieldNames componentsJoinedByString:@"`,`"]]];
+ tableName, [fieldNames componentsJoinedByString:@"`,`"]]];
queryLength = 0;
} else {
[sqlString appendString:@"),\n\t("];
@@ -881,24 +888,24 @@
// Write this row to the file
[fileHandle writeData:[sqlString dataUsingEncoding:connectionEncoding]];
}
-
+
// Complete the command
[fileHandle writeData:[[NSString stringWithString:@";\n\n"] dataUsingEncoding:connectionEncoding]];
-
+
if ( ![[mySQLConnection getLastErrorMessage] isEqualToString:@""] ) {
[errors appendString:[NSString stringWithFormat:@"%@\n", [mySQLConnection getLastErrorMessage]]];
if ( [addErrorsSwitch state] == NSOnState ) {
[fileHandle writeData:[[NSString stringWithFormat:@"# Error: %@\n", [mySQLConnection getLastErrorMessage]]
- dataUsingEncoding:connectionEncoding]];
+ dataUsingEncoding:connectionEncoding]];
}
}
}
}
-
+
// Add an additional separator between tables
[fileHandle writeData:[[NSString stringWithString:@"\n\n"] dataUsingEncoding:connectionEncoding]];
}
-
+
// Close the progress sheet
[NSApp endSheet:singleProgressSheet];
[singleProgressSheet orderOut:nil];
@@ -922,7 +929,7 @@
Takes an array and writes it in CSV format to the supplied NSFileHandle
*/
- (BOOL)writeCsvForArray:(NSArray *)array orQueryResult:(CMMCPResult *)queryResult toFileHandle:(NSFileHandle *)fileHandle outputFieldNames:(BOOL)outputFieldNames terminatedBy:(NSString *)fieldSeparatorString
- enclosedBy:(NSString *)enclosingString escapedBy:(NSString *)escapeString lineEnds:(NSString *)lineEndString silently:(BOOL)silently;
+ enclosedBy:(NSString *)enclosingString escapedBy:(NSString *)escapeString lineEnds:(NSString *)lineEndString silently:(BOOL)silently;
{
NSStringEncoding tableEncoding = [CMMCPConnection encodingForMySQLEncoding:[[tableDocumentInstance encoding] cString]];
NSMutableString *csvCell = [NSMutableString string];
@@ -935,31 +942,31 @@
BOOL quoteFieldSeparators = [enclosingString isEqualToString:@""];
BOOL csvCellIsNumeric;
int i, j, startingRow, totalRows, progressBarWidth, lastProgressValue;
-
+
if (queryResult != nil && [queryResult numOfRows]) [queryResult dataSeek:0];
-
+
// Detect and restore special characters being used as terminating or line end strings
NSMutableString *tempSeparatorString = [NSMutableString stringWithString:fieldSeparatorString];
[tempSeparatorString replaceOccurrencesOfString:@"\\t" withString:@"\t"
- options:NSLiteralSearch
- range:NSMakeRange(0, [tempSeparatorString length])];
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [tempSeparatorString length])];
[tempSeparatorString replaceOccurrencesOfString:@"\\n" withString:@"\n"
- options:NSLiteralSearch
- range:NSMakeRange(0, [tempSeparatorString length])];
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [tempSeparatorString length])];
[tempSeparatorString replaceOccurrencesOfString:@"\\r" withString:@"\r"
- options:NSLiteralSearch
- range:NSMakeRange(0, [tempSeparatorString length])];
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [tempSeparatorString length])];
fieldSeparatorString = [NSString stringWithString:tempSeparatorString];
NSMutableString *tempLineEndString = [NSMutableString stringWithString:lineEndString];
[tempLineEndString replaceOccurrencesOfString:@"\\t" withString:@"\t"
- options:NSLiteralSearch
- range:NSMakeRange(0, [tempLineEndString length])];
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [tempLineEndString length])];
[tempLineEndString replaceOccurrencesOfString:@"\\n" withString:@"\n"
- options:NSLiteralSearch
- range:NSMakeRange(0, [tempLineEndString length])];
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [tempLineEndString length])];
[tempLineEndString replaceOccurrencesOfString:@"\\r" withString:@"\r"
- options:NSLiteralSearch
- range:NSMakeRange(0, [tempLineEndString length])];
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [tempLineEndString length])];
lineEndString = [NSString stringWithString:tempLineEndString];
// Updating the progress bar can take >20% of processing time - store details to only update when required
@@ -967,13 +974,13 @@
lastProgressValue = 0;
[singleProgressBar setDoubleValue:0];
[singleProgressBar displayIfNeeded];
-
+
if ( !silently ) {
-
+
// Set the progress text
[singleProgressText setStringValue:NSLocalizedString(@"Exporting...", @"text showing that app is exporting to text file")];
[singleProgressText displayIfNeeded];
-
+
// Open progress sheet
[NSApp beginSheet:singleProgressSheet
@@ -986,7 +993,7 @@
escapedFieldSeparatorString = [NSString stringWithFormat:@"%@%@", escapeString, fieldSeparatorString];
escapedEnclosingString = [NSString stringWithFormat:@"%@%@", escapeString, enclosingString];
escapedLineEndString = [NSString stringWithFormat:@"%@%@", escapeString, lineEndString];
-
+
// Determine the total number of rows and starting row depending on supplied data format
if (array == nil) {
startingRow = outputFieldNames ? -1 : 0;
@@ -998,17 +1005,17 @@
// Walk through the supplied data constructing the CSV string
for ( i = startingRow ; i < totalRows ; i++ ) {
-
+
// Update the progress bar
[singleProgressBar setDoubleValue:((i+1)*100/totalRows)];
if ((int)[singleProgressBar doubleValue] > lastProgressValue) {
lastProgressValue = (int)[singleProgressBar doubleValue];
[singleProgressBar displayIfNeeded];
}
-
+
// Retrieve the row from the supplied data
if (array == nil) {
-
+
// Header row
if (i == -1) {
[csvRow setArray:[queryResult fetchFieldNames]];
@@ -1018,16 +1025,17 @@
} else {
[csvRow setArray:[array objectAtIndex:i]];
}
-
+
[csvString setString:@""];
for ( j = 0 ; j < [csvRow count] ; j++ ) {
-
- // For NULL objects supplied from a queryResult, no data is added to the cell
+
+ // For NULL objects supplied from a queryResult, add an unenclosed null string as per prefs
if ([[csvRow objectAtIndex:j] isKindOfClass:[NSNull class]]) {
- [csvString appendString:fieldSeparatorString];
+ [csvString appendString:nullString];
+ if (j < [csvRow count] - 1) [csvString appendString:fieldSeparatorString];
continue;
}
-
+
// Retrieve the contents of this cell
if ([[csvRow objectAtIndex:j] isKindOfClass:[NSData class]]) {
dataConversionString = [[NSString alloc] initWithData:[csvRow objectAtIndex:j] encoding:tableEncoding];
@@ -1036,15 +1044,16 @@
} else {
[csvCell setString:[[csvRow objectAtIndex:j] description]];
}
-
- // For NULL values supplied via an array no cell needs to be written.
+
+ // For NULL values supplied via an array add the unenclosed null string as set in preferences
if ( [csvCell isEqualToString:nullString] ) {
+ [csvString appendString:nullString];
// Add empty strings as a pair of enclosing characters.
} else if ( [csvCell length] == 0 ) {
[csvString appendString:enclosingString];
[csvString appendString:enclosingString];
-
+
} else {
// Test whether this cell contains a number
@@ -1057,31 +1066,33 @@
// Escape any occurrences of the escaping character
[csvCell replaceOccurrencesOfString:escapeString
- withString:escapedEscapeString
- options:NSLiteralSearch
- range:NSMakeRange(0,[csvCell length])];
-
+ withString:escapedEscapeString
+ options:NSLiteralSearch
+ range:NSMakeRange(0,[csvCell length])];
+
// Escape any occurrences of the enclosure string
if ( ![escapeString isEqualToString:enclosingString] ) {
[csvCell replaceOccurrencesOfString:enclosingString
- withString:escapedEnclosingString
- options:NSLiteralSearch
- range:NSMakeRange(0,[csvCell length])];
+ withString:escapedEnclosingString
+ options:NSLiteralSearch
+ range:NSMakeRange(0,[csvCell length])];
}
+
+ // Escape occurrences of the line end character
+ [csvCell replaceOccurrencesOfString:lineEndString
+ withString:escapedLineEndString
+ options:NSLiteralSearch
+ range:NSMakeRange(0,[csvCell length])];
// If the string isn't quoted or otherwise enclosed, escape occurrences of the
- // field separators and the line ending separator.
+ // field separators
if ( quoteFieldSeparators || csvCellIsNumeric ) {
[csvCell replaceOccurrencesOfString:fieldSeparatorString
- withString:escapedFieldSeparatorString
- options:NSLiteralSearch
- range:NSMakeRange(0,[csvCell length])];
- [csvCell replaceOccurrencesOfString:lineEndString
- withString:escapedLineEndString
- options:NSLiteralSearch
- range:NSMakeRange(0,[csvCell length])];
+ withString:escapedFieldSeparatorString
+ options:NSLiteralSearch
+ range:NSMakeRange(0,[csvCell length])];
}
-
+
// Write out the cell data by appending strings - this is significantly faster than stringWithFormat.
if (csvCellIsNumeric) {
[csvString appendString:csvCell];
@@ -1091,12 +1102,12 @@
[csvString appendString:enclosingString];
}
}
- [csvString appendString:fieldSeparatorString];
+ if (j < [csvRow count] - 1) [csvString appendString:fieldSeparatorString];
}
-
+
// Append the line ending to the string for this row
[csvString appendString:lineEndString];
-
+
// Write it to the fileHandle
[fileHandle writeData:[csvString dataUsingEncoding:tableEncoding]];
}
@@ -1127,7 +1138,7 @@
BOOL isEscaped, br;
int fieldCount = nil;
int x,i,j;
-
+
//repare tabs and line ends
tempTerminated = [NSMutableString stringWithString:terminated];
[tempTerminated replaceOccurrencesOfString:@"\\t" withString:@"\t"
@@ -1185,7 +1196,10 @@
}
}
- //add line to array
+ // Skip blank lines
+ if (![tempString length]) continue;
+
+ // Add the line to the array
[linesArray addObject:[NSString stringWithString:tempString]];
}
@@ -1198,13 +1212,14 @@
fieldCount = [tempRowArray count];
} else {
while ( [tempRowArray count] < fieldCount ) {
- [tempRowArray addObject:@"NULL"];
+ [tempRowArray addObject:[NSString stringWithString:[prefs objectForKey:@"nullValue"]]];
}
}
for ( i = 0 ; i < [tempRowArray count] ; i++ ) {
- if ( [[tempRowArray objectAtIndex:i] isEqualToString:@"NULL"] || [[tempRowArray objectAtIndex:i] isEqualToString:@""] || [[tempRowArray objectAtIndex:i] isEqualToString:@"\\N"] || [[tempRowArray objectAtIndex:i] isEqualToString:[prefs objectForKey:@"nullValue"]] ) {
-
- //put nsnull object to array if field contains un-enclosed NULL string
+
+ // Insert a NSNull object if the cell contains an unescaped null character or an unescaped string
+ // which matches the NULL string set in preferences.
+ if ( [[tempRowArray objectAtIndex:i] isEqualToString:@"\\N"] || [[tempRowArray objectAtIndex:i] isEqualToString:[prefs objectForKey:@"nullValue"]] ) {
[tempRowArray replaceObjectAtIndex:i withObject:[NSNull null]];
} else {
@@ -1221,6 +1236,11 @@
[mutableField deleteCharactersInRange:NSMakeRange(([mutableField length]-[enclosed length]),[enclosed length])];
}
}
+ if ( [mutableField length] >= [enclosed length] ) {
+ if ( [[mutableField substringFromIndex:([mutableField length]-[enclosed length])] isEqualToString:enclosed] ) {
+ [mutableField deleteCharactersInRange:NSMakeRange(([mutableField length]-[enclosed length]),[enclosed length])];
+ }
+ }
//strip escaped characters
if ( ![enclosed isEqualToString:@""] ) {
[mutableField replaceOccurrencesOfString:[NSString stringWithFormat:@"%@%@", escaped, enclosed] withString:enclosed options:NSLiteralSearch range:NSMakeRange(0, [mutableField length])];
@@ -1259,13 +1279,13 @@
int i,j, startingRow, totalRows, progressBarWidth, lastProgressValue;
if (queryResult != nil && [queryResult numOfRows]) [queryResult dataSeek:0];
-
+
// Updating the progress bar can take >20% of processing time - store details to only update when required
progressBarWidth = (int)[singleProgressBar bounds].size.width;
lastProgressValue = 0;
[singleProgressBar setDoubleValue:0];
[singleProgressBar displayIfNeeded];
-
+
// Set up an array of encoded field names as opening and closing tags
if (array == nil) {
[xmlRow setArray:[queryResult fetchFieldNames]];
@@ -1275,17 +1295,17 @@
for ( j = 0; j < [xmlRow count]; j++ ) {
[xmlTags addObject:[NSMutableArray array]];
[[xmlTags objectAtIndex:j] addObject:[NSString stringWithFormat:@"\t\t<%@>",
- [self htmlEscapeString:[[xmlRow objectAtIndex:j] description]]]];
+ [self htmlEscapeString:[[xmlRow objectAtIndex:j] description]]]];
[[xmlTags objectAtIndex:j] addObject:[NSString stringWithFormat:@"</%@>\n",
- [self htmlEscapeString:[[xmlRow objectAtIndex:j] description]]]];
+ [self htmlEscapeString:[[xmlRow objectAtIndex:j] description]]]];
}
if ( !silently ) {
-
+
// Set the progress text
[singleProgressText setStringValue:NSLocalizedString(@"Writing...", @"text showing that app is writing text file")];
[singleProgressText displayIfNeeded];
-
+
// Open progress sheet
[NSApp beginSheet:singleProgressSheet
modalForWindow:tableWindow modalDelegate:self
@@ -1298,21 +1318,21 @@
[xmlString appendString:@"<!--\n-\n"];
[xmlString appendString:@"- Sequel Pro dump\n"];
[xmlString appendString:[NSString stringWithFormat:@"- Version %@\n",
- [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]]];
+ [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]]];
[xmlString appendString:@"- http://code.google.com/p/sequel-pro\n-\n"];
[xmlString appendString:[NSString stringWithFormat:@"- Host: %@ (MySQL %@)\n",
- [tableDocumentInstance host], [tableDocumentInstance mySQLVersion]]];
+ [tableDocumentInstance host], [tableDocumentInstance mySQLVersion]]];
[xmlString appendString:[NSString stringWithFormat:@"- Database: %@\n", [tableDocumentInstance database]]];
[xmlString appendString:[NSString stringWithFormat:@"- Generation Time: %@\n", [NSDate date]]];
[xmlString appendString:@"-\n-->\n\n"];
[fileHandle writeData:[xmlString dataUsingEncoding:tableEncoding]];
}
-
+
// Write an opening tag in the form of the table name
[fileHandle writeData:[[NSString stringWithFormat:@"\t<%@>\n",
- [self htmlEscapeString:table]]
- dataUsingEncoding:tableEncoding]];
-
+ [self htmlEscapeString:table]]
+ dataUsingEncoding:tableEncoding]];
+
// Determine the total number of rows and starting row depending on supplied data format
if (array == nil) {
startingRow = 0;
@@ -1321,28 +1341,28 @@
startingRow = 1;
totalRows = [array count];
}
-
+
// Walk through the array, contructing the XML string.
for ( i = 1 ; i < totalRows ; i++ ) {
-
+
// Update the progress bar
[singleProgressBar setDoubleValue:((i+1)*100/totalRows)];
if ((int)[singleProgressBar doubleValue] > lastProgressValue) {
lastProgressValue = (int)[singleProgressBar doubleValue];
[singleProgressBar displayIfNeeded];
}
-
+
// Retrieve the row from the supplied data
if (array == nil) {
[xmlRow setArray:[queryResult fetchRowAsArray]];
} else {
[xmlRow setArray:[array objectAtIndex:i]];
}
-
+
// Construct the row
[xmlString setString:@"\t<row>\n"];
for ( j = 0 ; j < [xmlRow count] ; j++ ) {
-
+
// Retrieve the contents of this tag
if ([[xmlRow objectAtIndex:j] isKindOfClass:[NSData class]]) {
dataConversionString = [[NSString alloc] initWithData:[xmlRow objectAtIndex:j] encoding:tableEncoding];
@@ -1351,7 +1371,7 @@
} else {
[xmlItem setString:[[xmlRow objectAtIndex:j] description]];
}
-
+
// Add the opening and closing tag and the contents to the XML string
[xmlString appendString:[[xmlTags objectAtIndex:j] objectAtIndex:0]];
[xmlString appendString:[self htmlEscapeString:xmlItem]];
@@ -1362,12 +1382,12 @@
// Write the row to the filehandle
[fileHandle writeData:[xmlString dataUsingEncoding:tableEncoding]];
}
-
+
// Write the closing tag for the table
[fileHandle writeData:[[NSString stringWithFormat:@"\t</%@>",
- [self htmlEscapeString:table]]
- dataUsingEncoding:tableEncoding]];
-
+ [self htmlEscapeString:table]]
+ dataUsingEncoding:tableEncoding]];
+
// Close the progress sheet if appropriate
if ( !silently ) {
[NSApp endSheet:singleProgressSheet];
@@ -1385,14 +1405,14 @@
{
int i;
NSMutableArray *selectedTables = [NSMutableArray array];
-
+
// Extract the table names of the selected tables
for ( i = 0 ; i < [tables count] ; i++ ) {
if ( [[[tables objectAtIndex:i] objectAtIndex:0] boolValue] ) {
[selectedTables addObject:[NSString stringWithString:[[tables objectAtIndex:i] objectAtIndex:1]]];
}
}
-
+
return [self exportTables:selectedTables toFileHandle:fileHandle usingFormat:type];
}
@@ -1408,7 +1428,8 @@
NSMutableString *infoString = [NSMutableString string];
NSMutableString *errors = [NSMutableString string];
NSStringEncoding connectionEncoding = [mySQLConnection encoding];
-
+ NSMutableString *csvLineEnd;
+
// Reset the interface
[errorsView setString:@""];
[errorsView displayIfNeeded];
@@ -1416,37 +1437,49 @@
[singleProgressText displayIfNeeded];
[singleProgressBar setDoubleValue:0];
[singleProgressBar displayIfNeeded];
-
+
// Open the progress sheet
[NSApp beginSheet:singleProgressSheet
- modalForWindow:tableWindow modalDelegate:self
- didEndSelector:nil contextInfo:nil];
-
-
- // Add the dump header to the dump file, dependant on export type.
+ modalForWindow:tableWindow modalDelegate:self
+ didEndSelector:nil contextInfo:nil];
+
+
+ // Add a dump header to the dump file, dependant on export type.
if ( [type isEqualToString:@"csv"] ) {
- [infoString setString:[NSString stringWithFormat:@"Host: %@ Database: %@ Generation Time: %@\n\n",
- [tableDocumentInstance host], [tableDocumentInstance database], [NSDate date]]];
+ csvLineEnd = [NSMutableString stringWithString:[exportMultipleLinesTerminatedField stringValue]];
+ [csvLineEnd replaceOccurrencesOfString:@"\\t" withString:@"\t"
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [csvLineEnd length])];
+ [csvLineEnd replaceOccurrencesOfString:@"\\n" withString:@"\n"
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [csvLineEnd length])];
+ [csvLineEnd replaceOccurrencesOfString:@"\\r" withString:@"\r"
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [csvLineEnd length])];
+ if ([selectedTables count] > 1) {
+ [infoString setString:[NSString stringWithFormat:@"Host: %@ Database: %@ Generation Time: %@%@%@",
+ [tableDocumentInstance host], [tableDocumentInstance database], [NSDate date], csvLineEnd, csvLineEnd]];
+ }
} else if ( [type isEqualToString:@"xml"] ) {
[infoString setString:@"<?xml version=\"1.0\"?>\n\n"];
[infoString appendString:@"<!--\n-\n"];
[infoString appendString:@"- Sequel Pro dump\n"];
[infoString appendString:[NSString stringWithFormat:@"- Version %@\n",
- [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]]];
+ [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]]];
[infoString appendString:@"- http://code.google.com/p/sequel-pro\n-\n"];
[infoString appendString:[NSString stringWithFormat:@"- Host: %@ (MySQL %@)\n",
- [tableDocumentInstance host], [tableDocumentInstance mySQLVersion]]];
+ [tableDocumentInstance host], [tableDocumentInstance mySQLVersion]]];
[infoString appendString:[NSString stringWithFormat:@"- Database: %@\n", [tableDocumentInstance database]]];
[infoString appendString:[NSString stringWithFormat:@"- Generation Time: %@\n", [NSDate date]]];
[infoString appendString:@"-\n-->\n\n\n"];
[infoString appendString:[NSString stringWithFormat:@"<%@>\n\n\n",
- [self htmlEscapeString:[tableDocumentInstance database]]]];
+ [self htmlEscapeString:[tableDocumentInstance database]]]];
}
[fileHandle writeData:[infoString dataUsingEncoding:connectionEncoding]];
-
+
// Loop through the selected tables
for ( i = 0 ; i < [selectedTables count] ; i++ ) {
-
+
// Update the progress text and reset the progress bar to indeterminate status
tableName = [selectedTables objectAtIndex:i];
[singleProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %i of %i (%@): fetching data...", @"text showing that app is fetching data for table dump"), (i+1), [selectedTables count], tableName]];
@@ -1454,20 +1487,20 @@
[singleProgressBar setIndeterminate:YES];
[singleProgressBar setUsesThreadedAnimation:YES];
[singleProgressBar startAnimation:self];
-
- // For CSV exports, output the name of the table
- if ( [type isEqualToString:@"csv"] ) {
- [fileHandle writeData:[[NSString stringWithFormat:@"Table %@\n\n", tableName] dataUsingEncoding:connectionEncoding]];
+
+ // For CSV exports of more than one table, output the name of the table
+ if ( [type isEqualToString:@"csv"] && [selectedTables count] > 1) {
+ [fileHandle writeData:[[NSString stringWithFormat:@"Table %@%@%@", tableName, csvLineEnd, csvLineEnd] dataUsingEncoding:connectionEncoding]];
}
-
+
// Retrieve all the content within this table
queryResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SELECT * FROM `%@`", tableName]];
-
+
// Note any errors during retrieval
if ( ![[mySQLConnection getLastErrorMessage] isEqualToString:@""] ) {
[errors appendString:[NSString stringWithFormat:@"%@\n", [mySQLConnection getLastErrorMessage]]];
}
-
+
// Update the progress text and set the progress bar back to determinate
[singleProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %i of %i (%@): Writing...", @"text showing that app is writing data for table export"), (i+1), [selectedTables count], tableName]];
[singleProgressText displayIfNeeded];
@@ -1476,36 +1509,40 @@
[singleProgressBar setIndeterminate:NO];
[singleProgressBar setDoubleValue:0];
[singleProgressBar displayIfNeeded];
-
+
// Use the appropriate export method to write the data to file
if ( [type isEqualToString:@"csv"] ) {
[self writeCsvForArray:nil orQueryResult:queryResult
- toFileHandle:fileHandle
- outputFieldNames:[exportMultipleFieldNamesSwitch state]
- terminatedBy:[exportMultipleFieldsTerminatedField stringValue]
- enclosedBy:[exportMultipleFieldsEnclosedField stringValue]
- escapedBy:[exportMultipleFieldsEscapedField stringValue]
- lineEnds:[exportMultipleLinesTerminatedField stringValue]
- silently:YES];
+ toFileHandle:fileHandle
+ outputFieldNames:[exportMultipleFieldNamesSwitch state]
+ terminatedBy:[exportMultipleFieldsTerminatedField stringValue]
+ enclosedBy:[exportMultipleFieldsEnclosedField stringValue]
+ escapedBy:[exportMultipleFieldsEscapedField stringValue]
+ lineEnds:[exportMultipleLinesTerminatedField stringValue]
+ silently:YES];
+
+ // Add a spacer to the file
+ [fileHandle writeData:[[NSString stringWithFormat:@"%@%@%@", csvLineEnd, csvLineEnd, csvLineEnd] dataUsingEncoding:connectionEncoding]];
} else if ( [type isEqualToString:@"xml"] ) {
[self writeXmlForArray:nil orQueryResult:queryResult
- toFileHandle:fileHandle
- tableName:tableName
- withHeader:NO
- silently:YES];
+ toFileHandle:fileHandle
+ tableName:tableName
+ withHeader:NO
+ silently:YES];
+
+ // Add a spacer to the file
+ [fileHandle writeData:[[NSString stringWithString:@"\n\n\n"] dataUsingEncoding:connectionEncoding]];
}
- // Add a spacer to the file
- [fileHandle writeData:[[NSString stringWithString:@"\n\n\n"] dataUsingEncoding:connectionEncoding]];
}
-
+
// For XML output, close the database tag
if ( [type isEqualToString:@"xml"] ) {
[fileHandle writeData:[[NSString stringWithFormat:@"</%@>",
[self htmlEscapeString:[tableDocumentInstance database]]]
- dataUsingEncoding:connectionEncoding]];
+ dataUsingEncoding:connectionEncoding]];
}
-
+
// Close the progress sheet
[NSApp endSheet:singleProgressSheet];
[singleProgressSheet orderOut:nil];
@@ -1656,13 +1693,13 @@
// For the backtick character treat the string as ended
if ( ([queries characterAtIndex:i] == '`') && (stringType == '`') ) {
-
+
inString = NO;
break;
-
- // Otherwise, prepare to treat the string as ended after a stringType....
+
+ // Otherwise, prepare to treat the string as ended after a stringType....
} else if ( [queries characterAtIndex:i] == stringType ) {
-
+
// ...but only if the stringType isn't escaped with an *odd* number of escaping characters.
escaped = NO;
j = 1;
@@ -1796,10 +1833,9 @@ objectValueForTableColumn:(NSTableColumn *)aTableColumn
if ([[[aTableColumn dataCell] class] isEqualTo:[NSPopUpButtonCell class]]) {
[(NSPopUpButtonCell *)[aTableColumn dataCell] removeAllItems];
[(NSPopUpButtonCell *)[aTableColumn dataCell] addItemWithTitle:NSLocalizedString(@"Do not import", @"text for csv import drop downs")];
- [(NSPopUpButtonCell *)[aTableColumn dataCell] addItemsWithTitles:[importArray objectAtIndex:currentRow]];
- //[(NSPopUpButtonCell *)[aTableColumn dataCell] selectItemAtIndex:[fieldMappingArray objectAtIndex:rowIndex]];
+ [(NSPopUpButtonCell *)[aTableColumn dataCell] addItemsWithTitles:fieldMappingButtonOptions];
}
-
+
return [fieldMappingArray objectAtIndex:rowIndex];
}
} else {
@@ -1832,6 +1868,7 @@ objectValueForTableColumn:(NSTableColumn *)aTableColumn
self = [super init];
tables = [[NSMutableArray alloc] init];
+ fieldMappingButtonOptions = [[NSMutableArray alloc] init];
return self;
}
@@ -1842,6 +1879,7 @@ objectValueForTableColumn:(NSTableColumn *)aTableColumn
[tables release];
[importArray release];
+ [fieldMappingButtonOptions release];
[fieldMappingArray release];
[savePath release];
[openPath release];
diff --git a/TablesList.h b/TablesList.h
index d7d37d2e..7270219b 100644
--- a/TablesList.h
+++ b/TablesList.h
@@ -92,8 +92,4 @@
- (BOOL)selectionShouldChangeInTableView:(NSTableView *)aTableView;
- (void)tableViewSelectionDidChange:(NSNotification *)aNotification;
-//last but not least
-- (id)init;
-- (void)dealloc;
-
@end
diff --git a/TablesList.m b/TablesList.m
index 500ac349..40ea87c5 100644
--- a/TablesList.m
+++ b/TablesList.m
@@ -543,12 +543,12 @@ traps enter and esc and edit/cancel without entering next row
}
}
-/*
-loads a table in content or source view (if tab selected)
-*/
+/**
+ * Loads a table in content or source view (if tab selected)
+ */
- (void)tableViewSelectionDidChange:(NSNotification *)aNotification
{
- if ( [tablesListView numberOfSelectedRows] == 1 ) {
+ if ( [tablesListView numberOfSelectedRows] == 1 ) {
if ( [tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 0 ) {
[tableSourceInstance loadTable:[tables objectAtIndex:[tablesListView selectedRow]]];
structureLoaded = YES;
@@ -575,6 +575,10 @@ loads a table in content or source view (if tab selected)
[tableWindow setTitle:[NSString stringWithFormat:@"(MySQL %@) %@@%@/%@/%@", [tableDocumentInstance mySQLVersion], [tableDocumentInstance user],
[tableDocumentInstance host], [tableDocumentInstance database], [tables objectAtIndex:[tablesListView selectedRow]]]];
+ // Update connection characater set encoding based on the table's encoding if required
+ if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"encoding"] isEqualToString:@"Autodetect"]) {
+ [tableDocumentInstance detectTableEncodingForTable:[tables objectAtIndex:[tablesListView selectedRow]]];
+ }
} else {
[tableSourceInstance loadTable:nil];
[tableContentInstance loadTable:nil];
@@ -589,8 +593,6 @@ loads a table in content or source view (if tab selected)
}
}
-
-
- (BOOL)tableView:(NSTableView *)aTableView shouldSelectRow:(int)rowIndex
{
return (rowIndex != 0);