diff options
author | Bibiko <bibiko@eva.mpg.de> | 2010-03-26 15:14:11 +0000 |
---|---|---|
committer | Bibiko <bibiko@eva.mpg.de> | 2010-03-26 15:14:11 +0000 |
commit | 52309a04b95bc6dea3ead6d1968bd6e17be285bf (patch) | |
tree | 1b2ca1982f9b5c9599e04289d1de2c88a4ba6a60 /Frameworks/MCPKit/MCPFoundationKit | |
parent | 91db43ffddbe3f5476ef3265b57d68c61a8e06c2 (diff) | |
download | sequelpro-52309a04b95bc6dea3ead6d1968bd6e17be285bf.tar.gz sequelpro-52309a04b95bc6dea3ead6d1968bd6e17be285bf.tar.bz2 sequelpro-52309a04b95bc6dea3ead6d1968bd6e17be285bf.zip |
• first steps to ease the structure querying for auto-completion and navigator
- now it accumulates the data and caches them db by db, ie one has to select a db before using its structure for completion and navigator
- next step is to avoid querying info_schema as much as possible
- it will only query the structure if something was changed
- next steps follows as soon as possible
Diffstat (limited to 'Frameworks/MCPKit/MCPFoundationKit')
-rw-r--r-- | Frameworks/MCPKit/MCPFoundationKit/MCPConnection.h | 19 | ||||
-rw-r--r-- | Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m | 108 |
2 files changed, 92 insertions, 35 deletions
diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.h b/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.h index 89739e23..0b239b5f 100644 --- a/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.h +++ b/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.h @@ -83,6 +83,21 @@ */ - (NSString *)connectionID; +/** + * + */ +- (NSString *)database; + +/** + * + */ +- (BOOL)navigatorSchemaPathExistsForDatabase:(NSString*)dbname; + +/** + * + */ +- (NSArray*)allDatabaseNames; + @end @interface MCPConnection : NSObject @@ -123,7 +138,7 @@ BOOL isMaxAllowedPacketEditable; NSString *serverVersionString; - NSDictionary *theDbStructure; + NSMutableDictionary *structure; NSDictionary *uniqueDbIdentifier; NSArray *allKeysofDbStructure; @@ -247,7 +262,7 @@ void performThreadedKeepAlive(void *ptr); - (MCPResult *)listTablesFromDB:(NSString *)dbName like:(NSString *)tablesName; - (MCPResult *)listFieldsFromTable:(NSString *)tableName; - (MCPResult *)listFieldsFromTable:(NSString *)tableName like:(NSString *)fieldsName; -- (void)queryDbStructure; +- (void)queryDbStructureAndForceUpdate:(NSNumber*)forceUpdate; - (NSDictionary *)getDbStructure; - (NSInteger)getUniqueDbIdentifierFor:(NSString*)term; - (NSArray *)getAllKeysOfDbStructure; diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m b/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m index 878d6844..bc7917bd 100644 --- a/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m +++ b/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m @@ -115,7 +115,7 @@ static BOOL sTruncateLongFieldInLogs = YES; useKeepAlive = YES; keepAliveInterval = 60; - theDbStructure = nil; + structure = [[NSMutableDictionary alloc] initWithCapacity:1]; allKeysofDbStructure = nil; uniqueDbIdentifier = nil; isQueryingDbStructure = NO; @@ -422,7 +422,7 @@ static BOOL sTruncateLongFieldInLogs = YES; } if (serverVersionString) [serverVersionString release], serverVersionString = nil; - if (theDbStructure) [theDbStructure release], theDbStructure = nil; + if (structure) [structure release], structure = nil; if (allKeysofDbStructure) [allKeysofDbStructure release], allKeysofDbStructure = nil; if (uniqueDbIdentifier) [uniqueDbIdentifier release], uniqueDbIdentifier = nil; if (pingThread != NULL) pthread_cancel(pingThread), pingThread = NULL; @@ -1836,12 +1836,73 @@ void performThreadedKeepAlive(void *ptr) * Updates the dict containing the structure of all available databases (mainly for completion/navigator) * executed on a new connection. */ -- (void)queryDbStructure +- (void)queryDbStructureAndForceUpdate:(NSNumber*)forceUpdate { NSAutoreleasePool *queryPool = [[NSAutoreleasePool alloc] init]; if (!isQueryingDbStructure && [self serverMajorVersion] >= 5) { + NSString *SPUniqueSchemaDelimiter = @""; + + NSString *connectionID; + if([delegate respondsToSelector:@selector(connectionID)]) + connectionID = [NSString stringWithString:[[self delegate] connectionID]]; + else + connectionID = @"_"; + + if(![structure valueForKey:connectionID]) + [structure setObject:[NSMutableDictionary dictionary] forKey:connectionID]; + + // Add all known database coming from connection + NSArray *dbs = [[self delegate] allDatabaseNames]; + for(id db in dbs) { + NSString *db_id = [NSString stringWithFormat:@"%@%@%@", connectionID, SPUniqueSchemaDelimiter, db]; + if(![[structure valueForKey:connectionID] valueForKey:db_id]) { + [[structure valueForKey:connectionID] setObject:db forKey:db_id]; + } + } + + // Remove deleted databases + NSArray *keys = [[structure valueForKey:connectionID] allKeys]; + for(id key in keys) { + NSString *db = [[key componentsSeparatedByString:SPUniqueSchemaDelimiter] objectAtIndex:1]; + if(![dbs containsObject:db]) { + [[structure valueForKey:connectionID] removeObjectForKey:key]; + } + } + + NSString *currentDatabase = nil; + if([delegate respondsToSelector:@selector(database)]) + currentDatabase = [[self delegate] database]; + + if(!currentDatabase || (currentDatabase && ![currentDatabase length])) { + isQueryingDbStructure = NO; + [queryPool release]; + return; + } + + if([currentDatabase isEqualToString:@"mysql"]) { + if([[self delegate] navigatorSchemaPathExistsForDatabase:currentDatabase]) { + [queryPool release]; + return; + } + } + if([currentDatabase isEqualToString:@"information_schema"]) { + if([[self delegate] navigatorSchemaPathExistsForDatabase:currentDatabase]) { + [queryPool release]; + return; + } + } + + if(forceUpdate == nil) { + if([[self delegate] navigatorSchemaPathExistsForDatabase:currentDatabase]) { + [queryPool release]; + return; + } + } + + NSString *currentDatabaseEscaped = [currentDatabase stringByReplacingOccurrencesOfString:@"'" withString:@"\'"]; + MYSQL *structConnection = mysql_init(NULL); if (structConnection) { const char *theLogin = [self cStringFromString:connectionLogin]; @@ -1894,7 +1955,7 @@ void performThreadedKeepAlive(void *ptr) } NSUInteger numberOfItems = 20000; - query = @"SELECT COUNT(*) FROM `information_schema`.`COLUMNS`"; + query = [NSString stringWithFormat:@"SELECT COUNT(1) FROM `information_schema`.`COLUMNS` WHERE TABLE_SCHEMA = '%@'", currentDatabaseEscaped]; encodedSetNameData = NSStringDataUsingLossyEncoding(query, theConnectionEncoding, 1); setNameCString = [encodedSetNameData bytes]; setNameCStringLength = [encodedSetNameData length]; @@ -1916,42 +1977,29 @@ void performThreadedKeepAlive(void *ptr) } // Query the desired data - NSString *queryDbString = @"" - @"SELECT TABLE_SCHEMA AS `databases`, TABLE_NAME AS `tables`, COLUMN_NAME AS `fields`, COLUMN_TYPE AS `type`, CHARACTER_SET_NAME AS `charset`, '0' AS `structtype`, `COLUMN_KEY` AS `KEY`, `EXTRA` AS EXTRA, `PRIVILEGES` AS `PRIVILEGES`, `COLLATION_NAME` AS `collation`, `COLUMN_DEFAULT` AS `default`, `IS_NULLABLE` AS `is_nullable`, `COLUMN_COMMENT` AS `comment` FROM `information_schema`.`COLUMNS` " + NSString *queryDbString = [NSString stringWithFormat:@"" + @"SELECT TABLE_SCHEMA AS `databases`, TABLE_NAME AS `tables`, COLUMN_NAME AS `fields`, COLUMN_TYPE AS `type`, CHARACTER_SET_NAME AS `charset`, '0' AS `structtype`, `COLUMN_KEY` AS `KEY`, `EXTRA` AS EXTRA, `PRIVILEGES` AS `PRIVILEGES`, `COLLATION_NAME` AS `collation`, `COLUMN_DEFAULT` AS `default`, `IS_NULLABLE` AS `is_nullable`, `COLUMN_COMMENT` AS `comment` FROM `information_schema`.`COLUMNS` WHERE TABLE_SCHEMA = '%@'" @"UNION " - @"SELECT c.TABLE_SCHEMA AS `DATABASES`, c.TABLE_NAME AS `TABLES`, c.COLUMN_NAME AS `fields`, c.COLUMN_TYPE AS `TYPE`, c.CHARACTER_SET_NAME AS `CHARSET`, '1' AS `structtype`, `COLUMN_KEY` AS `KEY`, `EXTRA` AS EXTRA, `PRIVILEGES` AS `PRIVILEGES`, `COLLATION_NAME` AS `collation`, `COLUMN_DEFAULT` AS `default`, `IS_NULLABLE` AS `is_nullable`, `COLUMN_COMMENT` AS `comment` FROM `information_schema`.`COLUMNS` AS c, `information_schema`.`VIEWS` AS v WHERE c.TABLE_SCHEMA = v.TABLE_SCHEMA AND c.TABLE_NAME = v.TABLE_NAME " + @"SELECT c.TABLE_SCHEMA AS `DATABASES`, c.TABLE_NAME AS `TABLES`, c.COLUMN_NAME AS `fields`, c.COLUMN_TYPE AS `TYPE`, c.CHARACTER_SET_NAME AS `CHARSET`, '1' AS `structtype`, `COLUMN_KEY` AS `KEY`, `EXTRA` AS EXTRA, `PRIVILEGES` AS `PRIVILEGES`, `COLLATION_NAME` AS `collation`, `COLUMN_DEFAULT` AS `default`, `IS_NULLABLE` AS `is_nullable`, `COLUMN_COMMENT` AS `comment` FROM `information_schema`.`COLUMNS` AS c, `information_schema`.`VIEWS` AS v WHERE c.TABLE_SCHEMA = '%@' AND c.TABLE_SCHEMA = v.TABLE_SCHEMA AND c.TABLE_NAME = v.TABLE_NAME " @"UNION " - @"SELECT ROUTINE_SCHEMA AS `DATABASES`, ROUTINE_NAME AS `TABLES`, ROUTINE_NAME AS `fields`, `DTD_identifier` AS `TYPE`, '' AS `CHARSET`, '2' AS `structtype`, `IS_DETERMINISTIC` AS `KEY`, `SECURITY_TYPE` AS EXTRA, `DEFINER` AS `PRIVILEGES`, '' AS `collation`, '' AS `DEFAULT`, `SQL_DATA_ACCESS` AS `is_nullable`, '' AS `COMMENT` FROM `information_schema`.`ROUTINES` WHERE ROUTINE_TYPE = 'PROCEDURE' " + @"SELECT ROUTINE_SCHEMA AS `DATABASES`, ROUTINE_NAME AS `TABLES`, ROUTINE_NAME AS `fields`, `DTD_identifier` AS `TYPE`, '' AS `CHARSET`, '2' AS `structtype`, `IS_DETERMINISTIC` AS `KEY`, `SECURITY_TYPE` AS EXTRA, `DEFINER` AS `PRIVILEGES`, '' AS `collation`, '' AS `DEFAULT`, `SQL_DATA_ACCESS` AS `is_nullable`, '' AS `COMMENT` FROM `information_schema`.`ROUTINES` WHERE ROUTINE_TYPE = 'PROCEDURE' AND ROUTINE_SCHEMA = '%@'" @"UNION " - @"SELECT ROUTINE_SCHEMA AS `DATABASES`, ROUTINE_NAME AS `TABLES`, ROUTINE_NAME AS `fields`, `DTD_identifier` AS `TYPE`, '' AS `CHARSET`, '3' AS `structtype`, `IS_DETERMINISTIC` AS `KEY`, `SECURITY_TYPE` AS EXTRA, `DEFINER` AS `PRIVILEGES`, '' AS `collation`, '' AS `DEFAULT`, `SQL_DATA_ACCESS` AS `is_nullable`, '' AS `COMMENT` FROM `information_schema`.`ROUTINES` WHERE ROUTINE_TYPE = 'FUNCTION' " - @"ORDER BY `DATABASES`,`TABLES`,`fields`"; - + @"SELECT ROUTINE_SCHEMA AS `DATABASES`, ROUTINE_NAME AS `TABLES`, ROUTINE_NAME AS `fields`, `DTD_identifier` AS `TYPE`, '' AS `CHARSET`, '3' AS `structtype`, `IS_DETERMINISTIC` AS `KEY`, `SECURITY_TYPE` AS EXTRA, `DEFINER` AS `PRIVILEGES`, '' AS `collation`, '' AS `DEFAULT`, `SQL_DATA_ACCESS` AS `is_nullable`, '' AS `COMMENT` FROM `information_schema`.`ROUTINES` WHERE ROUTINE_TYPE = 'FUNCTION' AND ROUTINE_SCHEMA = '%@'", currentDatabaseEscaped, currentDatabaseEscaped, currentDatabaseEscaped, currentDatabaseEscaped]; + NSData *encodedQueryData = NSStringDataUsingLossyEncoding(queryDbString, theConnectionEncoding, 1); const char *queryCString = [encodedQueryData bytes]; unsigned long queryCStringLength = [encodedQueryData length]; if (mysql_real_query(structConnection, queryCString, queryCStringLength) == 0) { theResult = mysql_use_result(structConnection); - NSMutableDictionary *structure = [NSMutableDictionary dictionary]; NSMutableSet *allKeys = [[NSMutableSet alloc] initWithCapacity:20]; NSMutableSet *namesSet = [[NSMutableSet alloc] initWithCapacity:20]; NSMutableArray *allDbNames = [NSMutableArray array]; NSMutableArray *allTableNames = [NSMutableArray array]; - // id to make any key unique - NSString *connectionID; - if([delegate respondsToSelector:@selector(connectionID)]) - connectionID = [NSString stringWithString:[[self delegate] connectionID]]; - else - connectionID = @"_"; - - NSString *SPUniqueSchemaDelimiter = @""; NSUInteger cnt = 0; // used to make field data unique - [structure setObject:[NSMutableDictionary dictionary] forKey:connectionID]; - while(row = mysql_fetch_row(theResult)) { - cnt++; NSString *db = [self stringWithUTF8CString:row[0]]; NSString *db_id = [NSString stringWithFormat:@"%@%@%@", connectionID, SPUniqueSchemaDelimiter, db]; NSString *table = [self stringWithUTF8CString:row[1]]; @@ -1977,7 +2025,7 @@ void performThreadedKeepAlive(void *ptr) [allKeys addObject:table_id]; [allKeys addObject:field_id]; - if(![[structure valueForKey:connectionID] valueForKey:db_id]) { + if(!cnt || ![[structure valueForKey:connectionID] valueForKey:db_id]) { [[structure valueForKey:connectionID] setObject:[NSMutableDictionary dictionary] forKey:db_id]; } @@ -1987,19 +2035,13 @@ void performThreadedKeepAlive(void *ptr) [[[[structure valueForKey:connectionID] valueForKey:db_id] valueForKey:table_id] setObject:[NSArray arrayWithObjects:type, def, isnull, charset, coll, key, extra, priv, comment, [NSNumber numberWithUnsignedLongLong:cnt], nil] forKey:field_id]; [[[[structure valueForKey:connectionID] valueForKey:db_id] valueForKey:table_id] setObject:structtype forKey:@" struct_type "]; - + cnt++; } mysql_free_result(theResult); mysql_close(structConnection); - if(theDbStructure != nil) { - [theDbStructure release]; - theDbStructure = nil; - } - theDbStructure = [[NSDictionary dictionaryWithDictionary:structure] retain]; - if(allKeysofDbStructure != nil) { [allKeysofDbStructure release]; allKeysofDbStructure = nil; @@ -2060,7 +2102,7 @@ void performThreadedKeepAlive(void *ptr) */ - (NSDictionary *)getDbStructure { - return theDbStructure; + return [NSDictionary dictionaryWithDictionary:structure];; } /** @@ -2493,7 +2535,7 @@ void performThreadedKeepAlive(void *ptr) if (connectionSocket) [connectionSocket release]; if (connectionPassword) [connectionPassword release]; if (serverVersionString) [serverVersionString release], serverVersionString = nil; - if (theDbStructure) [theDbStructure release], theDbStructure = nil; + if (structure) [structure release], structure = nil; if (allKeysofDbStructure) [allKeysofDbStructure release], allKeysofDbStructure = nil; if (uniqueDbIdentifier) [uniqueDbIdentifier release], uniqueDbIdentifier = nil; |