diff options
author | rowanbeentje <rowan@beent.je> | 2012-03-22 01:18:18 +0000 |
---|---|---|
committer | rowanbeentje <rowan@beent.je> | 2012-03-22 01:18:18 +0000 |
commit | 24f89a873caf37947f0447ff870ca4c8d55c453e (patch) | |
tree | 22162a0e1eead7190e316c384ff8c6c1b98661b3 | |
parent | 3916b4227d1e02942504e13a2d36b3e6f57670bb (diff) | |
download | sequelpro-24f89a873caf37947f0447ff870ca4c8d55c453e.tar.gz sequelpro-24f89a873caf37947f0447ff870ca4c8d55c453e.tar.bz2 sequelpro-24f89a873caf37947f0447ff870ca4c8d55c453e.zip |
- Rework SPTableData PRIMARY KEY and UNIQUE KEY parsing to use SPSQLParser instead of regexes
- Support multiple primary keys in the SPTableData parse
- If possible, use primary keys to preserve table content selection instead of row indexes
- Improve SPTableData primary keys method to use cached value instead of using another query
- Preserve selection when filtering tables if appropriate
-rw-r--r-- | Source/SPConstants.h | 2 | ||||
-rw-r--r-- | Source/SPConstants.m | 2 | ||||
-rw-r--r-- | Source/SPDatabaseDocument.m | 23 | ||||
-rw-r--r-- | Source/SPHistoryController.m | 12 | ||||
-rw-r--r-- | Source/SPIndexesController.m | 17 | ||||
-rw-r--r-- | Source/SPTableContent.h | 6 | ||||
-rw-r--r-- | Source/SPTableContent.m | 160 | ||||
-rw-r--r-- | Source/SPTableData.h | 1 | ||||
-rw-r--r-- | Source/SPTableData.m | 99 |
9 files changed, 199 insertions, 123 deletions
diff --git a/Source/SPConstants.h b/Source/SPConstants.h index 4b2d87a3..ce53ceb3 100644 --- a/Source/SPConstants.h +++ b/Source/SPConstants.h @@ -400,6 +400,8 @@ extern NSString *SPLastImportIntoNewTableType; extern NSString *SPGlobalValueHistory; extern NSString *SPBundleDeletedDefaultBundlesKey; extern NSString *SPHiddenKeyFileVisibilityKey; +extern NSString *SPSelectionDetailTypeIndexed; +extern NSString *SPSelectionDetailTypePrimaryKeyed; // URLs extern NSString *SPDonationsURL; diff --git a/Source/SPConstants.m b/Source/SPConstants.m index 7fa35505..ae9845fa 100644 --- a/Source/SPConstants.m +++ b/Source/SPConstants.m @@ -211,6 +211,8 @@ NSString *SPLastImportIntoNewTableType = @"LastImportIntoNewTableType" NSString *SPGlobalValueHistory = @"GlobalValueHistory"; NSString *SPBundleDeletedDefaultBundlesKey = @"deletedDefaultBundles"; NSString *SPHiddenKeyFileVisibilityKey = @"KeySelectionHiddenFilesVisibility"; +NSString *SPSelectionDetailTypeIndexed = @"SelectionDetailTypeNSIndexSet"; +NSString *SPSelectionDetailTypePrimaryKeyed = @"SelectionDetailTypePrimaryKeyedDetails"; // URLs NSString *SPDonationsURL = @"http://www.sequelpro.com/donate/"; diff --git a/Source/SPDatabaseDocument.m b/Source/SPDatabaseDocument.m index 7fd93c1b..529b05f5 100644 --- a/Source/SPDatabaseDocument.m +++ b/Source/SPDatabaseDocument.m @@ -4297,16 +4297,9 @@ static NSString *SPCreateSyntx = @"SPCreateSyntax"; if ([tableContentInstance filterSettings]) [sessionState setObject:[tableContentInstance filterSettings] forKey:@"contentFilter"]; - NSIndexSet *contentSelectedIndexSet = [tableContentInstance selectedRowIndexes]; - if (contentSelectedIndexSet && [contentSelectedIndexSet count]) { - NSMutableArray *indices = [NSMutableArray array]; - NSUInteger indexBuffer[[contentSelectedIndexSet count]]; - NSUInteger limit = [contentSelectedIndexSet getIndexes:indexBuffer maxCount:[contentSelectedIndexSet count] inIndexRange:NULL]; - NSUInteger idx; - for (idx = 0; idx < limit; idx++) { - [indices addObject:[NSNumber numberWithInteger:indexBuffer[idx]]]; - } - [sessionState setObject:indices forKey:@"contentSelectedIndexSet"]; + NSDictionary *contentSelectedRows = [tableContentInstance selectionDetailsAllowingIndexSelection:YES]; + if (contentSelectedRows) { + [sessionState setObject:contentSelectedRows forKey:@"contentSelection"]; } } @@ -4734,14 +4727,8 @@ static NSString *SPCreateSyntx = @"SPCreateSyntax"; [tablesListInstance selectTableAtIndex:[NSNumber numberWithInteger:[tables indexOfObject:[spfSession objectForKey:@"table"]]]]; // Restore table selection indexes - if([spfSession objectForKey:@"contentSelectedIndexSet"]) { - NSMutableIndexSet *anIndexSet = [NSMutableIndexSet indexSet]; - NSArray *items = [spfSession objectForKey:@"contentSelectedIndexSet"]; - NSUInteger i; - for(i=0; i<[items count]; i++) - [anIndexSet addIndex:[NSArrayObjectAtIndex(items, i) integerValue]]; - - [tableContentInstance setSelectedRowIndexesToRestore:anIndexSet]; + if([spfSession objectForKey:@"contentSelection"]) { + [tableContentInstance setSelectionToRestore:[spfSession objectForKey:@"contentSelection"]]; } [[tablesListInstance valueForKeyPath:@"tablesListView"] scrollRowToVisible:[tables indexOfObject:[spfSession objectForKey:@"selectedTable"]]]; diff --git a/Source/SPHistoryController.m b/Source/SPHistoryController.m index 3bd3b0b3..2729397c 100644 --- a/Source/SPHistoryController.m +++ b/Source/SPHistoryController.m @@ -267,7 +267,7 @@ NSString *contentSortCol = [tableContentInstance sortColumnName]; BOOL contentSortColIsAsc = [tableContentInstance sortColumnIsAscending]; NSUInteger contentPageNumber = [tableContentInstance pageNumber]; - NSIndexSet *contentSelectedIndexSet = [tableContentInstance selectedRowIndexes]; + NSDictionary *contentSelectedRows = [tableContentInstance selectionDetailsAllowingIndexSelection:YES]; NSRect contentViewport = [tableContentInstance viewport]; NSDictionary *contentFilter = [tableContentInstance filterSettings]; NSData *filterTableData = [tableContentInstance filterTableData]; @@ -283,7 +283,7 @@ [NSNumber numberWithBool:contentSortColIsAsc], @"sortIsAsc", nil]; if (contentSortCol) [contentState setObject:contentSortCol forKey:@"sortCol"]; - if (contentSelectedIndexSet) [contentState setObject:contentSelectedIndexSet forKey:@"selection"]; + if (contentSelectedRows) [contentState setObject:contentSelectedRows forKey:@"selection"]; if (contentFilter) [contentState setObject:contentFilter forKey:@"filter"]; if (filterTableData) [contentState setObject:filterTableData forKey:@"filterTable"]; @@ -322,7 +322,7 @@ || ![[currentHistoryEntry objectForKey:@"contentFilter"] isEqualToDictionary:contentFilter]))) { [currentHistoryEntry setObject:[NSValue valueWithRect:contentViewport] forKey:@"contentViewport"]; - if (contentSelectedIndexSet) [currentHistoryEntry setObject:contentSelectedIndexSet forKey:@"contentSelectedIndexSet"]; + if (contentSelectedRows) [currentHistoryEntry setObject:contentSelectedRows forKey:@"contentSelection"]; // Special case: if the last history item is currently active, and has no table, // but the new selection does - delete the last entry, in order to replace it. @@ -344,7 +344,7 @@ [NSValue valueWithRect:contentViewport], @"contentViewport", nil]; if (contentSortCol) [newEntry setObject:contentSortCol forKey:@"contentSortCol"]; - if (contentSelectedIndexSet) [newEntry setObject:contentSelectedIndexSet forKey:@"contentSelectedIndexSet"]; + if (contentSelectedRows) [newEntry setObject:contentSelectedRows forKey:@"contentSelection"]; if (contentFilter) [newEntry setObject:contentFilter forKey:@"contentFilter"]; [history addObject:newEntry]; @@ -397,7 +397,7 @@ // Set table content details for restore [tableContentInstance setSortColumnNameToRestore:[historyEntry objectForKey:@"contentSortCol"] isAscending:[[historyEntry objectForKey:@"contentSortColIsAsc"] boolValue]]; [tableContentInstance setPageToRestore:[[historyEntry objectForKey:@"contentPageNumber"] integerValue]]; - [tableContentInstance setSelectedRowIndexesToRestore:[historyEntry objectForKey:@"contentSelectedIndexSet"]]; + [tableContentInstance setSelectionToRestore:[historyEntry objectForKey:@"contentSelection"]]; [tableContentInstance setViewportToRestore:[[historyEntry objectForKey:@"contentViewport"] rectValue]]; [tableContentInstance setFiltersToRestore:[historyEntry objectForKey:@"contentFilter"]]; @@ -514,7 +514,7 @@ // Restore the content view state [tableContentInstance setSortColumnNameToRestore:[contentState objectForKey:@"sortCol"] isAscending:[[contentState objectForKey:@"sortIsAsc"] boolValue]]; [tableContentInstance setPageToRestore:[[contentState objectForKey:@"page"] unsignedIntegerValue]]; - [tableContentInstance setSelectedRowIndexesToRestore:[contentState objectForKey:@"selection"]]; + [tableContentInstance setSelectionToRestore:[contentState objectForKey:@"selection"]]; [tableContentInstance setViewportToRestore:[[contentState objectForKey:@"viewport"] rectValue]]; [tableContentInstance setFiltersToRestore:[contentState objectForKey:@"filter"]]; } diff --git a/Source/SPIndexesController.m b/Source/SPIndexesController.m index 99d359f7..f4f03d28 100644 --- a/Source/SPIndexesController.m +++ b/Source/SPIndexesController.m @@ -187,22 +187,7 @@ static const NSString *SPNewIndexKeyBlockSize = @"IndexKeyBlockSize"; // Check to see whether a primary key already exists for the table, and if so select INDEX instead for (NSDictionary *field in fields) { - BOOL hasCompositePrimaryKey = NO; - BOOL isPrimaryKey = [[field objectForKey:@"isprimarykey"] boolValue]; - - // The 'isprimarykey' key of a field is only present for single column primary keys, not composite keys, - // so we need to check the indexes manually. - if (!isPrimaryKey) { - for (NSDictionary *index in indexes) - { - if ([[index objectForKey:@"Key_name"] isEqualToString:@"PRIMARY"]) { - hasCompositePrimaryKey = YES; - break; - } - } - } - - if (isPrimaryKey || hasCompositePrimaryKey) { + if ([[field objectForKey:@"isprimarykey"] boolValue]) { // Hide primary key option [[[indexTypePopUpButton menu] itemWithTag:SPPrimaryKeyMenuTag] setHidden:YES]; diff --git a/Source/SPTableContent.h b/Source/SPTableContent.h index d8feee7e..7e77c749 100644 --- a/Source/SPTableContent.h +++ b/Source/SPTableContent.h @@ -143,7 +143,7 @@ BOOL tableRowsSelectable; NSString *sortColumnToRestore; NSUInteger pageToRestore; - NSIndexSet *selectionIndexToRestore; + NSDictionary *selectionToRestore; NSRect selectionViewportToRestore; NSString *filterFieldToRestore, *filterComparisonToRestore, *filterValueToRestore, *firstBetweenValueToRestore, *secondBetweenValueToRestore; @@ -272,14 +272,14 @@ - (NSString *)sortColumnName; - (BOOL)sortColumnIsAscending; - (NSUInteger)pageNumber; -- (NSIndexSet *)selectedRowIndexes; +- (NSDictionary *)selectionDetailsAllowingIndexSelection:(BOOL)allowIndexFallback; - (NSRect)viewport; - (CGFloat)tablesListWidth; - (NSDictionary *)filterSettings; - (NSArray *)dataColumnDefinitions; - (void)setSortColumnNameToRestore:(NSString *)theSortColumnName isAscending:(BOOL)isAscending; - (void)setPageToRestore:(NSUInteger)thePage; -- (void)setSelectedRowIndexesToRestore:(NSIndexSet *)theIndexSet; +- (void)setSelectionToRestore:(NSDictionary *)theSelection; - (void)setViewportToRestore:(NSRect)theViewport; - (void)setFiltersToRestore:(NSDictionary *)filterSettings; - (void)storeCurrentDetailsForRestoration; diff --git a/Source/SPTableContent.m b/Source/SPTableContent.m index 3e81c2ad..948c4eb3 100644 --- a/Source/SPTableContent.m +++ b/Source/SPTableContent.m @@ -129,7 +129,7 @@ sortColumnToRestore = nil; sortColumnToRestoreIsAsc = YES; pageToRestore = 1; - selectionIndexToRestore = nil; + selectionToRestore = nil; selectionViewportToRestore = NSZeroRect; filterFieldToRestore = nil; filterComparisonToRestore = nil; @@ -303,14 +303,6 @@ [(SPCopyTable*)[tableContentView onMainThread] scrollRectToVisible:selectionViewportToRestore]; } - // Restore selection indexes if appropriate - if (selectionIndexToRestore) { - BOOL previousTableRowsSelectable = tableRowsSelectable; - tableRowsSelectable = YES; - [[tableContentView onMainThread] selectRowIndexes:selectionIndexToRestore byExtendingSelection:NO]; - tableRowsSelectable = previousTableRowsSelectable; - } - // Update display if necessary if (!NSEqualRects(selectionViewportToRestore, NSZeroRect)) [[tableContentView onMainThread] setNeedsDisplayInRect:selectionViewportToRestore]; @@ -854,6 +846,65 @@ // End cancellation ability [tableDocumentInstance disableTaskCancellation]; + // Restore selection indexes if appropriate + if (selectionToRestore) { + BOOL previousTableRowsSelectable = tableRowsSelectable; + tableRowsSelectable = YES; + NSMutableIndexSet *selectionSet = [NSMutableIndexSet indexSet]; + + // Currently two types of stored selection are supported: primary keys and direct index sets. + if ([[selectionToRestore objectForKey:@"type"] isEqualToString:SPSelectionDetailTypePrimaryKeyed]) { + + // Check whether the keys are still present and get their positions + BOOL columnsFound = YES; + NSArray *primaryKeyFieldNames = [selectionToRestore objectForKey:@"keys"]; + NSUInteger primaryKeyFieldCount = [primaryKeyFieldNames count]; + NSUInteger primaryKeyFieldIndexes[primaryKeyFieldCount]; + for (NSUInteger i = 0; i < primaryKeyFieldCount; i++) { + primaryKeyFieldIndexes[i] = [[tableDataInstance columnNames] indexOfObject:[primaryKeyFieldNames objectAtIndex:i]]; + if (primaryKeyFieldIndexes[i] == NSNotFound) { + columnsFound = NO; + } + } + + // Only proceed with reselection if all columns were found + if (columnsFound) { + NSDictionary *selectionKeysToRestore = [selectionToRestore objectForKey:@"rows"]; + NSUInteger rowsToSelect = [selectionKeysToRestore count]; + BOOL rowMatches = NO; + + for (NSUInteger i = 0; i < tableRowsCount; i++) { + if (primaryKeyFieldCount == 1) { + if ([selectionKeysToRestore objectForKey:SPDataStorageObjectAtRowAndColumn(tableValues, i, primaryKeyFieldIndexes[0])]) { + rowMatches = YES; + } + } else { + NSMutableString *lookupString = [[NSMutableString alloc] initWithString:[SPDataStorageObjectAtRowAndColumn(tableValues, i, primaryKeyFieldIndexes[0]) description]]; + for (NSUInteger j = 1; j < primaryKeyFieldCount; j++) { + [lookupString appendString:SPUniqueSchemaDelimiter]; + [lookupString appendString:[SPDataStorageObjectAtRowAndColumn(tableValues, i, primaryKeyFieldIndexes[j]) description]]; + } + if ([selectionKeysToRestore objectForKey:lookupString]) rowMatches = YES; + [lookupString release]; + } + + if (rowMatches) { + [selectionSet addIndex:i]; + rowsToSelect--; + if (rowsToSelect <= 0) break; + rowMatches = NO; + } + } + } + + } else if ([[selectionToRestore objectForKey:@"type"] isEqualToString:SPSelectionDetailTypeIndexed]) { + selectionSet = [selectionToRestore objectForKey:@"rows"]; + } + + [[tableContentView onMainThread] selectRowIndexes:selectionSet byExtendingSelection:NO]; + tableRowsSelectable = previousTableRowsSelectable; + } + if ([prefs boolForKey:SPLimitResults] && (contentPage > 1 || (NSInteger)tableRowsCount == [prefs integerForKey:SPLimitResultsValue])) { isLimited = YES; @@ -1465,6 +1516,7 @@ #endif // Reset and reload data using the new filter settings + [self setSelectionToRestore:[self selectionDetailsAllowingIndexSelection:NO]]; previousTableRowsCount = 0; [self clearTableValues]; [self loadTableValues]; @@ -1596,7 +1648,7 @@ // Update data using the new sort order previousTableRowsCount = tableRowsCount; - + [self setSelectionToRestore:[self selectionDetailsAllowingIndexSelection:NO]]; [self loadTableValues]; if ([mySQLConnection queryErrored] && ![mySQLConnection lastQueryWasCancelled]) { @@ -3626,11 +3678,81 @@ } /** - * Provide a getter for the table's selected rows index set + * Provide a getter for the table's selected rows. If a primary key is available, + * the returned dictionary will contain details of the primary key used, and an + * identifier for each selected row. If no primary key is available, the returned + * dictionary will contain details and a list of the selected row *indexes* if the + * supplied argument is set to true, which may not always be appropriate. */ -- (NSIndexSet *) selectedRowIndexes +- (NSDictionary *)selectionDetailsAllowingIndexSelection:(BOOL)allowIndexFallback { - return [tableContentView selectedRowIndexes]; + + // If a primary key is available, store the selection details for rows using the primary key. + NSArray *primaryKeyFieldNames = [tableDataInstance primaryKeyColumnNames]; + if (primaryKeyFieldNames) { + + // Set up an array of the column indexes to store + NSUInteger primaryKeyFieldCount = [primaryKeyFieldNames count]; + NSUInteger primaryKeyFieldIndexes[primaryKeyFieldCount]; + BOOL problemColumns = NO; + for (NSUInteger i = 0; i < primaryKeyFieldCount; i++) { + primaryKeyFieldIndexes[i] = [[tableDataInstance columnNames] indexOfObject:[primaryKeyFieldNames objectAtIndex:i]]; + if (primaryKeyFieldIndexes[i] == NSNotFound) { + problemColumns = YES; +#ifndef SP_REFACTOR + } else { + if ([prefs boolForKey:SPLoadBlobsAsNeeded]) { + if ([tableDataInstance columnIsBlobOrText:[primaryKeyFieldNames objectAtIndex:i]]) { + problemColumns = YES; + } + } +#endif + } + } + + // Only proceed with key-based selection if there were no problem columns + if (!problemColumns) { + NSIndexSet *selectedRowIndexes = [tableContentView selectedRowIndexes]; + NSUInteger *indexBuffer = malloc(sizeof(NSUInteger) * [selectedRowIndexes count]); + NSUInteger indexCount = [selectedRowIndexes getIndexes:indexBuffer maxCount:[selectedRowIndexes count] inIndexRange:NULL]; + + NSMutableDictionary *selectedRowLookupTable = [NSMutableDictionary dictionaryWithCapacity:indexCount]; + NSNumber *trueNumber = [NSNumber numberWithBool:YES]; + for (NSUInteger i = 0; i < indexCount; i++) { + if (primaryKeyFieldCount == 1) { + [selectedRowLookupTable setObject:trueNumber forKey:[SPDataStorageObjectAtRowAndColumn(tableValues, indexBuffer[i], primaryKeyFieldIndexes[0]) description]]; + } else { + NSMutableString *lookupString = [NSMutableString stringWithString:SPDataStorageObjectAtRowAndColumn(tableValues, indexBuffer[i], primaryKeyFieldIndexes[0])]; + for (NSUInteger j = 1; j < primaryKeyFieldCount; j++) { + [lookupString appendString:SPUniqueSchemaDelimiter]; + [lookupString appendString:[SPDataStorageObjectAtRowAndColumn(tableValues, indexBuffer[i], primaryKeyFieldIndexes[j]) description]]; + } + [selectedRowLookupTable setObject:trueNumber forKey:lookupString]; + } + } + free(indexBuffer); + + return [NSDictionary dictionaryWithObjectsAndKeys: + SPSelectionDetailTypePrimaryKeyed, @"type", + selectedRowLookupTable, @"rows", + primaryKeyFieldNames, @"keys", + nil]; + } + } + + // If no primary key was available, fall back to using just the selected row indexes if permitted + if (allowIndexFallback) { + return [NSDictionary dictionaryWithObjectsAndKeys: + SPSelectionDetailTypeIndexed, @"type", + [tableContentView selectedRowIndexes], @"rows", + nil]; + } + + // Otherwise return a blank selection + return [NSDictionary dictionaryWithObjectsAndKeys: + SPSelectionDetailTypeIndexed, @"type", + [NSIndexSet indexSet], @"rows", + nil]; } /** @@ -3711,11 +3833,11 @@ /** * Set the selected row indexes to restore on next table load */ -- (void) setSelectedRowIndexesToRestore:(NSIndexSet *)theIndexSet +- (void) setSelectionToRestore:(NSDictionary *)theSelection { - if (selectionIndexToRestore) [selectionIndexToRestore release], selectionIndexToRestore = nil; + if (selectionToRestore) [selectionToRestore release], selectionToRestore = nil; - if (theIndexSet) selectionIndexToRestore = [[NSIndexSet alloc] initWithIndexSet:theIndexSet]; + if (theSelection) selectionToRestore = [theSelection copy]; } /** @@ -3777,7 +3899,7 @@ { [self setSortColumnNameToRestore:[self sortColumnName] isAscending:[self sortColumnIsAscending]]; [self setPageToRestore:[self pageNumber]]; - [self setSelectedRowIndexesToRestore:[self selectedRowIndexes]]; + [self setSelectionToRestore:[self selectionDetailsAllowingIndexSelection:YES]]; [self setViewportToRestore:[self viewport]]; [self setFiltersToRestore:[self filterSettings]]; } @@ -3789,7 +3911,7 @@ { [self setSortColumnNameToRestore:nil isAscending:YES]; [self setPageToRestore:1]; - [self setSelectedRowIndexesToRestore:nil]; + [self setSelectionToRestore:nil]; [self setViewportToRestore:NSZeroRect]; [self setFiltersToRestore:nil]; } @@ -4291,7 +4413,7 @@ if (sortCol) [sortCol release]; [usedQuery release]; if (sortColumnToRestore) [sortColumnToRestore release]; - if (selectionIndexToRestore) [selectionIndexToRestore release]; + if (selectionToRestore) [selectionToRestore release]; if (filterFieldToRestore) filterFieldToRestore = nil; if (filterComparisonToRestore) filterComparisonToRestore = nil; if (filterValueToRestore) filterValueToRestore = nil; diff --git a/Source/SPTableData.h b/Source/SPTableData.h index 94c95da4..e292fe7a 100644 --- a/Source/SPTableData.h +++ b/Source/SPTableData.h @@ -35,6 +35,7 @@ NSMutableArray *constraints; NSArray *triggers; NSMutableDictionary *status; + NSMutableArray *primaryKeyColumns; NSString *tableEncoding; NSString *tableCreateSyntax; diff --git a/Source/SPTableData.m b/Source/SPTableData.m index 0c0814d6..b2626057 100644 --- a/Source/SPTableData.m +++ b/Source/SPTableData.m @@ -53,6 +53,7 @@ columnNames = [[NSMutableArray alloc] init]; constraints = [[NSMutableArray alloc] init]; status = [[NSMutableDictionary alloc] init]; + primaryKeyColumns = [[NSMutableArray alloc] init]; triggers = nil; tableEncoding = nil; @@ -375,6 +376,7 @@ [columnNames removeAllObjects]; [constraints removeAllObjects]; tableHasAutoIncrementField = NO; + [primaryKeyColumns removeAllObjects]; if( [tableListInstance tableType] == SPTableTypeTable || [tableListInstance tableType] == SPTableTypeView ) { tableData = [self informationForTable:[tableListInstance tableName]]; @@ -400,6 +402,7 @@ [tableEncoding release]; } tableEncoding = [[NSString alloc] initWithString:[tableData objectForKey:@"encoding"]]; + [primaryKeyColumns addObjectsFromArray:[tableData objectForKey:@"primarykeyfield"]]; pthread_mutex_unlock(&dataProcessingLock); @@ -419,6 +422,7 @@ NSEnumerator *enumerator; tableHasAutoIncrementField = NO; + [primaryKeyColumns removeAllObjects]; if (viewData == nil) { [columns removeAllObjects]; @@ -707,33 +711,38 @@ // add "isprimarykey" to the corresponding tableColumn // add dict root "primarykeyfield" = <field> for faster accessing else if( [NSArrayObjectAtIndex(parts, 0) hasPrefix:@"PRIMARY"] && [parts count] == 3) { - NSString *parsedString = [(NSString*)NSArrayObjectAtIndex(parts, 2) stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; - if([parsedString length]>4) { - NSString *priFieldName = [[parsedString substringWithRange:NSMakeRange(2,[parsedString length]-4)] stringByReplacingOccurrencesOfString:@"``" withString:@"`"]; - [tableData setObject:priFieldName forKey:@"primarykeyfield"]; - for(id theTableColumn in tableColumns) - if([[theTableColumn objectForKey:@"name"] isEqualToString:priFieldName]) { - [theTableColumn setObject:[NSNumber numberWithInteger:1] forKey:@"isprimarykey"]; - break; + SPSQLParser *keyParser = [SPSQLParser stringWithString:NSArrayObjectAtIndex(parts, 2)]; + keyParser = [SPSQLParser stringWithString:[keyParser stringFromCharacter:'(' toCharacter:')' inclusively:NO]]; + NSArray *primaryKeyQuotedNames = [keyParser splitStringByCharacter:',']; + if ([keyParser length]) { + NSMutableArray *primaryKeyFields = [NSMutableArray array]; + for (NSString *quotedKeyName in primaryKeyQuotedNames) { + NSString *primaryFieldName = [[SPSQLParser stringWithString:quotedKeyName] unquotedString]; + [primaryKeyFields addObject:primaryFieldName]; + for (NSMutableDictionary *theTableColumn in tableColumns) { + if ([[theTableColumn objectForKey:@"name"] isEqualToString:primaryFieldName]) { + [theTableColumn setObject:[NSNumber numberWithInteger:1] forKey:@"isprimarykey"]; + break; + } } + } + [tableData setObject:primaryKeyFields forKey:@"primarykeyfield"]; } } // unique keys // add to each corresponding tableColumn the tag "unique" if given else if( [NSArrayObjectAtIndex(parts, 0) hasPrefix:@"UNIQUE"] && [parts count] == 4) { - NSString *parsedString = [(NSString*)NSArrayObjectAtIndex(parts, 3) stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; - if([parsedString length]>4) { - NSArray *uniqueFieldNames = [parsedString componentsSeparatedByString:@"`,`"]; - for(NSString* uniq in uniqueFieldNames) { - NSString *uniqField = [[uniq stringByReplacingOccurrencesOfRegex:@"^\\(`|`\\)" withString:@""] stringByReplacingOccurrencesOfString:@"``" withString:@"`"]; - for(id theTableColumn in tableColumns) - if([[theTableColumn objectForKey:@"name"] isEqualToString:uniqField]) { - [theTableColumn setObject:[NSNumber numberWithInteger:1] forKey:@"unique"]; - break; - } + SPSQLParser *keyParser = [SPSQLParser stringWithString:NSArrayObjectAtIndex(parts, 3)]; + keyParser = [SPSQLParser stringWithString:[keyParser stringFromCharacter:'(' toCharacter:')' inclusively:NO]]; + for (NSString *quotedUniqueKey in [keyParser splitStringByCharacter:',']) { + NSString *uniqueFieldName = [[SPSQLParser stringWithString:quotedUniqueKey] unquotedString]; + for (NSMutableDictionary *theTableColumn in tableColumns) { + if ([[theTableColumn objectForKey:@"name"] isEqualToString:uniqueFieldName]) { + [theTableColumn setObject:[NSNumber numberWithInteger:1] forKey:@"unique"]; + break; + } } - } } // who knows @@ -1284,52 +1293,19 @@ - (NSArray *)primaryKeyColumnNames { - // Ensure that identifier queries occur over UTF8 - BOOL changeEncoding = ![[mySQLConnection encoding] isEqualToString:@"utf8"]; - if (changeEncoding) { - [mySQLConnection storeEncodingForRestoration]; - [mySQLConnection setEncoding:@"utf8"]; - } - - NSString *selectedTable = [tableListInstance tableName]; - if(![selectedTable length]) return nil; - - SPMySQLResult *r; - NSMutableArray *keyColumns = [NSMutableArray array]; - - // select all columns that are primary keys - // MySQL before 5.0.3 does not support the WHERE syntax - r = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW COLUMNS FROM %@ /*!50003 WHERE `key` = 'PRI'*/", [selectedTable backtickQuotedString]]]; - [r setReturnDataAsStrings:YES]; - [r setDefaultRowReturnType:SPMySQLResultRowAsArray]; - - if ([r numberOfRows] < 1) { - if (changeEncoding && [mySQLConnection isConnected]) [mySQLConnection restoreStoredEncoding]; - return nil; - } - - if ([mySQLConnection queryErrored]) { - if ([mySQLConnection isConnected]) { - NSRunAlertPanel(@"Error", [NSString stringWithFormat:NSLocalizedString(@"An error occured while retrieving the PRIMARY KEY data:\n\n%@",@"message when the query that fetches the primary keys fails"), [mySQLConnection lastErrorMessage]], @"OK", nil, nil); - if (changeEncoding) [mySQLConnection restoreStoredEncoding]; - } - return nil; - } - - - for (NSArray *resultRow in r) { + // If processing is already in action, wait for it to complete + [self _loopWhileWorking]; - // check if the row is indeed a key (for MySQL servers before 5.0.3) - if ([[NSArrayObjectAtIndex(resultRow ,3) description] isEqualToString:@"PRI"]) { - [keyColumns addObject:[NSArrayObjectAtIndex(resultRow ,0) description]]; + if ([columns count] == 0) { + if ([tableListInstance tableType] == SPTableTypeView) { + [self updateInformationForCurrentView]; + } else { + [self updateInformationForCurrentTable]; } } - if (changeEncoding) [mySQLConnection restoreStoredEncoding]; - - if([keyColumns count]) return keyColumns; - - return nil; + if (![primaryKeyColumns count]) return nil; + return primaryKeyColumns; } #pragma mark - @@ -1343,6 +1319,7 @@ [columnNames release]; [constraints release]; [status release]; + [primaryKeyColumns release]; if (triggers) [triggers release]; if (tableEncoding) [tableEncoding release]; |