aboutsummaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/SPAppController.h2
-rw-r--r--Source/SPAppController.m77
-rw-r--r--Source/SPBundleHTMLOutputController.h2
-rw-r--r--Source/SPBundleHTMLOutputController.m68
-rw-r--r--Source/SPCopyTable.m24
-rw-r--r--Source/SPDatabaseDocument.m3
-rw-r--r--Source/SPTableContent.h2
-rw-r--r--Source/SPTableContent.m152
8 files changed, 213 insertions, 117 deletions
diff --git a/Source/SPAppController.h b/Source/SPAppController.h
index 0d68b26c..569ef2b8 100644
--- a/Source/SPAppController.h
+++ b/Source/SPAppController.h
@@ -113,7 +113,7 @@
- (void)handleEventWithURL:(NSURL*)url;
- (IBAction)executeBundleItemForApp:(id)sender;
-- (NSDictionary*)shellEnvironment;
+- (NSDictionary*)shellEnvironmentForDocument:(NSString*)docUUID;
- (void)addHTMLOutputController:(id)controller;
diff --git a/Source/SPAppController.m b/Source/SPAppController.m
index 841a4d69..e5b47c80 100644
--- a/Source/SPAppController.m
+++ b/Source/SPAppController.m
@@ -663,10 +663,10 @@
while(1) {
NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
- untilDate:[NSDate distantPast]
- inMode:NSDefaultRunLoopMode
- dequeue:YES];
-
+ untilDate:[NSDate distantPast]
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES];
+
if ([event type] == NSKeyDown) {
unichar key = [[event characters] length] == 1 ? [[event characters] characterAtIndex:0] : 0;
if (([event modifierFlags] & NSCommandKeyMask) && key == '.') {
@@ -684,33 +684,50 @@
return;
}
- if(processDocument && command && [command isEqualToString:@"passToDoc"]) {
- NSMutableDictionary *cmdDict = [NSMutableDictionary dictionary];
- [cmdDict setObject:parameter forKey:@"parameter"];
- [cmdDict setObject:passedProcessID forKey:@"id"];
- [processDocument handleSchemeCommand:cmdDict];
- return;
+ if(processDocument && command) {
+ if([command isEqualToString:@"passToDoc"]) {
+ NSMutableDictionary *cmdDict = [NSMutableDictionary dictionary];
+ [cmdDict setObject:parameter forKey:@"parameter"];
+ [cmdDict setObject:passedProcessID forKey:@"id"];
+ [processDocument handleSchemeCommand:cmdDict];
+ return;
+ }
+ else {
+ SPBeginAlertSheet(NSLocalizedString(@"sequelpro URL Scheme Error", @"sequelpro url Scheme Error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [NSApp mainWindow], self, nil, nil,
+ [NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [command description], NSLocalizedString(@"sequelpro URL scheme command not supported.", @"sequelpro URL scheme command not supported.")]);
+
+ return;
+ }
}
- if(processDocument != nil) {
+ if(passedProcessID && [passedProcessID length]) {
// If command failed notify the file handle hand shake mechanism
NSString *out = @"1";
[out writeToFile:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultStatusPathHeader, passedProcessID]
atomically:YES
encoding:NSUTF8StringEncoding
error:nil];
- out = @"Scheme Error";
+ out = NSLocalizedString(@"An error for sequelpro URL scheme command occurred. Probably no corresponding connection window found.", @"An error for sequelpro URL scheme command occurred. Probably no corresponding connection window found.");
[out writeToFile:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultPathHeader, passedProcessID]
atomically:YES
encoding:NSUTF8StringEncoding
error:nil];
- }
+
+ SPBeginAlertSheet(NSLocalizedString(@"sequelpro URL Scheme Error", @"sequelpro url Scheme Error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [NSApp mainWindow], self, nil, nil,
+ [NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [command description], NSLocalizedString(@"An error for sequelpro URL scheme command occurred. Probably no corresponding connection window found.", @"An error for sequelpro URL scheme command occurred. Probably no corresponding connection window found.")]);
+
+
+ usleep(5000);
+ [[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultStatusPathHeader, passedProcessID] error:nil];
+ [[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultPathHeader, passedProcessID] error:nil];
+ [[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultMetaPathHeader, passedProcessID] error:nil];
+ [[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryInputPathHeader, passedProcessID] error:nil];
- if(passedProcessID == nil || ![passedProcessID length]) {
+
+
+ } else {
SPBeginAlertSheet(NSLocalizedString(@"sequelpro URL Scheme Error", @"sequelpro url Scheme Error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [NSApp mainWindow], self, nil, nil,
[NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [command description], NSLocalizedString(@"An error occur while executing a scheme command. If the scheme command was invoked by a Bundle command, it could be that the command still runs. You can try to terminate it by pressing ⌘+. or via the Activities pane.", @"an error occur while executing a scheme command. if the scheme command was invoked by a bundle command, it could be that the command still runs. you can try to terminate it by pressing ⌘+. or via the activities pane.")]);
- } else {
- NSBeep();
}
if(processDocument)
@@ -720,6 +737,7 @@
NSLog(@"param: %@", parameter);
NSLog(@"command: %@", command);
NSLog(@"command id: %@", passedProcessID);
+
}
- (IBAction)executeBundleItemForApp:(id)sender
@@ -858,6 +876,7 @@
if([[win delegate] isKindOfClass:[SPBundleHTMLOutputController class]]) {
if([[[win delegate] windowUUID] isEqualToString:[cmdData objectForKey:SPBundleFileUUIDKey]]) {
correspondingWindowFound = YES;
+ [[win delegate] setDocUUID:uuid];
[[win delegate] displayHTMLContent:output withOptions:nil];
break;
}
@@ -866,6 +885,7 @@
if(!correspondingWindowFound) {
SPBundleHTMLOutputController *c = [[SPBundleHTMLOutputController alloc] init];
[c setWindowUUID:[cmdData objectForKey:SPBundleFileUUIDKey]];
+ [c setDocUUID:uuid];
[c displayHTMLContent:output withOptions:nil];
[[NSApp delegate] addHTMLOutputController:c];
}
@@ -889,11 +909,30 @@
* Return of certain shell variables mainly for usage in JavaScript support inside the
* HTML output window to allow to ask on run-time
*/
-- (NSDictionary*)shellEnvironment
+- (NSDictionary*)shellEnvironmentForDocument:(NSString*)docUUID
{
NSMutableDictionary *env = [NSMutableDictionary dictionary];
- SPDatabaseDocument *doc = [self frontDocument];
- if(doc) [env addEntriesFromDictionary:[doc shellVariables]];
+ SPDatabaseDocument *doc;
+ if(docUUID == nil)
+ doc = [self frontDocument];
+ else {
+ BOOL found = NO;
+ for (NSWindow *aWindow in [NSApp orderedWindows]) {
+ if([[aWindow windowController] isMemberOfClass:[SPWindowController class]]) {
+ for(SPDatabaseDocument *d in [[aWindow windowController] documents]) {
+ if([d processID] && [[d processID] isEqualToString:docUUID]) {
+ [env addEntriesFromDictionary:[d shellVariables]];
+ found = YES;
+ break;
+ }
+ }
+ }
+ if(found) break;
+ }
+ }
+
+ // if(doc && [doc shellVariables]) [env addEntriesFromDictionary:[doc shellVariables]];
+ // if(doc) [doc release];
id firstResponder = [[NSApp keyWindow] firstResponder];
if([firstResponder respondsToSelector:@selector(executeBundleItemForInputField:)]) {
BOOL selfIsQueryEditor = ([[[firstResponder class] description] isEqualToString:@"SPTextView"]) ;
diff --git a/Source/SPBundleHTMLOutputController.h b/Source/SPBundleHTMLOutputController.h
index 0ad38241..ea0b96da 100644
--- a/Source/SPBundleHTMLOutputController.h
+++ b/Source/SPBundleHTMLOutputController.h
@@ -32,6 +32,7 @@
NSString *docTitle;
NSString *initHTMLSourceString;
NSString *windowUUID;
+ NSString *docUUID;
WebPreferences *webPreferences;
}
@@ -39,6 +40,7 @@
@property(readwrite,retain) NSString *docTitle;
@property(readwrite,retain) NSString *initHTMLSourceString;
@property(readwrite,retain) NSString *windowUUID;
+@property(readwrite,retain) NSString *docUUID;
- (IBAction)printDocument:(id)sender;
diff --git a/Source/SPBundleHTMLOutputController.m b/Source/SPBundleHTMLOutputController.m
index a632a51a..7cad079b 100644
--- a/Source/SPBundleHTMLOutputController.m
+++ b/Source/SPBundleHTMLOutputController.m
@@ -25,11 +25,14 @@
#import "SPBundleHTMLOutputController.h"
#import "SPAlertSheets.h"
+@class WebScriptCallFrame;
+
@implementation SPBundleHTMLOutputController
@synthesize docTitle;
@synthesize initHTMLSourceString;
@synthesize windowUUID;
+@synthesize docUUID;
/**
* Initialisation
@@ -63,7 +66,6 @@
{
[[self window] orderFront:nil];
-
[self setInitHTMLSourceString:content];
[[webView mainFrame] loadHTMLString:content baseURL:nil];
@@ -208,6 +210,7 @@
[webView close];
[self setInitHTMLSourceString:@""];
windowUUID = @"";
+ docUUID = @"";
[self release];
}
@@ -299,6 +302,20 @@
}
}
+- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
+{
+ if(error) {
+ NSLog(@"%@", [error localizedDescription]);
+ }
+}
+
+- (void)webView:(WebView *)webView didFailLoadWithError:(NSError*)error forFrame:(WebFrame *)frame
+{
+ if(error) {
+ NSLog(@"%@", [error localizedDescription]);
+ }
+}
+
#pragma mark -
#pragma mark JS support
@@ -328,9 +345,11 @@
return NO;
}
-- (void)webView:(WebView *)sender windowScriptObjectAvailable: (WebScriptObject *)windowScriptObject
+- (void)webView:(WebView *)sender windowScriptObjectAvailable:(WebScriptObject *)windowScriptObject
{
+
[windowScriptObject setValue:self forKey:@"system"];
+ [webView setScriptDebugDelegate:self];
}
+ (NSString *)webScriptNameForSelector:(SEL)aSelector
@@ -370,17 +389,40 @@
return YES;
}
-- (void)windowScriptObjectAvailable:(WebScriptObject*)webScriptObject {
- [webScriptObject setValue:self forKey:@"system"];
+- (void)webView:(WebView *)webView failedToParseSource:(NSString *)source baseLineNumber:(NSUInteger)lineNumber fromURL:(NSURL *)url withError:(NSError *)error forWebFrame:(WebFrame *)webFrame
+{
+ NSString *mes = [NSString stringWithFormat:@"Failed to parse JavaScript source:\nline = %ld\nerror = %@ with\n%@\nfor source = \n%@", lineNumber, [error localizedDescription], [error userInfo], source];
+
+ NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"JavaScript Parsing Error", @"javascript parsing error")
+ defaultButton:NSLocalizedString(@"OK", @"OK button")
+ alternateButton:nil
+ otherButton:nil
+ informativeTextWithFormat:mes];
+
+ [alert setAlertStyle:NSCriticalAlertStyle];
+ [alert runModal];
}
+- (void)webView:(WebView *)webView exceptionWasRaised:(WebScriptCallFrame *)frame sourceId:(NSInteger)sid line:(NSInteger)lineno forWebFrame:(WebFrame *)webFrame
+{
+ NSString *mes = [NSString stringWithFormat:@"Exception:\nline = %ld\nfunction = %@\ncaller = %@\nexception = %@", lineno, [frame functionName], [frame caller], [frame userInfo], [frame exception]];
+
+ NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"JavaScript Exception", @"javascript exception")
+ defaultButton:NSLocalizedString(@"OK", @"OK button")
+ alternateButton:nil
+ otherButton:nil
+ informativeTextWithFormat:mes];
+
+ [alert setAlertStyle:NSCriticalAlertStyle];
+ [alert runModal];
+}
/**
* JavaScript window.system.getShellEnvironmentForName('a_key') function to
* return the value for key keyName
*/
- (NSString *)getShellEnvironmentForName:(NSString*)keyName
{
- return [[[NSApp delegate] shellEnvironment] objectForKey:keyName];
+ return [[[NSApp delegate] shellEnvironmentForDocument:nil] objectForKey:keyName];
}
/**
@@ -403,6 +445,9 @@
NSString *command = nil;
NSString *uuid = nil;
+ if([self docUUID] && [[self docUUID] length])
+ uuid = [self docUUID];
+
if([call isKindOfClass:[NSString class]])
command = [NSString stringWithString:call];
else if([[[call class] description] isEqualToString:@"WebScriptObject"]){
@@ -426,8 +471,15 @@
NSString *output = nil;
if(uuid == nil)
output = [command runBashCommandWithEnvironment:nil atCurrentDirectoryPath:nil error:&err];
- else
- output = [command runBashCommandWithEnvironment:nil
+ else {
+ NSMutableDictionary *theEnv = [NSMutableDictionary dictionary];
+ [theEnv addEntriesFromDictionary:[[NSApp delegate] shellEnvironmentForDocument:nil]];
+ [theEnv setObject:uuid forKey:SPBundleShellVariableProcessID];
+ [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryInputPathHeader, uuid] forKey:SPBundleShellVariableQueryFile];
+ [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultPathHeader, uuid] forKey:SPBundleShellVariableQueryResultFile];
+ [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultStatusPathHeader, uuid] forKey:SPBundleShellVariableQueryResultStatusFile];
+ [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultMetaPathHeader, uuid] forKey:SPBundleShellVariableQueryResultMetaFile];
+ output = [command runBashCommandWithEnvironment:theEnv
atCurrentDirectoryPath:nil
callerInstance:[NSApp delegate]
contextInfo:[NSDictionary dictionaryWithObjectsAndKeys:
@@ -436,7 +488,7 @@
uuid, SPBundleFileInternalexecutionUUID,
nil]
error:&err];
-
+ }
if(err != nil) {
NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Error while executing JavaScript BASH command", @"error while executing javascript bash command")
diff --git a/Source/SPCopyTable.m b/Source/SPCopyTable.m
index 7a132348..6b9383ab 100644
--- a/Source/SPCopyTable.m
+++ b/Source/SPCopyTable.m
@@ -973,8 +973,8 @@ NSInteger kBlobAsImageFile = 4;
// Save the current line if it's the last field in the table
if ( [self numberOfColumns] - 1 == column ) {
- if([[self delegate] respondsToSelector:@selector(addRowToDB)])
- [[self delegate] addRowToDB];
+ if([[self delegate] respondsToSelector:@selector(saveRowToTable)])
+ [[self delegate] saveRowToTable];
[[self window] makeFirstResponder:self];
} else {
// Select the next field for editing
@@ -991,8 +991,8 @@ NSInteger kBlobAsImageFile = 4;
// Save the current line if it's the last field in the table
if ( column < 1 ) {
- if([[self delegate] respondsToSelector:@selector(addRowToDB)])
- [[self delegate] addRowToDB];
+ if([[self delegate] respondsToSelector:@selector(saveRowToTable)])
+ [[self delegate] saveRowToTable];
[[self window] makeFirstResponder:self];
} else {
// Select the previous field for editing
@@ -1010,8 +1010,8 @@ NSInteger kBlobAsImageFile = 4;
return YES;
[[control window] makeFirstResponder:control];
- if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(addRowToDB)])
- [[self delegate] addRowToDB];
+ if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(saveRowToTable)])
+ [[self delegate] saveRowToTable];
return YES;
}
@@ -1028,10 +1028,10 @@ NSInteger kBlobAsImageFile = 4;
if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; //check if we're already at the end of the list
[[control window] makeFirstResponder:control];
- if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(addRowToDB)])
- [[self delegate] addRowToDB];
+ if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(saveRowToTable)])
+ [[self delegate] saveRowToTable];
- if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; //check again. addRowToDB could reload the table and change the number of rows
+ if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; //check again. saveRowToTable could reload the table and change the number of rows
if (tableStorage && column>=[tableStorage columnCount]) return YES; //the column count could change too
[self selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO];
@@ -1051,10 +1051,10 @@ NSInteger kBlobAsImageFile = 4;
NSUInteger newRow = row-1;
[[control window] makeFirstResponder:control];
- if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(addRowToDB)])
- [[self delegate] addRowToDB];
+ if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(saveRowToTable)])
+ [[self delegate] saveRowToTable];
- if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; // addRowToDB could reload the table and change the number of rows
+ if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; // saveRowToTable could reload the table and change the number of rows
if (tableStorage && column>=[tableStorage columnCount]) return YES; //the column count could change too
[self selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO];
diff --git a/Source/SPDatabaseDocument.m b/Source/SPDatabaseDocument.m
index a65dab2b..44d3965c 100644
--- a/Source/SPDatabaseDocument.m
+++ b/Source/SPDatabaseDocument.m
@@ -4816,6 +4816,9 @@
- (NSDictionary*)shellVariables
{
+
+ if(!_isConnected) return [NSDictionary dictionary];
+
NSMutableDictionary *env = [NSMutableDictionary dictionary];
if (tablesListInstance) {
diff --git a/Source/SPTableContent.h b/Source/SPTableContent.h
index 1dc4caf9..e3fd8a53 100644
--- a/Source/SPTableContent.h
+++ b/Source/SPTableContent.h
@@ -197,7 +197,7 @@
- (void)clickLinkArrowTask:(SPTextAndLinkCell *)theArrowCell;
- (IBAction)setCompareTypes:(id)sender;
- (void)processResultIntoDataStorage:(MCPStreamingResult *)theResult approximateRowCount:(NSUInteger)targetRowCount;
-- (BOOL)addRowToDB;
+- (BOOL)saveRowToTable;
- (NSString *)argumentForRow:(NSInteger)row;
- (NSString *)argumentForRow:(NSInteger)row excludingLimits:(BOOL)excludeLimits;
- (NSString *)argumentForRow:(NSUInteger)rowIndex ofTable:(NSString *)tableForColumn andDatabase:(NSString *)database includeBlobs:(BOOL)includeBlobs;
diff --git a/Source/SPTableContent.m b/Source/SPTableContent.m
index 1e9bdf5f..82282b5d 100644
--- a/Source/SPTableContent.m
+++ b/Source/SPTableContent.m
@@ -2370,116 +2370,116 @@
/**
- * Tries to write a new row to the database.
- * Returns YES if row is written to database, otherwise NO; also returns YES if no row
- * is being edited and nothing has to be written to the database.
+ * Tries to write a new row to the table.
+ * Returns YES if row is written to table, otherwise NO; also returns YES if no row
+ * is being edited or nothing has to be written to the table.
*/
-- (BOOL)addRowToDB
+- (BOOL)saveRowToTable
{
- if([tablesListInstance tableType] == SPTableTypeView) return;
+ // Only handle tables - views should be handled per-cell.
+ if ([tablesListInstance tableType] == SPTableTypeView) return NO;
- NSMutableString *queryString;
- id rowObject;
- NSMutableString *rowValue = [NSMutableString string];
- NSString *currentTime = [[NSDate date] descriptionWithCalendarFormat:@"%H:%M:%S" timeZone:nil locale:nil];
- BOOL prefsLoadBlobsAsNeeded = [prefs boolForKey:SPLoadBlobsAsNeeded];
- NSInteger i;
-
- if ( !isEditingRow || currentlyEditingRow == -1) {
- return YES;
- }
-
- [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:@"SMySQLQueryWillBePerformed" object:tableDocumentInstance];
+ // If no row is being edited, return success.
+ if (!isEditingRow) return YES;
- // If editing, compare the new row to the old row and if they are identical finish editing without saving.
+ // If editing, quickly compare the new row to the old row and if they are identical finish editing without saving.
if (!isEditingNewRow && [oldRow isEqualToArray:[tableValues rowContentsAtIndex:currentlyEditingRow]]) {
isEditingRow = NO;
currentlyEditingRow = -1;
- [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance];
return YES;
}
- NSMutableArray *fieldValues = [[NSMutableArray alloc] init];
-
- // Get the field values
- for ( i = 0 ; i < [dataColumns count] ; i++ ) {
+ // Iterate through the row contents, constructing the (ordered) arrays of keys and values to be saved
+ NSMutableArray *rowFieldsToSave = [[NSMutableArray alloc] initWithCapacity:[dataColumns count]];
+ NSMutableArray *rowValuesToSave = [[NSMutableArray alloc] initWithCapacity:[dataColumns count]];
+ NSInteger i;
+ id rowObject;
+ for (i = 0; i < [dataColumns count]; i++) {
rowObject = [tableValues cellDataAtRow:currentlyEditingRow column:i];
- // Add not loaded placeholders directly for easy comparison when added
- if (prefsLoadBlobsAsNeeded && !isEditingNewRow && [rowObject isSPNotLoaded])
- {
- [fieldValues addObject:[SPNotLoaded notLoaded]];
- continue;
-
- // Catch CURRENT_TIMESTAMP automatic updates - if the row is new and the cell value matches
- // the default value, or if the cell hasn't changed, update the current timestamp.
- } else if ([[NSArrayObjectAtIndex(dataColumns, i) objectForKey:@"onupdatetimestamp"] integerValue]
- && ( (isEditingNewRow && [rowObject isEqualTo:[NSArrayObjectAtIndex(dataColumns, i) objectForKey:@"default"]])
- || (!isEditingNewRow && [rowObject isEqualTo:NSArrayObjectAtIndex(oldRow, i)])))
- {
- [rowValue setString:@"CURRENT_TIMESTAMP"];
+ // Skip "not loaded" cells entirely - these only occur when editing tables when the
+ // preference setting is enabled, and don't need to be saved back to the table.
+ if ([rowObject isSPNotLoaded]) continue;
+
+ // If an edit has taken place, and the field value hasn't changed, the value
+ // can also be skipped
+ if (!isEditingNewRow && [rowObject isEqual:NSArrayObjectAtIndex(oldRow, i)]) continue;
- } else if ( [rowObject isNSNull]
- || ([rowObject isMemberOfClass:[NSString class]] && [[rowObject description] isEqualToString:@""]) ) {
+ // Prepare to derive the value to save
+ NSString *fieldValue;
+ NSString *fieldTypeGroup = [NSArrayObjectAtIndex(dataColumns, i) objectForKey:@"typegrouping"];
- //NULL when user entered the nullValue string defined in the prefs or when a number field isn't set
- // problem: when a number isn't set, sequel-pro enters 0
- // -> second if argument isn't necessary!
- [rowValue setString:@"NULL"];
- } else if ( [[NSArrayObjectAtIndex(dataColumns, i) objectForKey:@"typegrouping"] isEqualToString:@"geometry"] ) {
- [rowValue setString:([rowObject isKindOfClass:[MCPGeometryData class]]) ? [[rowObject wktString] getGeomFromTextString] : [(NSString*)rowObject getGeomFromTextString]];
+ // Use NULL when the user has entered the nullValue string defined in the preferences,
+ // or when a numeric field is empty.
+ if ([rowObject isNSNull]
+ || (([fieldTypeGroup isEqualToString:@"float"] || [fieldTypeGroup isEqualToString:@"integer"])
+ && [[rowObject description] isEqualToString:@""]))
+ {
+ fieldValue = @"NULL";
+
+ // Convert geometry values to their string values
+ } else if ([fieldTypeGroup isEqualToString:@"geometry"]) {
+ fieldValue = ([rowObject isKindOfClass:[MCPGeometryData class]]) ? [[rowObject wktString] getGeomFromTextString] : [(NSString*)rowObject getGeomFromTextString];
+
// Convert the object to a string (here we can add special treatment for date-, number- and data-fields)
} else {
- // I don't believe any of these class matches are ever met at present.
- if ( [rowObject isKindOfClass:[NSCalendarDate class]] ) {
- [rowValue setString:[NSString stringWithFormat:@"'%@'", [mySQLConnection prepareString:[rowObject description]]]];
- } else if ( [rowObject isKindOfClass:[NSNumber class]] ) {
- [rowValue setString:[rowObject stringValue]];
- } else if ( [rowObject isKindOfClass:[NSData class]] ) {
- [rowValue setString:[NSString stringWithFormat:@"X'%@'", [mySQLConnection prepareBinaryData:rowObject]]];
+ // I believe these class matches are not ever met at present.
+ if ([rowObject isKindOfClass:[NSCalendarDate class]]) {
+ fieldValue = [NSString stringWithFormat:@"'%@'", [mySQLConnection prepareString:[rowObject description]]];
+ } else if ([rowObject isKindOfClass:[NSNumber class]]) {
+ fieldValue = [rowObject stringValue];
+
+ // Convert data to its hex representation
+ } else if ([rowObject isKindOfClass:[NSData class]]) {
+ fieldValue = [NSString stringWithFormat:@"X'%@'", [mySQLConnection prepareBinaryData:rowObject]];
+
} else {
if ([[rowObject description] isEqualToString:@"CURRENT_TIMESTAMP"]) {
- [rowValue setString:@"CURRENT_TIMESTAMP"];
- } else if ([[NSArrayObjectAtIndex(dataColumns, i) objectForKey:@"typegrouping"] isEqualToString:@"bit"]) {
- [rowValue setString:[NSString stringWithFormat:@"b'%@'", ((![[rowObject description] length] || [[rowObject description] isEqualToString:@"0"]) ? @"0" : [rowObject description])]];
- } else if ([[NSArrayObjectAtIndex(dataColumns, i) objectForKey:@"typegrouping"] isEqualToString:@"date"]
- && [[rowObject description] isEqualToString:@"NOW()"]) {
- [rowValue setString:@"NOW()"];
+ fieldValue = @"CURRENT_TIMESTAMP";
+ } else if ([fieldTypeGroup isEqualToString:@"bit"]) {
+ fieldValue = [NSString stringWithFormat:@"b'%@'", ((![[rowObject description] length] || [[rowObject description] isEqualToString:@"0"]) ? @"0" : [rowObject description])];
+ } else if ([fieldTypeGroup isEqualToString:@"date"] && [[rowObject description] isEqualToString:@"NOW()"]) {
+ fieldValue = @"NOW()";
} else {
- [rowValue setString:[NSString stringWithFormat:@"'%@'", [mySQLConnection prepareString:[rowObject description]]]];
+ fieldValue = [NSString stringWithFormat:@"'%@'", [mySQLConnection prepareString:[rowObject description]]];
}
}
}
- [fieldValues addObject:[NSString stringWithString:rowValue]];
+
+ // Store the key and value in the ordered arrays for saving.
+ [rowFieldsToSave addObject:[NSArrayObjectAtIndex(dataColumns, i) objectForKey:@"name"]];
+ [rowValuesToSave addObject:fieldValue];
}
- // Use INSERT syntax when creating new rows - no need to do not loaded checking, as all values have been entered
- if ( isEditingNewRow ) {
+ [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:@"SMySQLQueryWillBePerformed" object:tableDocumentInstance];
+ NSMutableString *queryString;
+
+ // Use INSERT syntax when creating new rows
+ if (isEditingNewRow) {
queryString = [NSString stringWithFormat:@"INSERT INTO %@ (%@) VALUES (%@)",
- [selectedTable backtickQuotedString], [[tableDataInstance columnNames] componentsJoinedAndBacktickQuoted], [fieldValues componentsJoinedByString:@","]];
- // Use UPDATE syntax otherwise
+ [selectedTable backtickQuotedString], [rowFieldsToSave componentsJoinedAndBacktickQuoted], [rowValuesToSave componentsJoinedByString:@", "]];
+
+ // Otherwise use an UPDATE syntax to save only the changed cells - if this point is reached,
+ // the equality test has failed and so there is always at least one changed cell
} else {
- BOOL firstCellOutput = NO;
queryString = [NSMutableString stringWithFormat:@"UPDATE %@ SET ", [selectedTable backtickQuotedString]];
- for ( i = 0 ; i < [dataColumns count] ; i++ ) {
-
- // If data column loading is deferred and the value is the not loaded string, skip this cell
- if (prefsLoadBlobsAsNeeded && [[fieldValues objectAtIndex:i] isSPNotLoaded]) continue;
-
- if (firstCellOutput) [queryString appendString:@", "];
- else firstCellOutput = YES;
-
+ for (i = 0; i < [rowFieldsToSave count]; i++) {
+ if (i) [queryString appendString:@", "];
[queryString appendFormat:@"%@ = %@",
- [[NSArrayObjectAtIndex(dataColumns, i) objectForKey:@"name"] backtickQuotedString], [fieldValues objectAtIndex:i]];
+ [NSArrayObjectAtIndex(rowFieldsToSave, i) backtickQuotedString],
+ NSArrayObjectAtIndex(rowValuesToSave, i)];
}
[queryString appendFormat:@" WHERE %@", [self argumentForRow:-2]];
}
+ [rowFieldsToSave release];
+ [rowValuesToSave release];
+
+ // Run the query
[mySQLConnection queryString:queryString];
- [fieldValues release];
[[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance];
// If no rows have been changed, show error if appropriate.
@@ -2494,7 +2494,7 @@
isEditingRow = NO;
isEditingNewRow = NO;
currentlyEditingRow = -1;
- [[SPQueryController sharedQueryController] showErrorInConsole:[NSString stringWithFormat:NSLocalizedString(@"/* WARNING %@ No rows have been affected */\n", @"warning shown in the console when no rows have been affected after writing to the db"), currentTime] connection:[tableDocumentInstance name]];
+ [[SPQueryController sharedQueryController] showErrorInConsole:NSLocalizedString(@"/* WARNING: No rows have been affected */\n", @"warning shown in the console when no rows have been affected after writing to the db") connection:[tableDocumentInstance name]];
return YES;
// On success...
@@ -2582,7 +2582,7 @@
isSavingRow = YES;
// Attempt to save the row, and return YES if the save succeeded.
- if ([self addRowToDB]) {
+ if ([self saveRowToTable]) {
isSavingRow = NO;
return YES;
}