diff options
author | avenjamin <avenjamin@gmail.com> | 2008-12-08 02:41:58 +0000 |
---|---|---|
committer | avenjamin <avenjamin@gmail.com> | 2008-12-08 02:41:58 +0000 |
commit | d7892ee21760a09fcedaa46e8a2f544146bd9a29 (patch) | |
tree | 12003978e9c27573ce09f4cc224047d6af38fd81 | |
parent | 20a22bbffa77ab514210d9defa01afd7bb0bba3a (diff) | |
download | sequelpro-d7892ee21760a09fcedaa46e8a2f544146bd9a29.tar.gz sequelpro-d7892ee21760a09fcedaa46e8a2f544146bd9a29.tar.bz2 sequelpro-d7892ee21760a09fcedaa46e8a2f544146bd9a29.zip |
Remove checking for empty string or NULL when importing a CSV file.
-rw-r--r-- | TableDump.m | 502 |
1 files changed, 247 insertions, 255 deletions
diff --git a/TableDump.m b/TableDump.m index de7b30db..3d9b6857 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 @@ -403,7 +403,7 @@ //import dump file NSArray *queries; int i; - + //open progress sheet [NSApp beginSheet:singleProgressSheet modalForWindow:tableWindow @@ -417,7 +417,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 +452,9 @@ [errorsSheet orderOut:nil]; } - //////////////// - // IMPORT CSV // - //////////////// + //////////////// + // IMPORT CSV // + //////////////// } else if ( [fileType isEqualToString:@"CSV"] ) { //import csv file @@ -522,7 +522,7 @@ [buttonCell addItemsWithTitles:[importArray objectAtIndex:currentRow]]; [[fieldMappingTableView tableColumnWithIdentifier:@"value"] setDataCell:buttonCell]; - + // show fieldMapping sheet [NSApp beginSheet:fieldMappingSheet modalForWindow:tableWindow @@ -574,7 +574,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 +637,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 +656,7 @@ } else { value = 0; } - + [fieldMappingArray addObject:[NSNumber numberWithInt:value]]; } @@ -722,23 +722,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 +747,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 +755,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 +784,7 @@ } } } - + // Add the table content if required if ( [addTableContentSwitch state] == NSOnState ) { queryResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SELECT * FROM `%@`", tableName]]; @@ -799,56 +799,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 +860,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 +881,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 +922,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 +935,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 +967,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 +986,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 +998,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 +1018,16 @@ } 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 if ([[csvRow objectAtIndex:j] isKindOfClass:[NSNull class]]) { 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 +1036,15 @@ } else { [csvCell setString:[[csvRow objectAtIndex:j] description]]; } - + // For NULL values supplied via an array no cell needs to be written. if ( [csvCell isEqualToString:nullString] ) { - - // Add empty strings as a pair of enclosing characters. + + // 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 +1057,31 @@ // 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])]; } - + // If the string isn't quoted or otherwise enclosed, escape occurrences of the // field separators and the line ending separator. if ( quoteFieldSeparators || csvCellIsNumeric ) { [csvCell replaceOccurrencesOfString:fieldSeparatorString - withString:escapedFieldSeparatorString - options:NSLiteralSearch - range:NSMakeRange(0,[csvCell length])]; + withString:escapedFieldSeparatorString + options:NSLiteralSearch + range:NSMakeRange(0,[csvCell length])]; [csvCell replaceOccurrencesOfString:lineEndString - withString:escapedLineEndString - options:NSLiteralSearch - range:NSMakeRange(0,[csvCell length])]; + withString:escapedLineEndString + 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]; @@ -1093,10 +1093,10 @@ } 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]]; } @@ -1202,40 +1202,32 @@ } } 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 - [tempRowArray replaceObjectAtIndex:i withObject:[NSNull null]]; - - } else { - - //strip enclosed and escaped characters - mutableField = [NSMutableString stringWithString:[tempRowArray objectAtIndex:i]]; - - //strip enclosed characters - if ( [mutableField length] >= (2*[enclosed length]) ) { - if ( [[mutableField substringToIndex:[enclosed length]] isEqualToString:enclosed] ) { - [mutableField deleteCharactersInRange:NSMakeRange(0,[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])]; - } else { - [mutableField replaceOccurrencesOfString:[NSString stringWithFormat:@"%@%@", escaped, terminated] withString:terminated options:NSLiteralSearch range:NSMakeRange(0, [mutableField length])]; - } - if ( ![lineEnds isEqualToString:@""] ) { - [mutableField replaceOccurrencesOfString:[NSString stringWithFormat:@"%@%@", escaped, lineEnds] withString:lineEnds options:NSLiteralSearch range:NSMakeRange(0, [mutableField length])]; + //strip enclosed and escaped characters + mutableField = [NSMutableString stringWithString:[tempRowArray objectAtIndex:i]]; + + //strip enclosed characters + if ( [mutableField length] >= (2*[enclosed length]) ) { + if ( [[mutableField substringToIndex:[enclosed length]] isEqualToString:enclosed] ) { + [mutableField deleteCharactersInRange:NSMakeRange(0,[enclosed length])]; } - if ( ![escaped isEqualToString:@""] && ![escaped isEqualToString:enclosed] ) { - [mutableField replaceOccurrencesOfString:[NSString stringWithFormat:@"%@%@", escaped, escaped] withString:escaped options:NSLiteralSearch range:NSMakeRange(0, [mutableField length])]; + if ( [[mutableField substringFromIndex:([mutableField length]-[enclosed length])] isEqualToString:enclosed] ) { + [mutableField deleteCharactersInRange:NSMakeRange(([mutableField length]-[enclosed length]),[enclosed length])]; } - //add field to tempRowArray - [tempRowArray replaceObjectAtIndex:i withObject:[NSString stringWithString:mutableField]]; } + //strip escaped characters + if ( ![enclosed isEqualToString:@""] ) { + [mutableField replaceOccurrencesOfString:[NSString stringWithFormat:@"%@%@", escaped, enclosed] withString:enclosed options:NSLiteralSearch range:NSMakeRange(0, [mutableField length])]; + } else { + [mutableField replaceOccurrencesOfString:[NSString stringWithFormat:@"%@%@", escaped, terminated] withString:terminated options:NSLiteralSearch range:NSMakeRange(0, [mutableField length])]; + } + if ( ![lineEnds isEqualToString:@""] ) { + [mutableField replaceOccurrencesOfString:[NSString stringWithFormat:@"%@%@", escaped, lineEnds] withString:lineEnds options:NSLiteralSearch range:NSMakeRange(0, [mutableField length])]; + } + if ( ![escaped isEqualToString:@""] && ![escaped isEqualToString:enclosed] ) { + [mutableField replaceOccurrencesOfString:[NSString stringWithFormat:@"%@%@", escaped, escaped] withString:escaped options:NSLiteralSearch range:NSMakeRange(0, [mutableField length])]; + } + //add field to tempRowArray + [tempRowArray replaceObjectAtIndex:i withObject:[NSString stringWithString:mutableField]]; } //add row to tempArray [tempArray addObject:[NSArray arrayWithArray:tempRowArray]]; @@ -1259,13 +1251,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 +1267,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 +1290,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 +1313,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 +1343,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 +1354,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 +1377,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]; } @@ -1409,7 +1401,7 @@ NSMutableString *errors = [NSMutableString string]; NSStringEncoding connectionEncoding = [mySQLConnection encoding]; NSMutableString *csvLineEnd; - + // Reset the interface [errorsView setString:@""]; [errorsView displayIfNeeded]; @@ -1417,13 +1409,13 @@ [singleProgressText displayIfNeeded]; [singleProgressBar setDoubleValue:0]; [singleProgressBar displayIfNeeded]; - + // Open the progress sheet [NSApp beginSheet:singleProgressSheet - modalForWindow:tableWindow modalDelegate:self - didEndSelector:nil contextInfo:nil]; - - + modalForWindow:tableWindow modalDelegate:self + didEndSelector:nil contextInfo:nil]; + + // Add a dump header to the dump file, dependant on export type. if ( [type isEqualToString:@"csv"] ) { csvLineEnd = [NSMutableString stringWithString:[exportMultipleLinesTerminatedField stringValue]]; @@ -1438,28 +1430,28 @@ 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]]; + [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]]; @@ -1467,20 +1459,20 @@ [singleProgressBar setIndeterminate:YES]; [singleProgressBar setUsesThreadedAnimation:YES]; [singleProgressBar startAnimation:self]; - + // 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]; @@ -1489,40 +1481,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]; - - // Add a spacer to the file - [fileHandle writeData:[[NSString stringWithFormat:@"%@%@%@", csvLineEnd, csvLineEnd, csvLineEnd] dataUsingEncoding:connectionEncoding]]; + 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]; - - // Add a spacer to the file - [fileHandle writeData:[[NSString stringWithString:@"\n\n\n"] dataUsingEncoding:connectionEncoding]]; + toFileHandle:fileHandle + tableName:tableName + withHeader:NO + silently:YES]; + + // 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]; @@ -1673,13 +1665,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; @@ -1816,7 +1808,7 @@ objectValueForTableColumn:(NSTableColumn *)aTableColumn [(NSPopUpButtonCell *)[aTableColumn dataCell] addItemsWithTitles:[importArray objectAtIndex:currentRow]]; //[(NSPopUpButtonCell *)[aTableColumn dataCell] selectItemAtIndex:[fieldMappingArray objectAtIndex:rowIndex]]; } - + return [fieldMappingArray objectAtIndex:rowIndex]; } } else { |