aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/SPExportController.m2
-rw-r--r--Source/SPExportInitializer.m15
-rw-r--r--Source/SPExporter.h4
-rw-r--r--Source/SPSQLExporter.h11
-rw-r--r--Source/SPSQLExporter.m1010
-rw-r--r--Source/SPSQLExporterDelegate.m26
6 files changed, 532 insertions, 536 deletions
diff --git a/Source/SPExportController.m b/Source/SPExportController.m
index 7f8610ec..7357a9ee 100644
--- a/Source/SPExportController.m
+++ b/Source/SPExportController.m
@@ -190,7 +190,7 @@
// Export finished Growl notification
[[SPGrowlController sharedGrowlController] notifyWithTitle:@"Export Finished"
description:[NSString stringWithFormat:NSLocalizedString(@"Finished exporting to %@", @"description for finished exporting growl notification"), exportFilename]
- document:[tableDocumentInstance parentWindow]
+ document:tableDocumentInstance
notificationName:@"Export Finished"];
}
diff --git a/Source/SPExportInitializer.m b/Source/SPExportInitializer.m
index 20b38c5e..46eaf2b6 100644
--- a/Source/SPExportInitializer.m
+++ b/Source/SPExportInitializer.m
@@ -149,13 +149,10 @@
// Start the notification timer to allow notifications to be shown even if frontmost for long queries
[[SPGrowlController sharedGrowlController] setVisibilityForNotificationName:@"Export Finished"];
- // Reset the interface
- [[exportProgressTitle onMainThread] setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Exporting %@", @"text showing that the application is importing a supplied format"), exportTypeLabel]];
- [[exportProgressText onMainThread] setStringValue:NSLocalizedString(@"Writing...", @"text showing that app is writing text file")];
-
- [[exportProgressText onMainThread] displayIfNeeded];
- [[exportProgressIndicator onMainThread] setDoubleValue:0];
- [[exportProgressIndicator onMainThread] displayIfNeeded];
+ // Reset the progress interface
+ [exportProgressTitle setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Exporting %@", @"text showing that the application is importing a supplied format"), exportTypeLabel]];
+ [exportProgressText setStringValue:NSLocalizedString(@"Writing...", @"text showing that app is writing text file")];
+ [exportProgressIndicator setDoubleValue:0];
// Open the progress sheet
[NSApp beginSheet:exportProgressWindow
@@ -303,7 +300,7 @@
// Set the exporter's max progress
[sqlExporter setExportMaxProgress:((NSInteger)[exportProgressIndicator bounds].size.width)];
-
+
// Set the progress bar's max value
[exportProgressIndicator setMaxValue:[sqlExporter exportMaxProgress]];
@@ -315,7 +312,7 @@
// Create custom filename if required
filename = (createCustomFilename) ? [self expandCustomFilenameFormatFromString:[exportCustomFilenameTokenField stringValue] usingTableName:nil] : [NSString stringWithFormat:@"%@_%@", [tableDocumentInstance database], [[NSDate date] descriptionWithCalendarFormat:@"%Y-%m-%d" timeZone:nil locale:nil]];
- SPFileHandle *fileHandle = [self getFileHandleForFilePath:[[exportPathField stringValue] stringByAppendingPathComponent:[filename stringByAppendingPathExtension:([exportCompressOutputFile state]) ? @"gz" : @"sql"]]];
+ SPFileHandle *fileHandle = [self getFileHandleForFilePath:[[exportPathField stringValue] stringByAppendingPathComponent:[filename stringByAppendingPathExtension:([exportCompressOutputFile state]) ? @"sql.gz" : @"sql"]]];
[sqlExporter setExportOutputFileHandle:fileHandle];
diff --git a/Source/SPExporter.h b/Source/SPExporter.h
index 805173c9..f3c01077 100644
--- a/Source/SPExporter.h
+++ b/Source/SPExporter.h
@@ -64,7 +64,7 @@
SPFileHandle *exportOutputFileHandle;
NSStringEncoding exportOutputEncoding;
- NSInteger exportMaxProgress;
+ double exportMaxProgress;
}
@property(readwrite, retain) MCPConnection *connection;
@@ -78,6 +78,6 @@
@property(readwrite, retain) SPFileHandle *exportOutputFileHandle;
@property(readwrite, assign) NSStringEncoding exportOutputEncoding;
-@property(readwrite, assign) NSInteger exportMaxProgress;
+@property(readwrite, assign) double exportMaxProgress;
@end
diff --git a/Source/SPSQLExporter.h b/Source/SPSQLExporter.h
index 6b4702ce..735056aa 100644
--- a/Source/SPSQLExporter.h
+++ b/Source/SPSQLExporter.h
@@ -88,7 +88,12 @@
* Compress output
*/
BOOL sqlOutputCompressFile;
-
+
+ /**
+ * Number of tables processed by exporter
+ */
+ NSUInteger sqlCurrentTableExportIndex;
+
/**
* Table information
*/
@@ -111,7 +116,9 @@
@property(readwrite, assign) BOOL sqlOutputIncludeErrors;
@property(readwrite, assign) BOOL sqlOutputCompressFile;
-@property (readwrite, retain) NSDictionary *sqlTableInformation;
+@property(readwrite, assign) NSUInteger sqlCurrentTableExportIndex;
+
+@property(readwrite, retain) NSDictionary *sqlTableInformation;
/**
* Initialise an instance of SPSQLExporter using the supplied delegate.
diff --git a/Source/SPSQLExporter.m b/Source/SPSQLExporter.m
index 9b7cbaf6..99e42515 100644
--- a/Source/SPSQLExporter.m
+++ b/Source/SPSQLExporter.m
@@ -52,6 +52,7 @@
@synthesize sqlOutputEncodeBLOBasHex;
@synthesize sqlOutputIncludeErrors;
@synthesize sqlOutputCompressFile;
+@synthesize sqlCurrentTableExportIndex;
@synthesize sqlTableInformation;
/**
@@ -75,505 +76,399 @@
*/
- (void)main
{
- @try {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSAutoreleasePool *sqlExportPool = [[NSAutoreleasePool alloc] init];
-
- MCPResult *queryResult;
- MCPStreamingResult *streamingResult;
-
- NSArray *row;
- NSString *tableName;
- NSDictionary *tableDetails;
- NSMutableArray *tableColumnNumericStatus;
- SPTableType tableType = SPTableTypeTable;
-
- id createTableSyntax = nil;
- NSUInteger i, j, t, s, rowCount, queryLength, lastProgressValue;
-
- BOOL sqlOutputIncludeStructure;
- BOOL sqlOutputIncludeContent;
- BOOL sqlOutputIncludeDropSyntax;
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ NSAutoreleasePool *sqlExportPool = [[NSAutoreleasePool alloc] init];
+
+ MCPResult *queryResult;
+ MCPStreamingResult *streamingResult;
+
+ NSArray *row;
+ NSString *tableName;
+ NSDictionary *tableDetails;
+ NSMutableArray *tableColumnNumericStatus;
+ SPTableType tableType = SPTableTypeTable;
+
+ id createTableSyntax = nil;
+ NSUInteger i, j, t, s, rowCount, queryLength, lastProgressValue;
+
+ BOOL sqlOutputIncludeStructure;
+ BOOL sqlOutputIncludeContent;
+ BOOL sqlOutputIncludeDropSyntax;
+
+ NSMutableArray *tables = [NSMutableArray array];
+ NSMutableArray *procs = [NSMutableArray array];
+ NSMutableArray *funcs = [NSMutableArray array];
+
+ NSMutableString *metaString = [NSMutableString string];
+ NSMutableString *cellValue = [NSMutableString string];
+ NSMutableString *errors = [[NSMutableString alloc] init];
+ NSMutableString *sqlString = [[NSMutableString alloc] init];
+
+ NSMutableDictionary *viewSyntaxes = [NSMutableDictionary dictionary];
+
+ // Check that we have all the required info before starting the export
+ if ((![self sqlExportTables]) || ([[self sqlExportTables] count] == 0) ||
+ (![self sqlTableInformation]) || ([[self sqlTableInformation] count] == 0) ||
+ (![self sqlDatabaseHost]) || ([[self sqlDatabaseHost] isEqualToString:@""]) ||
+ (![self sqlDatabaseName]) || ([[self sqlDatabaseName] isEqualToString:@""]) ||
+ (![self sqlDatabaseVersion] || ([[self sqlDatabaseName] isEqualToString:@""])))
+ {
+ [pool release];
+ return;
+ }
+
+ // Inform the delegate that the export process is about to begin
+ [delegate performSelectorOnMainThread:@selector(sqlExportProcessWillBegin:) withObject:self waitUntilDone:NO];
+
+ // Mark the process as running
+ [self setExportProcessIsRunning:YES];
+
+ // Clear errors
+ [self setSqlExportErrors:@""];
+
+ // Copy over the selected item names into tables in preparation for iteration
+ NSMutableArray *targetArray;
+
+ for (NSArray *item in [self sqlExportTables])
+ {
+ // Check for cancellation flag
+ if ([self isCancelled]) {
+ [pool release];
+ return;
+ }
- NSMutableArray *tables = [NSMutableArray array];
- NSMutableArray *procs = [NSMutableArray array];
- NSMutableArray *funcs = [NSMutableArray array];
+ switch ([NSArrayObjectAtIndex(item, 4) intValue]) {
+ case SPTableTypeProc:
+ targetArray = procs;
+ break;
+ case SPTableTypeFunc:
+ targetArray = funcs;
+ break;
+ default:
+ targetArray = tables;
+ break;
+ }
- NSMutableString *metaString = [NSMutableString string];
- NSMutableString *cellValue = [NSMutableString string];
- NSMutableString *errors = [[NSMutableString alloc] init];
- NSMutableString *sqlString = [[NSMutableString alloc] init];
+ [targetArray addObject:item];
+ }
+
+ // If required write the UTF-8 Byte Order Mark
+ if ([self sqlOutputIncludeUTF8BOM]) {
+ [metaString setString:@"\xef\xbb\xbf"];
+ [metaString appendString:@"# ************************************************************\n"];
+ }
+ else {
+ [metaString setString:@"# ************************************************************\n"];
+ }
- NSMutableDictionary *viewSyntaxes = [NSMutableDictionary dictionary];
-
- // Check that we have all the required info before starting the export
- if ((![self sqlExportTables]) || ([[self sqlExportTables] count] == 0) ||
- (![self sqlTableInformation]) || ([[self sqlTableInformation] count] == 0) ||
- (![self sqlDatabaseHost]) || ([[self sqlDatabaseHost] isEqualToString:@""]) ||
- (![self sqlDatabaseName]) || ([[self sqlDatabaseName] isEqualToString:@""]) ||
- (![self sqlDatabaseVersion] || ([[self sqlDatabaseName] isEqualToString:@""])))
- {
+ // If required set the file handle to compress it's output
+ [[self exportOutputFileHandle] setShouldWriteWithGzipCompression:[self sqlOutputCompressFile]];
+
+ // Add the dump header to the dump file
+ [metaString appendString:@"# Sequel Pro SQL dump\n"];
+ [metaString appendString:[NSString stringWithFormat:@"# Version %@\n#\n", [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]]];
+ [metaString appendString:[NSString stringWithFormat:@"# %@\n# %@\n#\n", SPHomePageURL, SPDevURL]];
+ [metaString appendString:[NSString stringWithFormat:@"# Host: %@ (MySQL %@)\n", [self sqlDatabaseHost], [self sqlDatabaseVersion]]];
+ [metaString appendString:[NSString stringWithFormat:@"# Database: %@\n", [self sqlDatabaseName]]];
+ [metaString appendString:[NSString stringWithFormat:@"# Generation Time: %@\n", [NSDate date]]];
+ [metaString appendString:@"# ************************************************************\n\n\n"];
+
+ // Add commands to store the client encodings used when importing and set to UTF8 to preserve data
+ [metaString appendString:@"/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;\n"];
+ [metaString appendString:@"/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;\n"];
+ [metaString appendString:@"/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;\n"];
+ [metaString appendString:@"/*!40101 SET NAMES utf8 */;\n"];
+
+ // Add commands to store and disable unique checks, foreign key checks, mode and notes where supported.
+ // Include trailing semicolons to ensure they're run individually. Use MySQL-version based comments.
+ //if (sqlOutputIncludeDropSyntax) {
+ //[metaString appendString:@"/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;\n"];
+ //}
+
+ [metaString appendString:@"/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\n"];
+ [metaString appendString:@"/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\n"];
+ [metaString appendString:@"/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n\n\n"];
+
+ [[self exportOutputFileHandle] writeData:[metaString dataUsingEncoding:[self exportOutputEncoding]]];
+
+ // Loop through the selected tables
+ for (NSArray *table in [self sqlExportTables])
+ {
+ // Check for cancellation flag
+ if ([self isCancelled]) {
[pool release];
return;
}
-
- // Inform the delegate that the export process is about to begin
- [delegate performSelectorOnMainThread:@selector(sqlExportProcessWillBegin:) withObject:self waitUntilDone:NO];
- // Mark the process as running
- [self setExportProcessIsRunning:YES];
+ [self setSqlCurrentTableExportIndex:[self sqlCurrentTableExportIndex]+1];
+ tableName = NSArrayObjectAtIndex(table, 0);
+
+ sqlOutputIncludeStructure = [NSArrayObjectAtIndex(table, 1) boolValue];
+ sqlOutputIncludeContent = [NSArrayObjectAtIndex(table, 2) boolValue];
+ sqlOutputIncludeDropSyntax = [NSArrayObjectAtIndex(table, 3) boolValue];
- // Clear errors
- [self setSqlExportErrors:@""];
-
- // Copy over the selected item names into tables in preparation for iteration
- NSMutableArray *targetArray;
+ // Set the current table
+ [self setSqlExportCurrentTable:tableName];
- for (NSArray *item in [self sqlExportTables])
- {
- // Check for cancellation flag
- if ([self isCancelled]) {
- [pool release];
- return;
- }
+ // Inform the delegate that we are about to start fetcihing data for the current table
+ [delegate performSelectorOnMainThread:@selector(sqlExportProcessWillBeginFetchingData:) withObject:self waitUntilDone:NO];
+
+ lastProgressValue = 0;
+
+ // Add the name of table
+ [[self exportOutputFileHandle] writeData:[[NSString stringWithFormat:@"# Dump of table %@\n# ------------------------------------------------------------\n\n", tableName] dataUsingEncoding:[self exportOutputEncoding]]];
+
+ // Determine whether this table is a table or a view via the CREATE TABLE command, and keep the create table syntax
+ queryResult = [connection queryString:[NSString stringWithFormat:@"SHOW CREATE TABLE %@", [tableName backtickQuotedString]]];
+
+ [queryResult setReturnDataAsStrings:YES];
+
+ if ([queryResult numOfRows]) {
+ tableDetails = [[NSDictionary alloc] initWithDictionary:[queryResult fetchRowAsDictionary]];
- switch ([NSArrayObjectAtIndex(item, 4) intValue]) {
- case SPTableTypeProc:
- targetArray = procs;
- break;
- case SPTableTypeFunc:
- targetArray = funcs;
- break;
- default:
- targetArray = tables;
- break;
+ if ([tableDetails objectForKey:@"Create View"]) {
+ [viewSyntaxes setValue:[[[[tableDetails objectForKey:@"Create View"] copy] autorelease] createViewSyntaxPrettifier] forKey:tableName];
+ createTableSyntax = [self _createViewPlaceholderSyntaxForView:tableName];
+ tableType = SPTableTypeView;
+ }
+ else {
+ createTableSyntax = [[[tableDetails objectForKey:@"Create Table"] copy] autorelease];
+ tableType = SPTableTypeTable;
}
- [targetArray addObject:item];
- }
-
- // If required write the UTF-8 Byte Order Mark
- if ([self sqlOutputIncludeUTF8BOM]) {
- [metaString setString:@"\xef\xbb\xbf"];
- [metaString appendString:@"# ************************************************************\n"];
- }
- else {
- [metaString setString:@"# ************************************************************\n"];
+ [tableDetails release];
}
+
+ if ([connection queryErrored]) {
+ [errors appendString:[NSString stringWithFormat:@"%@\n", [connection getLastErrorMessage]]];
- // If required set the file handle to compress it's output
- [[self exportOutputFileHandle] setShouldWriteWithGzipCompression:[self sqlOutputCompressFile]];
-
- // Add the dump header to the dump file
- [metaString appendString:@"# Sequel Pro SQL dump\n"];
- [metaString appendString:[NSString stringWithFormat:@"# Version %@\n#\n", [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]]];
- [metaString appendString:[NSString stringWithFormat:@"# %@\n# %@\n#\n", SPHomePageURL, SPDevURL]];
- [metaString appendString:[NSString stringWithFormat:@"# Host: %@ (MySQL %@)\n", [self sqlDatabaseHost], [self sqlDatabaseVersion]]];
- [metaString appendString:[NSString stringWithFormat:@"# Database: %@\n", [self sqlDatabaseName]]];
- [metaString appendString:[NSString stringWithFormat:@"# Generation Time: %@\n", [NSDate date]]];
- [metaString appendString:@"# ************************************************************\n\n\n"];
-
- // Add commands to store the client encodings used when importing and set to UTF8 to preserve data
- [metaString appendString:@"/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;\n"];
- [metaString appendString:@"/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;\n"];
- [metaString appendString:@"/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;\n"];
- [metaString appendString:@"/*!40101 SET NAMES utf8 */;\n"];
+ if ([self sqlOutputIncludeErrors]) {
+ [[self exportOutputFileHandle] writeData:[[NSString stringWithFormat:@"# Error: %@\n", [connection getLastErrorMessage]] dataUsingEncoding:NSUTF8StringEncoding]];
+ }
+ }
- // Add commands to store and disable unique checks, foreign key checks, mode and notes where supported.
- // Include trailing semicolons to ensure they're run individually. Use MySQL-version based comments.
- //if (sqlOutputIncludeDropSyntax) {
- //[metaString appendString:@"/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;\n"];
- //}
+ // Add a 'DROP TABLE' command if required
+ if (sqlOutputIncludeDropSyntax)
+ [[self exportOutputFileHandle] writeData:[[NSString stringWithFormat:@"DROP %@ IF EXISTS %@;\n\n", ((tableType == SPTableTypeTable) ? @"TABLE" : @"VIEW"), [tableName backtickQuotedString]]
+ dataUsingEncoding:[self exportOutputEncoding]]];
- [metaString appendString:@"/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\n"];
- [metaString appendString:@"/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\n"];
- [metaString appendString:@"/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n\n\n"];
- [[self exportOutputFileHandle] writeData:[metaString dataUsingEncoding:[self exportOutputEncoding]]];
-
- // Loop through the selected tables
- for (NSArray *table in [self sqlExportTables])
- {
- // Check for cancellation flag
- if ([self isCancelled]) {
- [pool release];
- return;
+ // Add the create syntax for the table if specified in the export dialog
+ if (sqlOutputIncludeStructure && createTableSyntax) {
+
+ if ([createTableSyntax isKindOfClass:[NSData class]]) {
+ createTableSyntax = [[[NSString alloc] initWithData:createTableSyntax encoding:[self exportOutputEncoding]] autorelease];
}
- tableName = NSArrayObjectAtIndex(table, 0);
-
- sqlOutputIncludeStructure = [NSArrayObjectAtIndex(table, 1) boolValue];
- sqlOutputIncludeContent = [NSArrayObjectAtIndex(table, 2) boolValue];
- sqlOutputIncludeDropSyntax = [NSArrayObjectAtIndex(table, 3) boolValue];
-
- // Set the current table
- [self setSqlExportCurrentTable:tableName];
-
- // Inform the delegate that we are about to start fetcihing data for the current table
- [delegate performSelectorOnMainThread:@selector(sqlExportProcessWillBeginFetchingData:) withObject:self waitUntilDone:NO];
-
- lastProgressValue = 0;
-
- // Add the name of table
- [[self exportOutputFileHandle] writeData:[[NSString stringWithFormat:@"# Dump of table %@\n# ------------------------------------------------------------\n\n", tableName] dataUsingEncoding:[self exportOutputEncoding]]];
-
- // Determine whether this table is a table or a view via the CREATE TABLE command, and keep the create table syntax
- queryResult = [connection queryString:[NSString stringWithFormat:@"SHOW CREATE TABLE %@", [tableName backtickQuotedString]]];
+ [[self exportOutputFileHandle] writeData:[createTableSyntax dataUsingEncoding:NSUTF8StringEncoding]];
+ [[self exportOutputFileHandle] writeData:[[NSString stringWithString:@";\n\n"] dataUsingEncoding:NSUTF8StringEncoding]];
+ }
+
+ // Add the table content if required
+ if (sqlOutputIncludeContent && (tableType == SPTableTypeTable)) {
- [queryResult setReturnDataAsStrings:YES];
+ // Retrieve the table details via the data class, and use it to build an array containing column numeric status
+ tableDetails = [NSDictionary dictionaryWithDictionary:[[self sqlTableInformation] objectForKey:tableName]];
+
+ NSUInteger colCount = [[tableDetails objectForKey:@"columns"] count];
- if ([queryResult numOfRows]) {
- tableDetails = [[NSDictionary alloc] initWithDictionary:[queryResult fetchRowAsDictionary]];
-
- if ([tableDetails objectForKey:@"Create View"]) {
- [viewSyntaxes setValue:[[[[tableDetails objectForKey:@"Create View"] copy] autorelease] createViewSyntaxPrettifier] forKey:tableName];
- createTableSyntax = [self _createViewPlaceholderSyntaxForView:tableName];
- tableType = SPTableTypeView;
- }
- else {
- createTableSyntax = [[[tableDetails objectForKey:@"Create Table"] copy] autorelease];
- tableType = SPTableTypeTable;
+ tableColumnNumericStatus = [NSMutableArray arrayWithCapacity:colCount];
+
+ for (j = 0; j < colCount; j++)
+ {
+ // Check for cancellation flag
+ if ([self isCancelled]) {
+ [pool release];
+ return;
}
- [tableDetails release];
- }
-
- if ([connection queryErrored]) {
- [errors appendString:[NSString stringWithFormat:@"%@\n", [connection getLastErrorMessage]]];
+ NSString *tableColumnTypeGrouping = [NSArrayObjectAtIndex([tableDetails objectForKey:@"columns"], j) objectForKey:@"typegrouping"];
- if ([self sqlOutputIncludeErrors]) {
- [[self exportOutputFileHandle] writeData:[[NSString stringWithFormat:@"# Error: %@\n", [connection getLastErrorMessage]] dataUsingEncoding:NSUTF8StringEncoding]];
- }
+ [tableColumnNumericStatus addObject:[NSNumber numberWithBool:([tableColumnTypeGrouping isEqualToString:@"bit"] || [tableColumnTypeGrouping isEqualToString:@"integer"] || [tableColumnTypeGrouping isEqualToString:@"float"])]];
}
+
+ // Retrieve the number of rows in the table for progress bar drawing
+ rowCount = [NSArrayObjectAtIndex([[connection queryString:[NSString stringWithFormat:@"SELECT COUNT(1) FROM %@", [tableName backtickQuotedString]]] fetchRowAsArray], 0) integerValue];
+
+ // Set up a result set in streaming mode
+ streamingResult = [[connection streamingQueryString:[NSString stringWithFormat:@"SELECT * FROM %@", [tableName backtickQuotedString]] useLowMemoryBlockingStreaming:([self exportUsingLowMemoryBlockingStreaming])] retain];
- // Add a 'DROP TABLE' command if required
- if (sqlOutputIncludeDropSyntax)
- [[self exportOutputFileHandle] writeData:[[NSString stringWithFormat:@"DROP %@ IF EXISTS %@;\n\n", ((tableType == SPTableTypeTable) ? @"TABLE" : @"VIEW"), [tableName backtickQuotedString]]
- dataUsingEncoding:[self exportOutputEncoding]]];
-
+ NSArray *fieldNames = [streamingResult fetchFieldNames];
- // Add the create syntax for the table if specified in the export dialog
- if (sqlOutputIncludeStructure && createTableSyntax) {
-
- if ([createTableSyntax isKindOfClass:[NSData class]]) {
- createTableSyntax = [[[NSString alloc] initWithData:createTableSyntax encoding:[self exportOutputEncoding]] autorelease];
- }
+ // Inform the delegate that we are about to start writing data for the current table
+ [delegate performSelectorOnMainThread:@selector(sqlExportProcessWillBeginWritingData:) withObject:self waitUntilDone:NO];
+
+ if (rowCount) {
+ queryLength = 0;
- [[self exportOutputFileHandle] writeData:[createTableSyntax dataUsingEncoding:NSUTF8StringEncoding]];
- [[self exportOutputFileHandle] writeData:[[NSString stringWithString:@";\n\n"] dataUsingEncoding:NSUTF8StringEncoding]];
- }
-
- // Add the table content if required
- if (sqlOutputIncludeContent && (tableType == SPTableTypeTable)) {
+ // Lock the table for writing and disable keys if supported
+ [metaString setString:@""];
+ [metaString appendString:[NSString stringWithFormat:@"LOCK TABLES %@ WRITE;\n", [tableName backtickQuotedString]]];
+ [metaString appendString:[NSString stringWithFormat:@"/*!40000 ALTER TABLE %@ DISABLE KEYS */;\n\n", [tableName backtickQuotedString]]];
- // Retrieve the table details via the data class, and use it to build an array containing column numeric status
- tableDetails = [NSDictionary dictionaryWithDictionary:[[self sqlTableInformation] objectForKey:tableName]];
-
- NSUInteger colCount = [[tableDetails objectForKey:@"columns"] count];
+ [[self exportOutputFileHandle] writeData:[metaString dataUsingEncoding:[self exportOutputEncoding]]];
- tableColumnNumericStatus = [NSMutableArray arrayWithCapacity:colCount];
-
- for (j = 0; j < colCount; j++)
+ // Construct the start of the insertion command
+ [[self exportOutputFileHandle] writeData:[[NSString stringWithFormat:@"INSERT INTO %@ (%@)\nVALUES\n\t(",
+ [tableName backtickQuotedString], [fieldNames componentsJoinedAndBacktickQuoted]] dataUsingEncoding:NSUTF8StringEncoding]];
+
+ // Iterate through the rows to construct a VALUES group for each
+ j = 0;
+
+ sqlExportPool = [[NSAutoreleasePool alloc] init];
+
+ // Inform the delegate that we are about to start writing the data to disk
+ [delegate performSelectorOnMainThread:@selector(sqlExportProcessWillBeginWritingData:) withObject:self waitUntilDone:NO];
+
+ while (row = [streamingResult fetchNextRowAsArray])
{
// Check for cancellation flag
if ([self isCancelled]) {
+ [connection cancelCurrentQuery];
+ [streamingResult cancelResultLoad];
+ [sqlExportPool release];
[pool release];
+
return;
}
- NSString *tableColumnTypeGrouping = [NSArrayObjectAtIndex([tableDetails objectForKey:@"columns"], j) objectForKey:@"typegrouping"];
-
- [tableColumnNumericStatus addObject:[NSNumber numberWithBool:([tableColumnTypeGrouping isEqualToString:@"bit"] || [tableColumnTypeGrouping isEqualToString:@"integer"] || [tableColumnTypeGrouping isEqualToString:@"float"])]];
- }
-
- // Retrieve the number of rows in the table for progress bar drawing
- rowCount = [NSArrayObjectAtIndex([[connection queryString:[NSString stringWithFormat:@"SELECT COUNT(1) FROM %@", [tableName backtickQuotedString]]] fetchRowAsArray], 0) integerValue];
-
- // Set up a result set in streaming mode
- streamingResult = [[connection streamingQueryString:[NSString stringWithFormat:@"SELECT * FROM %@", [tableName backtickQuotedString]] useLowMemoryBlockingStreaming:([self exportUsingLowMemoryBlockingStreaming])] retain];
-
- NSArray *fieldNames = [streamingResult fetchFieldNames];
-
- // Inform the delegate that we are about to start writing data for the current table
- [delegate performSelectorOnMainThread:@selector(sqlExportProcessWillBeginWritingData:) withObject:self waitUntilDone:NO];
-
- if (rowCount) {
- queryLength = 0;
-
- // Lock the table for writing and disable keys if supported
- [metaString setString:@""];
- [metaString appendString:[NSString stringWithFormat:@"LOCK TABLES %@ WRITE;\n", [tableName backtickQuotedString]]];
- [metaString appendString:[NSString stringWithFormat:@"/*!40000 ALTER TABLE %@ DISABLE KEYS */;\n\n", [tableName backtickQuotedString]]];
-
- [[self exportOutputFileHandle] writeData:[metaString dataUsingEncoding:[self exportOutputEncoding]]];
-
- // Construct the start of the insertion command
- [[self exportOutputFileHandle] writeData:[[NSString stringWithFormat:@"INSERT INTO %@ (%@)\nVALUES\n\t(",
- [tableName backtickQuotedString], [fieldNames componentsJoinedAndBacktickQuoted]] dataUsingEncoding:NSUTF8StringEncoding]];
-
- // Iterate through the rows to construct a VALUES group for each
- j = 0;
-
- sqlExportPool = [[NSAutoreleasePool alloc] init];
-
- // Inform the delegate that we are about to start writing the data to disk
- [delegate performSelectorOnMainThread:@selector(sqlExportProcessWillBeginWritingData:) withObject:self waitUntilDone:NO];
+ j++;
+ [sqlString setString:@""];
+
+ // Update the progress
+ NSUInteger progress = (j * ([self exportMaxProgress] / rowCount));
+ if (progress > lastProgressValue) {
+ [self setExportProgressValue:progress];
+ lastProgressValue = progress;
+
+ // Inform the delegate that the export's progress has been updated
+ [delegate performSelectorOnMainThread:@selector(sqlExportProcessProgressUpdated:) withObject:self waitUntilDone:NO];
+ }
- while (row = [streamingResult fetchNextRowAsArray])
+ for (t = 0; t < colCount; t++)
{
// Check for cancellation flag
if ([self isCancelled]) {
- [connection cancelCurrentQuery];
- [streamingResult cancelResultLoad];
[sqlExportPool release];
[pool release];
return;
}
- j++;
- [sqlString setString:@""];
-
- // Update the progress
- if ((j * ([self exportMaxProgress] / rowCount)) > lastProgressValue) {
-
- NSInteger progress = (j * ([self exportMaxProgress] / rowCount));
-
- [self setExportProgressValue:progress];
-
- lastProgressValue = progress;
+ // Add NULL values directly to the output row
+ if ([NSArrayObjectAtIndex(row, t) isMemberOfClass:[NSNull class]]) {
+ [sqlString appendString:@"NULL"];
+ }
+ // Add data types directly as hex data
+ else if ([NSArrayObjectAtIndex(row, t) isKindOfClass:[NSData class]]) {
- // Inform the delegate that the export's progress has been updated
- [delegate performSelectorOnMainThread:@selector(sqlExportProcessProgressUpdated:) withObject:self waitUntilDone:NO];
- }
-
- for (t = 0; t < colCount; t++)
- {
- // Check for cancellation flag
- if ([self isCancelled]) {
- [sqlExportPool release];
- [pool release];
-
- return;
+ if ([self sqlOutputEncodeBLOBasHex]) {
+ [sqlString appendString:@"X'"];
+ [sqlString appendString:[connection prepareBinaryData:NSArrayObjectAtIndex(row, t)]];
}
-
- // Add NULL values directly to the output row
- if ([NSArrayObjectAtIndex(row, t) isMemberOfClass:[NSNull class]]) {
- [sqlString appendString:@"NULL"];
- }
- // Add data types directly as hex data
- else if ([NSArrayObjectAtIndex(row, t) isKindOfClass:[NSData class]]) {
+ else {
+ [sqlString appendString:@"'"];
- if ([self sqlOutputEncodeBLOBasHex]) {
- [sqlString appendString:@"X'"];
- [sqlString appendString:[connection prepareBinaryData:NSArrayObjectAtIndex(row, t)]];
- }
- else {
- [sqlString appendString:@"'"];
-
- NSString *data = [[NSString alloc] initWithData:NSArrayObjectAtIndex(row, t) encoding:[self exportOutputEncoding]];
-
- if (data == nil) {
- data = [[NSString alloc] initWithData:NSArrayObjectAtIndex(row, t) encoding:NSASCIIStringEncoding];
- }
-
- [sqlString appendString:data];
-
- [data release];
+ NSString *data = [[NSString alloc] initWithData:NSArrayObjectAtIndex(row, t) encoding:[self exportOutputEncoding]];
+
+ if (data == nil) {
+ data = [[NSString alloc] initWithData:NSArrayObjectAtIndex(row, t) encoding:NSASCIIStringEncoding];
}
- [sqlString appendString:@"'"];
+ [sqlString appendString:data];
+
+ [data release];
+ }
+
+ [sqlString appendString:@"'"];
+ }
+ else {
+ [cellValue setString:[NSArrayObjectAtIndex(row, t) description]];
+
+ // Add empty strings as a pair of quotes
+ if ([cellValue length] == 0) {
+ [sqlString appendString:@"''"];
}
else {
- [cellValue setString:[NSArrayObjectAtIndex(row, t) description]];
-
- // Add empty strings as a pair of quotes
- if ([cellValue length] == 0) {
- [sqlString appendString:@"''"];
+ // If this is a numeric column type, add the number directly.
+ if ([NSArrayObjectAtIndex(tableColumnNumericStatus, t) boolValue]) {
+ [sqlString appendString:cellValue];
}
+ // Otherwise add a quoted string with special characters escaped
else {
- // If this is a numeric column type, add the number directly.
- if ([NSArrayObjectAtIndex(tableColumnNumericStatus, t) boolValue]) {
- [sqlString appendString:cellValue];
- }
- // Otherwise add a quoted string with special characters escaped
- else {
- [sqlString appendString:@"'"];
- [sqlString appendString:[connection prepareString:cellValue]];
- [sqlString appendString:@"'"];
- }
+ [sqlString appendString:@"'"];
+ [sqlString appendString:[connection prepareString:cellValue]];
+ [sqlString appendString:@"'"];
}
}
-
- // Add the field separator if this isn't the last cell in the row
- if (t != ([row count] - 1)) [sqlString appendString:@","];
}
- queryLength += [sqlString length];
+ // Add the field separator if this isn't the last cell in the row
+ if (t != ([row count] - 1)) [sqlString appendString:@","];
+ }
+
+ queryLength += [sqlString length];
+
+ // Close this VALUES group and set up the next one if appropriate
+ if (j != rowCount) {
- // Close this VALUES group and set up the next one if appropriate
- if (j != rowCount) {
+ // Add a new INSERT starter command every ~250k of data
+ if (queryLength > 250000) {
+ [sqlString appendString:[NSString stringWithFormat:@");\n\nINSERT INTO %@ (%@)\nVALUES\n\t(",
+ [tableName backtickQuotedString], [fieldNames componentsJoinedAndBacktickQuoted]]];
+ queryLength = 0;
- // Add a new INSERT starter command every ~250k of data
- if (queryLength > 250000) {
- [sqlString appendString:[NSString stringWithFormat:@");\n\nINSERT INTO %@ (%@)\nVALUES\n\t(",
- [tableName backtickQuotedString], [fieldNames componentsJoinedAndBacktickQuoted]]];
- queryLength = 0;
-
- // Use the opportunity to drain and reset the autorelease pool
- [sqlExportPool release];
- sqlExportPool = [[NSAutoreleasePool alloc] init];
- }
- else {
- [sqlString appendString:@"),\n\t("];
- }
+ // Use the opportunity to drain and reset the autorelease pool
+ [sqlExportPool release];
+ sqlExportPool = [[NSAutoreleasePool alloc] init];
}
else {
- [sqlString appendString:@")"];
+ [sqlString appendString:@"),\n\t("];
}
-
- // Write this row to the file
- [[self exportOutputFileHandle] writeData:[sqlString dataUsingEncoding:NSUTF8StringEncoding]];
+ }
+ else {
+ [sqlString appendString:@")"];
}
- // Complete the command
- [[self exportOutputFileHandle] writeData:[[NSString stringWithString:@";\n\n"] dataUsingEncoding:NSUTF8StringEncoding]];
-
- // Unlock the table and re-enable keys if supported
- [metaString setString:@""];
- [metaString appendString:[NSString stringWithFormat:@"/*!40000 ALTER TABLE %@ ENABLE KEYS */;\n", [tableName backtickQuotedString]]];
- [metaString appendString:@"UNLOCK TABLES;\n"];
-
- [[self exportOutputFileHandle] writeData:[metaString dataUsingEncoding:NSUTF8StringEncoding]];
-
- // Drain the autorelease pool
- [sqlExportPool release];
+ // Write this row to the file
+ [[self exportOutputFileHandle] writeData:[sqlString dataUsingEncoding:NSUTF8StringEncoding]];
}
- if ([connection queryErrored]) {
- [errors appendString:[NSString stringWithFormat:@"%@\n", [connection getLastErrorMessage]]];
-
- if ([self sqlOutputIncludeErrors]) {
- [[self exportOutputFileHandle] writeData:[[NSString stringWithFormat:@"# Error: %@\n", [connection getLastErrorMessage]]
- dataUsingEncoding:NSUTF8StringEncoding]];
- }
- }
-
- // Release the result set
- [streamingResult release];
-
- queryResult = [connection queryString:[NSString stringWithFormat:@"/*!50003 SHOW TRIGGERS WHERE `Table` = %@ */;", [tableName tickQuotedString]]];
-
- [queryResult setReturnDataAsStrings:YES];
+ // Complete the command
+ [[self exportOutputFileHandle] writeData:[[NSString stringWithString:@";\n\n"] dataUsingEncoding:NSUTF8StringEncoding]];
- if ([queryResult numOfRows]) {
-
- [metaString setString:@"\n"];
- [metaString appendString:@"DELIMITER ;;\n"];
-
- for (s = 0; s < [queryResult numOfRows]; s++)
- {
- // Check for cancellation flag
- if ([self isCancelled]) {
- [pool release];
- return;
- }
-
- 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:@"%@@%@",
- [NSArrayObjectAtIndex(triggersDefiner, 0) backtickQuotedString],
- [NSArrayObjectAtIndex(triggersDefiner, 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];
- }
-
- [metaString appendString:@"DELIMITER ;\n"];
- [metaString appendString:@"/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE */;\n"];
-
- [[self exportOutputFileHandle] writeData:[metaString dataUsingEncoding:NSUTF8StringEncoding]];
- }
+ // Unlock the table and re-enable keys if supported
+ [metaString setString:@""];
+ [metaString appendString:[NSString stringWithFormat:@"/*!40000 ALTER TABLE %@ ENABLE KEYS */;\n", [tableName backtickQuotedString]]];
+ [metaString appendString:@"UNLOCK TABLES;\n"];
- if ([connection queryErrored]) {
- [errors appendString:[NSString stringWithFormat:@"%@\n", [connection getLastErrorMessage]]];
-
- if ([self sqlOutputIncludeErrors]) {
- [[self exportOutputFileHandle] writeData:[[NSString stringWithFormat:@"# Error: %@\n", [connection getLastErrorMessage]]
- dataUsingEncoding:NSUTF8StringEncoding]];
- }
- }
+ [[self exportOutputFileHandle] writeData:[metaString dataUsingEncoding:NSUTF8StringEncoding]];
+ // Drain the autorelease pool
+ [sqlExportPool release];
}
- // Add an additional separator between tables
- [[self exportOutputFileHandle] writeData:[[NSString stringWithString:@"\n\n"] dataUsingEncoding:NSUTF8StringEncoding]];
- }
-
- // Process any deferred views, adding commands to delete the placeholder tables and add the actual views
- for (tableName in viewSyntaxes)
- {
- // Check for cancellation flag
- if ([self isCancelled]) {
- [pool release];
- return;
- }
-
- [metaString setString:@"\n\n"];
- [metaString appendFormat:@"DROP TABLE %@;\n", [tableName backtickQuotedString]];
- [metaString appendFormat:@"%@;\n", [viewSyntaxes objectForKey:tableName]];
-
- [[self exportOutputFileHandle] writeData:[metaString dataUsingEncoding:NSUTF8StringEncoding]];
- }
-
- // Export procedures and functions
- for (NSString *procedureType in [NSArray arrayWithObjects:@"PROCEDURE", @"FUNCTION", nil])
- {
- // Check for cancellation flag
- if ([self isCancelled]) {
- [pool release];
- return;
+ if ([connection queryErrored]) {
+ [errors appendString:[NSString stringWithFormat:@"%@\n", [connection getLastErrorMessage]]];
+
+ if ([self sqlOutputIncludeErrors]) {
+ [[self exportOutputFileHandle] writeData:[[NSString stringWithFormat:@"# Error: %@\n", [connection getLastErrorMessage]]
+ dataUsingEncoding:NSUTF8StringEncoding]];
+ }
}
- // Retrieve the array of selected procedures or functions, and skip export if not selected
- NSMutableArray *items;
-
- if ([procedureType isEqualToString:@"PROCEDURE"]) items = procs;
- else items = funcs;
-
- if ([items count] == 0) continue;
+ // Release the result set
+ [streamingResult release];
- // Retrieve the definitions
- queryResult = [connection queryString:[NSString stringWithFormat:@"/*!50003 SHOW %@ STATUS WHERE `Db` = %@ */;", procedureType,
- [[self sqlDatabaseName] tickQuotedString]]];
+ queryResult = [connection queryString:[NSString stringWithFormat:@"/*!50003 SHOW TRIGGERS WHERE `Table` = %@ */;", [tableName tickQuotedString]]];
[queryResult setReturnDataAsStrings:YES];
if ([queryResult numOfRows]) {
[metaString setString:@"\n"];
- [metaString appendString:@"--\n"];
- [metaString appendString:[NSString stringWithFormat:@"-- Dumping routines (%@) for database %@\n", procedureType,
- [[self sqlDatabaseName] tickQuotedString]]];
-
- [metaString appendString:@"--\n"];
[metaString appendString:@"DELIMITER ;;\n"];
- // Loop through the definitions, exporting if enabled
for (s = 0; s < [queryResult numOfRows]; s++)
{
// Check for cancellation flag
@@ -582,79 +477,32 @@
return;
}
- NSDictionary *proceduresList = [[NSDictionary alloc] initWithDictionary:[queryResult fetchRowAsDictionary]];
- NSString *procedureName = [NSString stringWithFormat:@"%@", [proceduresList objectForKey:@"Name"]];
-
- // Only proceed if the item was selected for export
- if (![items containsObject:procedureName]) {
- [proceduresList release];
- continue;
- }
-
- // Only proceed if the item is in the list of items
- for (NSArray *item in items)
- {
- // Check for cancellation flag
- if ([self isCancelled]) {
- [pool release];
- return;
- }
-
- if ([NSArrayObjectAtIndex(item, 0) isEqualToString:procedureName]) {
- sqlOutputIncludeStructure = [NSArrayObjectAtIndex(item, 1) boolValue];
- sqlOutputIncludeContent = [NSArrayObjectAtIndex(item, 2) boolValue];
- sqlOutputIncludeDropSyntax = [NSArrayObjectAtIndex(item, 3) boolValue];
- }
- }
-
- // Add the 'DROP' command if required
- if (sqlOutputIncludeDropSyntax) {
- [metaString appendString:[NSString stringWithFormat:@"/*!50003 DROP %@ IF EXISTS %@ */;;\n", procedureType,
- [procedureName backtickQuotedString]]];
- }
-
- // Only continue if the 'CREATE SYNTAX' is required
- if (sqlOutputIncludeStructure) {
- [proceduresList release];
- continue;
- }
+ NSDictionary *triggers = [[NSDictionary alloc] initWithDictionary:[queryResult fetchRowAsDictionary]];
// Definer is user@host but we need to escape it to `user`@`host`
- NSArray *procedureDefiner = [[proceduresList objectForKey:@"Definer"] componentsSeparatedByString:@"@"];
+ NSArray *triggersDefiner = [[triggers objectForKey:@"Definer"] componentsSeparatedByString:@"@"];
NSString *escapedDefiner = [NSString stringWithFormat:@"%@@%@",
- [NSArrayObjectAtIndex(procedureDefiner, 0) backtickQuotedString],
- [NSArrayObjectAtIndex(procedureDefiner, 1) backtickQuotedString]
+ [NSArrayObjectAtIndex(triggersDefiner, 0) backtickQuotedString],
+ [NSArrayObjectAtIndex(triggersDefiner, 1) backtickQuotedString]
];
- MCPResult *createProcedureResult = [connection queryString:[NSString stringWithFormat:@"/*!50003 SHOW CREATE %@ %@ */;;", procedureType,
- [procedureName backtickQuotedString]]];
-
- [createProcedureResult setReturnDataAsStrings:YES];
-
- NSDictionary *procedureInfo = [[NSDictionary alloc] initWithDictionary:[createProcedureResult fetchRowAsDictionary]];
-
- [metaString appendString:[NSString stringWithFormat:@"/*!50003 SET SESSION SQL_MODE=\"%@\"*/;;\n", [procedureInfo objectForKey:@"sql_mode"]]];
-
- NSString *createProcedure = [procedureInfo objectForKey:[NSString stringWithFormat:@"Create %@", [procedureType capitalizedString]]];
- NSRange procedureRange = [createProcedure rangeOfString:procedureType options:NSCaseInsensitiveSearch];
- NSString *procedureBody = [createProcedure substringFromIndex:procedureRange.location];
-
- // /*!50003 CREATE*/ /*!50020 DEFINER=`sequelpro`@`%`*/ /*!50003 PROCEDURE `p`()
- // BEGIN
- // /* This procedure does nothing */
- // END */;;
- //
- // Build the CREATE PROCEDURE string to include MySQL Version limiters
- [metaString appendString:[NSString stringWithFormat:@"/*!50003 CREATE*/ /*!50020 DEFINER=%@*/ /*!50003 %@ */;;\n", escapedDefiner, procedureBody]];
-
- [procedureInfo release];
- [proceduresList release];
-
- [metaString appendString:@"/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE */;;\n"];
+ [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];
}
[metaString appendString:@"DELIMITER ;\n"];
+ [metaString appendString:@"/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE */;\n"];
[[self exportOutputFileHandle] writeData:[metaString dataUsingEncoding:NSUTF8StringEncoding]];
}
@@ -663,48 +511,196 @@
[errors appendString:[NSString stringWithFormat:@"%@\n", [connection getLastErrorMessage]]];
if ([self sqlOutputIncludeErrors]) {
- [[self exportOutputFileHandle] writeData:[[NSString stringWithFormat:@"# Error: %@\n", [connection getLastErrorMessage]] dataUsingEncoding:NSUTF8StringEncoding]];
+ [[self exportOutputFileHandle] writeData:[[NSString stringWithFormat:@"# Error: %@\n", [connection getLastErrorMessage]]
+ dataUsingEncoding:NSUTF8StringEncoding]];
}
}
}
- // Restore unique checks, foreign key checks, and other settings saved at the start
- [metaString setString:@"\n"];
- [metaString appendString:@"/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n"];
- [metaString appendString:@"/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\n"];
- [metaString appendString:@"/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\n"];
-
- //if (sqlOutputIncludeDropSyntax) {
- //[metaString appendString:@"/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;\n"];
- //}
+ // Add an additional separator between tables
+ [[self exportOutputFileHandle] writeData:[[NSString stringWithString:@"\n\n"] dataUsingEncoding:NSUTF8StringEncoding]];
+ }
+
+ // Process any deferred views, adding commands to delete the placeholder tables and add the actual views
+ for (tableName in viewSyntaxes)
+ {
+ // Check for cancellation flag
+ if ([self isCancelled]) {
+ [pool release];
+ return;
+ }
- // Restore the client encoding to the original encoding before import
- [metaString appendString:@"/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n"];
- [metaString appendString:@"/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n"];
- [metaString appendString:@"/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n"];
+ [metaString setString:@"\n\n"];
+ [metaString appendFormat:@"DROP TABLE %@;\n", [tableName backtickQuotedString]];
+ [metaString appendFormat:@"%@;\n", [viewSyntaxes objectForKey:tableName]];
- // Write footer-type information to the file
[[self exportOutputFileHandle] writeData:[metaString dataUsingEncoding:NSUTF8StringEncoding]];
-
- // Set export errors
- [self setSqlExportErrors:errors];
-
- [errors release];
- [sqlString release];
+ }
+
+ // Export procedures and functions
+ for (NSString *procedureType in [NSArray arrayWithObjects:@"PROCEDURE", @"FUNCTION", nil])
+ {
+ // Check for cancellation flag
+ if ([self isCancelled]) {
+ [pool release];
+ return;
+ }
- // Close the file
- [[self exportOutputFileHandle] closeFile];
+ // Retrieve the array of selected procedures or functions, and skip export if not selected
+ NSMutableArray *items;
- // Mark the process as not running
- [self setExportProcessIsRunning:NO];
+ if ([procedureType isEqualToString:@"PROCEDURE"]) items = procs;
+ else items = funcs;
- // Inform the delegate that the export process is complete
- [delegate performSelectorOnMainThread:@selector(sqlExportProcessComplete:) withObject:self waitUntilDone:NO];
+ if ([items count] == 0) continue;
+
+ // Retrieve the definitions
+ queryResult = [connection queryString:[NSString stringWithFormat:@"/*!50003 SHOW %@ STATUS WHERE `Db` = %@ */;", procedureType,
+ [[self sqlDatabaseName] tickQuotedString]]];
+
+ [queryResult setReturnDataAsStrings:YES];
+
+ if ([queryResult numOfRows]) {
+
+ [metaString setString:@"\n"];
+ [metaString appendString:@"--\n"];
+ [metaString appendString:[NSString stringWithFormat:@"-- Dumping routines (%@) for database %@\n", procedureType,
+ [[self sqlDatabaseName] tickQuotedString]]];
+
+ [metaString appendString:@"--\n"];
+ [metaString appendString:@"DELIMITER ;;\n"];
+
+ // Loop through the definitions, exporting if enabled
+ for (s = 0; s < [queryResult numOfRows]; s++)
+ {
+ // Check for cancellation flag
+ if ([self isCancelled]) {
+ [pool release];
+ return;
+ }
+
+ NSDictionary *proceduresList = [[NSDictionary alloc] initWithDictionary:[queryResult fetchRowAsDictionary]];
+ NSString *procedureName = [NSString stringWithFormat:@"%@", [proceduresList objectForKey:@"Name"]];
+
+ // Only proceed if the item was selected for export
+ if (![items containsObject:procedureName]) {
+ [proceduresList release];
+ continue;
+ }
+
+ // Only proceed if the item is in the list of items
+ for (NSArray *item in items)
+ {
+ // Check for cancellation flag
+ if ([self isCancelled]) {
+ [pool release];
+ return;
+ }
+
+ if ([NSArrayObjectAtIndex(item, 0) isEqualToString:procedureName]) {
+ sqlOutputIncludeStructure = [NSArrayObjectAtIndex(item, 1) boolValue];
+ sqlOutputIncludeContent = [NSArrayObjectAtIndex(item, 2) boolValue];
+ sqlOutputIncludeDropSyntax = [NSArrayObjectAtIndex(item, 3) boolValue];
+ }
+ }
+
+ // Add the 'DROP' command if required
+ if (sqlOutputIncludeDropSyntax) {
+ [metaString appendString:[NSString stringWithFormat:@"/*!50003 DROP %@ IF EXISTS %@ */;;\n", procedureType,
+ [procedureName backtickQuotedString]]];
+ }
+
+ // Only continue if the 'CREATE SYNTAX' is required
+ if (sqlOutputIncludeStructure) {
+ [proceduresList release];
+ continue;
+ }
+
+ // Definer is user@host but we need to escape it to `user`@`host`
+ NSArray *procedureDefiner = [[proceduresList objectForKey:@"Definer"] componentsSeparatedByString:@"@"];
+
+ NSString *escapedDefiner = [NSString stringWithFormat:@"%@@%@",
+ [NSArrayObjectAtIndex(procedureDefiner, 0) backtickQuotedString],
+ [NSArrayObjectAtIndex(procedureDefiner, 1) backtickQuotedString]
+ ];
+
+ MCPResult *createProcedureResult = [connection queryString:[NSString stringWithFormat:@"/*!50003 SHOW CREATE %@ %@ */;;", procedureType,
+ [procedureName backtickQuotedString]]];
+
+ [createProcedureResult setReturnDataAsStrings:YES];
+
+ NSDictionary *procedureInfo = [[NSDictionary alloc] initWithDictionary:[createProcedureResult fetchRowAsDictionary]];
+
+ [metaString appendString:[NSString stringWithFormat:@"/*!50003 SET SESSION SQL_MODE=\"%@\"*/;;\n", [procedureInfo objectForKey:@"sql_mode"]]];
+
+ NSString *createProcedure = [procedureInfo objectForKey:[NSString stringWithFormat:@"Create %@", [procedureType capitalizedString]]];
+ NSRange procedureRange = [createProcedure rangeOfString:procedureType options:NSCaseInsensitiveSearch];
+ NSString *procedureBody = [createProcedure substringFromIndex:procedureRange.location];
+
+ // /*!50003 CREATE*/ /*!50020 DEFINER=`sequelpro`@`%`*/ /*!50003 PROCEDURE `p`()
+ // BEGIN
+ // /* This procedure does nothing */
+ // END */;;
+ //
+ // Build the CREATE PROCEDURE string to include MySQL Version limiters
+ [metaString appendString:[NSString stringWithFormat:@"/*!50003 CREATE*/ /*!50020 DEFINER=%@*/ /*!50003 %@ */;;\n", escapedDefiner, procedureBody]];
+
+ [procedureInfo release];
+ [proceduresList release];
+
+ [metaString appendString:@"/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE */;;\n"];
+ }
+
+ [metaString appendString:@"DELIMITER ;\n"];
+
+ [[self exportOutputFileHandle] writeData:[metaString dataUsingEncoding:NSUTF8StringEncoding]];
+ }
+
+ if ([connection queryErrored]) {
+ [errors appendString:[NSString stringWithFormat:@"%@\n", [connection getLastErrorMessage]]];
+
+ if ([self sqlOutputIncludeErrors]) {
+ [[self exportOutputFileHandle] writeData:[[NSString stringWithFormat:@"# Error: %@\n", [connection getLastErrorMessage]] dataUsingEncoding:NSUTF8StringEncoding]];
+ }
+ }
- [pool release];
}
- @catch (NSException *e) {}
+
+ // Restore unique checks, foreign key checks, and other settings saved at the start
+ [metaString setString:@"\n"];
+ [metaString appendString:@"/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n"];
+ [metaString appendString:@"/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\n"];
+ [metaString appendString:@"/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\n"];
+
+ //if (sqlOutputIncludeDropSyntax) {
+ //[metaString appendString:@"/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;\n"];
+ //}
+
+ // Restore the client encoding to the original encoding before import
+ [metaString appendString:@"/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n"];
+ [metaString appendString:@"/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n"];
+ [metaString appendString:@"/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n"];
+
+ // Write footer-type information to the file
+ [[self exportOutputFileHandle] writeData:[metaString dataUsingEncoding:NSUTF8StringEncoding]];
+
+ // Set export errors
+ [self setSqlExportErrors:errors];
+
+ [errors release];
+ [sqlString release];
+
+ // Close the file
+ [[self exportOutputFileHandle] closeFile];
+
+ // Mark the process as not running
+ [self setExportProcessIsRunning:NO];
+
+ // Inform the delegate that the export process is complete
+ [delegate performSelectorOnMainThread:@selector(sqlExportProcessComplete:) withObject:self waitUntilDone:NO];
+
+ [pool release];
}
/**
diff --git a/Source/SPSQLExporterDelegate.m b/Source/SPSQLExporterDelegate.m
index b9afe724..8be899f6 100644
--- a/Source/SPSQLExporterDelegate.m
+++ b/Source/SPSQLExporterDelegate.m
@@ -47,6 +47,7 @@
*/
- (void)sqlExportProcessComplete:(SPSQLExporter *)exporter
{
+ [exportProgressIndicator stopAnimation:self];
[NSApp endSheet:exportProgressWindow returnCode:0];
[exportProgressWindow orderOut:self];
@@ -69,8 +70,10 @@
*/
- (void)sqlExportProcessProgressUpdated:(SPSQLExporter *)exporter
{
- //NSLog(@"updating: %f", [exporter exportProgressValue]);
-
+ if ([exportProgressIndicator doubleValue] == 0) {
+ [exportProgressIndicator stopAnimation:self];
+ [exportProgressIndicator setIndeterminate:NO];
+ }
[exportProgressIndicator setDoubleValue:[exporter exportProgressValue]];
}
@@ -79,17 +82,12 @@
*/
- (void)sqlExportProcessWillBeginFetchingData:(SPSQLExporter *)exporter
{
- // Update the current table export index
- currentTableExportIndex = (exportTableCount - [exporters count]);
+ [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %lu of %lu (%@): Fetching data...", @"export label showing that the app is fetching data for a specific table"), [exporter sqlCurrentTableExportIndex], exportTableCount, [exporter sqlExportCurrentTable]]];
- [[exportProgressText onMainThread] setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %lu of %lu (%@): Fetching data...", @"export label showing that the app is fetching data for a specific table"), currentTableExportIndex, exportTableCount, [exporter sqlExportCurrentTable]]];
-
- [[exportProgressText onMainThread] displayIfNeeded];
-
- [[exportProgressIndicator onMainThread] stopAnimation:self];
- [[exportProgressIndicator onMainThread] setUsesThreadedAnimation:NO];
- [[exportProgressIndicator onMainThread] setIndeterminate:NO];
- [[exportProgressIndicator onMainThread] setDoubleValue:0];
+ [exportProgressIndicator startAnimation:self];
+ [exportProgressIndicator setUsesThreadedAnimation:YES];
+ [exportProgressIndicator setIndeterminate:YES];
+ [exportProgressIndicator setDoubleValue:0];
}
/**
@@ -97,9 +95,7 @@
*/
- (void)sqlExportProcessWillBeginWritingData:(SPSQLExporter *)exporter
{
- [[exportProgressText onMainThread] setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %lu of %lu (%@): Writing data...", @"export label showing app if writing data for a specific table"), currentTableExportIndex, exportTableCount, [exporter sqlExportCurrentTable]]];
-
- [[exportProgressText onMainThread] displayIfNeeded];
+ [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %lu of %lu (%@): Writing data...", @"export label showing app if writing data for a specific table"), [exporter sqlCurrentTableExportIndex], exportTableCount, [exporter sqlExportCurrentTable]]];
}
@end