[Mysql-cocoa-commits] CVS: SMySQL MCPConnection.m,NONE,1.1.2.1 SMySQLConnection.m,1.10,NONE
Brought to you by:
sergecohen
From: Serge C. <ser...@us...> - 2002-05-30 13:41:51
|
Update of /cvsroot/mysql-cocoa/SMySQL In directory usw-pr-cvs1:/tmp/cvs-serv7990 Added Files: Tag: version-2 MCPConnection.m Removed Files: Tag: version-2 SMySQLConnection.m Log Message: Renamed SMySQLConnection.m to MCPConnection.m --- NEW FILE: MCPConnection.m --- // // SMySQLConnection.m // SMySQL // // Created by serge cohen (ser...@m4...) on Sat Dec 08 2001. // Copyright (c) 2001 MySQL Cocoa project. // // This code is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 of the License, or any later version. // // This code is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more // details. // // For a copy of the GNU General Public License, visit <http://www.gnu.org/> or // write to the Free Software Foundation, Inc., 59 Temple Place--Suite 330, // Boston, MA 02111-1307, USA. // // More info at <http://mysql-cocoa.sourceforge.net/> // // $Id: MCPConnection.m,v 1.1.2.1 2002/05/30 13:41:47 sergecohen Exp $ #import "SMySQLConnection.h" #import "SMySQLResult.h" @implementation SMySQLConnection /*" This class is used to keep a connection with a MySQL server, it correspond to the MYSQL structure of the C API, or the database handle of the PERL DBI/DBD interface. You have to start any work on a MySQL server by getting a working SMySQLConnection object. Most likely you will use this kind of code: !{ SMySQLConnection *theConnec = [SMySQLConnection alloc]; SMySQLResult *theRes; theConnec = [theConnec initToHost::albert.com withLogin:@"toto" password:@"albert" port:0]; [theConnec selectDB:@"db1"]; theRes = [theConnec queryString:@"select * from table1"]; ... } "*/ + (NSDictionary *) getMySQLLocales /*" Gets a proper Locale dictionary to use formater to parse strings from MySQL. For example strings representing dates should give a proper Locales for use with methods such as NSDate::dateWithNaturalLanguageString: locales: "*/ { NSMutableDictionary *theLocalDict = [NSMutableDictionary dictionaryWithCapacity:12]; [theLocalDict setObject:@"." forKey:@"NSDecimalSeparator"]; return [NSDictionary dictionaryWithDictionary:theLocalDict]; } + (NSStringEncoding) encodingForMySQLEncoding:(const char *) mysqlEncoding /*" Gets a proper NSStringEncoding according to the given MySQL charset. MySQL 4.0 offers this charsets: big5 cp1251 cp1257 croat czech danish dec8 dos estonia euc_kr gb2312 gbk german1 greek hebrew hp8 hungarian koi8_ru koi8_ukr latin1 latin1_de latin2 latin5 sjis swe7 tis620 ujis usa7 win1250 win1251ukr WARNING : incomplete implementation. Please, send your fixes. "*/ { if (!strcmp(mysqlEncoding, "latin1")) { return NSISOLatin1StringEncoding; } if (!strcmp(mysqlEncoding, "latin2")) { return NSISOLatin2StringEncoding; } if (!strcmp(mysqlEncoding, "win1250")) { return NSWindowsCP1250StringEncoding; } if (!strcmp(mysqlEncoding, "cp1251")) { return NSWindowsCP1251StringEncoding; } if (!strcmp(mysqlEncoding, "euc_kr")) { return NSJapaneseEUCStringEncoding; } if (!strcmp(mysqlEncoding, "sjis")) { return NSShiftJISStringEncoding; } // default to iso latin 1, even if it is not exact (throw an exception?) return NSISOLatin1StringEncoding; } + (NSStringEncoding) defaultMySQLEncoding /*" Returns the default charset of the library mysqlclient used. "*/ { return [SMySQLConnection encodingForMySQLEncoding:MYSQL_CHARSET]; } - (id) init /*" Initialise a MySQLConnection without making a connection, most likely useless, except with #{setConnectionOption:withArgument:}. "*/ { self = [super init]; mConnection = mysql_init(NULL); mConnected = NO; if (mConnection == NULL) { [self autorelease]; return nil; } // mEncoding = NSISOLatin1StringEncoding; mEncoding = [SMySQLConnection encodingForMySQLEncoding:mysql_character_set_name(mConnection)]; return self; } - (id) initToHost:(NSString *) host withLogin:(NSString *) login password:(NSString *) pass usingPort:(int) port /*" Initialise a connection using a #{TCP/IP connection} with the given parameters (except if host is set to !{localhost}, in which case uses the default) - host is the hostname or IP adress - login is the user name - pass is the password corresponding to the user name - port is the TCP port to use to connect. If port = 0, uses the default port from mysql.h "*/ { #warning What happens when inited twice the NSObject? self = [super init]; mEncoding = NSISOLatin1StringEncoding; if (mConnected) { // If a the connection is on, disconnect and reset it to default mysql_close(mConnection); mConnection = NULL; } else { } mConnection = mysql_init(mConnection); mConnected = NO; if (mConnection == NULL) { [self autorelease]; return nil; } [self connectWithLogin:login password:pass host:host port:port socket:nil]; return self; } - (id) initToSocket:(NSString *) socket withLogin:(NSString *) login password:(NSString *) pass /*" Initialise a connection using a #{unix socket} with the given parameters - socket is the path to the socket - login is the user name - pass is the password corresponding to the user name "*/ { #warning What happens when inited twice the NSObject? self = [super init]; mEncoding = NSISOLatin1StringEncoding; if (mConnected) { // If a the connection is on, disconnect and reset it to default mysql_close(mConnection); mConnection = NULL; } else { } mConnection = mysql_init(mConnection); mConnected = NO; if (mConnection == NULL) { [self autorelease]; return nil; } [self connectWithLogin:login password:pass host:NULL port:0 socket:socket]; return self; } - (BOOL) setConnectionOption:(int) option withArgument:(id) arg /*" #{NOT YET IMPLEMENTED} This method is to be used for getting special option for a connection, in which case the SMySQLConnection has to be inited with the init method, then option are selected, finally connection is done using one of the connect methods: !{ SMySQLConnection *theConnect = [[SMySQLConnection alloc] init]; [theConnect setConnectionOption: option withArgument: arg]; [theConnect connectToHost:albert.com withLogin:@"toto" password:@"albert" port:0]; .... } "*/ { // So far do nothing except for testing if it's proper time for setting option // What about if some option where setted and a connection is made again with connectTo... if ((mConnected) || (! mConnection)) { return FALSE; } return YES; } - (BOOL) connectWithLogin:(NSString *) login password:(NSString *) pass host:(NSString *) host port:(int) port socket:(NSString *) socket /*" The method used by #{initToHost:withLogin:password:usingPort:} and #{initToSocket:withLogin:password:}. Same information and use of the parameters: - login is the user name - pass is the password corresponding to the user name - host is the hostname or IP adress - port is the TCP port to use to connect. If port = 0, uses the default port from mysql.h - socket is the path to the socket (for the localhost) The socket is used if the host is set to !{@"localhost"}, to an empty or a !{nil} string For the moment the implementation might not be safe if you have a nil pointer to one of the NSString* variables (underestand: I don't know what the result will be). "*/ { #warning What to do if one of the string is a nil pointer? const char *theLogin = [self cStringFromString:login]; const char *theHost = [self cStringFromString:host]; const char *thePass = [self cStringFromString:pass]; const char *theSocket = [self cStringFromString:socket]; void *theRet; if (mConnected) { // Disconnect if it was already connected mysql_close(mConnection); mConnection = NULL; mConnected = NO; [self init]; } if ([host isEqualToString:@""]) { theHost = NULL; } if (theSocket == NULL) { theSocket = kSMySQLConnectionDefaultSocket; } theRet = mysql_real_connect(mConnection, theHost, theLogin, thePass, NULL, port, theSocket, kSMySQL_default_option); if (theRet != mConnection) { return mConnected = NO; } mEncoding = [SMySQLConnection encodingForMySQLEncoding:mysql_character_set_name(mConnection)]; return mConnected = YES; } - (BOOL) selectDB:(NSString *) dbName /*" Selects a database to work with. The SMySQLConnection object needs to be properly inited and connected to a server. If a connection is not yet set or the selection of the database didn't work, returns NO. Returns YES in normal cases where the database is properly selected. So far, if dbName is a nil pointer it will return NO (as if it cannot connect), most likely this will throw an exception in the future. "*/ { if (dbName == nil) { #warning Should throw an exception, illegal string pointer (nil) // Here we should throw an exception, impossible to select a databse if the string is indeed a nil pointer return NO; } if (mConnected) { const char *theDBName = [self cStringFromString:dbName]; if (mysql_select_db(mConnection, theDBName) == NULL) { return YES; } } return NO; } - (NSString *) getLastErrorMessage /*" Returns a string with the last MySQL error message on the connection. "*/ { if (mConnection) { return [self stringWithCString:mysql_error(mConnection)]; } else { return [NSString stringWithString:@"No connection initailized yet (MYSQL* still NULL)\n"]; } } - (unsigned int) getLastErrorID /*" Returns the ErrorID of the last MySQL error on the connection. "*/ { if (mConnection) { return mysql_errno(mConnection); } return kSMySQLConnection_error_not_inited; } - (BOOL) isConnected /*" Returns YES if the SMySQLConnection is connected to a DB, NO otherwise. "*/ { return mConnected; } - (BOOL)checkConnection /*" Checks if the connection to the server is still on. If not, tries to reconnect (changing no parameters from the MYSQL pointer). This method just uses mysql_ping(). "*/ { return (BOOL)(! mysql_ping(mConnection)); } - (NSString *) prepareBinaryData:(NSData *) theData /*" Takes a NSData object and transform it in a proper string for sending to the server in between quotes. "*/ { const char *theCDataBuffer = [theData bytes]; unsigned int theLength = [theData length]; char *theCEscBuffer = (char *)calloc(sizeof(char),(theLength*2) + 1); NSString *theReturn; mysql_real_escape_string(mConnection, theCEscBuffer, theCDataBuffer, theLength); theReturn = [self stringWithCString:theCEscBuffer]; free (theCEscBuffer); return theReturn; } - (NSString *) prepareString:(NSString *) theString /*" Takes a string and escape any special character (like single quote : ') so that the string can be used directly in a query. "*/ { const char *theCStringBuffer = [self cStringFromString:theString]; unsigned int theLength = strlen(theCStringBuffer); char *theCEscBuffer = (char *)calloc(sizeof(char),(theLength * 2) + 1); NSString *theReturn; mysql_real_escape_string(mConnection, theCEscBuffer, theCStringBuffer, theLength); theReturn = [self stringWithCString:theCEscBuffer]; free (theCEscBuffer); return theReturn; } - (SMySQLResult *) queryString:(NSString *) query /*" Takes a query string and return an SMySQLResult object holding the result of the query. The returned SMySQLResult is not retained, the client is responsible for that (it's autoreleased before being returned) Note that if you want to use this method with binary data (in the query), you should use !{prepareBinaryData:} to include the binary data in the query string. "*/ { SMySQLResult *theResult = [SMySQLResult alloc]; const char *theCQuery = [self cStringFromString:query]; int theQueryCode; if ((theQueryCode = mysql_query(mConnection, theCQuery)) == NULL) { if (mysql_field_count(mConnection) != 0) { theResult = [theResult initWithMySQLPtr:mConnection encoding:mEncoding]; } else { // NSLog (@"Query worked but gives no output\n"); [theResult init]; } } else { NSLog (@"Problem in queryString error code is : %d, query is : %s -in ObjC : %@-\n", theQueryCode, theCQuery, query); theResult = [theResult init]; } if (theResult) { [theResult autorelease]; } return theResult; } - (my_ulonglong) affectedRows /*" Returns the number of affected rows by the last query. "*/ { if (mConnected) { return mysql_affected_rows(mConnection); } return 0; } - (my_ulonglong) insertId /*" If the last query was an insert in a table having a autoindex column, returns the id (autoindexed field) of the last row inserted. "*/ { if (mConnected) { return mysql_insert_id(mConnection); } return 0; } - (SMySQLResult *) listDBs /*" Just a fast wrapper for the more complex !{listDBsWithPattern:} method. "*/ { return [self listDBsLike:nil]; } - (SMySQLResult *) listDBsLike:(NSString *) dbsName /*" Returns a list of database which name correspond to the SQL regular expression in 'pattern'. The comparison is done with wild card extension : % and _. The result should correspond to the queryString:@"SHOW databases [LIKE wild]"; but implemented with mysql_list_dbs. If an empty string or nil is passed as pattern, all databases will be shown. "*/ { SMySQLResult *theResult = [SMySQLResult alloc]; MYSQL_RES *theResPtr; if ((dbsName == nil) || ([dbsName isEqualToString:@""])) { if (theResPtr = mysql_list_dbs(mConnection, NULL)) { [theResult initWithResPtr: theResPtr encoding: mEncoding]; } else { [theResult init]; } } else { const char *theCDBsName = (const char *)[[dbsName dataUsingEncoding: mEncoding allowLossyConversion: YES] bytes]; if (theResPtr = mysql_list_dbs(mConnection, theCDBsName)) { [theResult initWithResPtr: theResPtr encoding: mEncoding]; } else { [theResult init]; } } if (theResult) { [theResult autorelease]; } return theResult; } - (SMySQLResult *) listTables /*" Make sure a DB is selected (with !{selectDB} method) first. "*/ { return [self listTablesLike:nil]; } - (SMySQLResult *) listTablesLike:(NSString *) tablesName /*" From within a database, give back the list of table which name correspond to tablesName (with wild card %, _ extension). Correspond to queryString:@"SHOW tables [LIKE wild]"; uses mysql_list_tables function. If an empty string or nil is passed as tablesName, all tables will be shown. WARNING: #{produce an error if no databases are selected} (with !{selectDB:} for example). "*/ { SMySQLResult *theResult = [SMySQLResult alloc]; MYSQL_RES *theResPtr; if ((tablesName == nil) || ([tablesName isEqualToString:@""])) { if (theResPtr = mysql_list_tables(mConnection, NULL)) { [theResult initWithResPtr: theResPtr encoding: mEncoding]; } else { [theResult init]; } } else { const char *theCTablesName = (const char *)[[tablesName dataUsingEncoding: mEncoding allowLossyConversion: YES] bytes]; if (theResPtr = mysql_list_tables(mConnection, theCTablesName)) { [theResult initWithResPtr: theResPtr encoding: mEncoding]; } else { [theResult init]; } } if (theResult) { [theResult autorelease]; } return theResult; } - (SMySQLResult *) listTablesFromDB:(NSString *) dbName like:(NSString *) tablesName /*" List tables in DB specified by dbName and corresponding to pattern. This method indeed issues a !{SHOW TABLES FROM dbName LIKE ...} query to the server. This is done this way to make sure the selected DB is not changed by this method. "*/ { SMySQLResult *theResult; if ((tablesName == nil) || ([tablesName isEqualToString:@""])) { NSString *theQuery = [NSString stringWithFormat:@"SHOW TABLES FROM %@", dbName]; theResult = [self queryString:theQuery]; } else { NSString *theQuery = [NSString stringWithFormat:@"SHOW COLUMNS FROM %@ LIKE '%@'", dbName, tablesName]; theResult = [self queryString:theQuery]; } return theResult; } - (SMySQLResult *)listFieldsFromTable:(NSString *)tableName /*" Just a fast wrapper for the more complex list !{listFieldsWithPattern:forTable:} method. "*/ { return [self listFieldsFromTable:tableName like:nil]; } - (SMySQLResult *) listFieldsFromTable:(NSString *) tableName like:(NSString *) fieldsName /*" Show all the fields of the table tableName which name correspond to pattern (with wild card expansion : %,_). Indeed, and as recommanded from mysql reference, this method is NOT using mysql_list_fields but the !{queryString:} method. If an empty string or nil is passed as fieldsName, all fields (of tableName) will be returned. "*/ { SMySQLResult *theResult; if ((fieldsName == nil) || ([fieldsName isEqualToString:@""])) { NSString *theQuery = [NSString stringWithFormat:@"SHOW COLUMNS FROM %@", tableName]; theResult = [self queryString:theQuery]; } else { NSString *theQuery = [NSString stringWithFormat:@"SHOW COLUMNS FROM %@ LIKE '%@'", tableName, fieldsName]; theResult = [self queryString:theQuery]; } return theResult; } - (NSString *) clientInfo /*" Returns a string giving the client library version. "*/ { return [self stringWithCString:mysql_get_client_info()]; } - (NSString *) hostInfo /*" Returns a string giving information on the host of the DB server. "*/ { return [self stringWithCString:mysql_get_host_info(mConnection)]; } - (NSString *) serverInfo /*" Returns a string giving the server version. "*/ { if (mConnected) { return [self stringWithCString: mysql_get_server_info(mConnection)]; } return @""; } - (NSNumber *) protoInfo /*" Returns the number of the protocole used to transfer info from server to client "*/ { return [NSNumber numberWithUnsignedInt:mysql_get_proto_info(mConnection)]; } - (SMySQLResult *) listProcesses /*" Lists active process "*/ { SMySQLResult *theResult = [SMySQLResult alloc]; MYSQL_RES *theResPtr; if (theResPtr = mysql_list_processes(mConnection)) { [theResult initWithResPtr:theResPtr encoding:mEncoding]; } else { [theResult init]; } if (theResult) { [theResult autorelease]; } return theResult; } /* - (BOOL)createDBWithName:(NSString *)dbName { const char *theDBName = [dbName UTF8String]; if ((mConnected) && (! mysql_create_db(mConnection, theDBName))) { return YES; } return NO; } - (BOOL)dropDBWithName:(NSString *)dbName { const char *theDBName = [dbName UTF8String]; if ((mConnected) && (! mysql_drop_db(mConnection, theDBName))) { return YES; } return NO; } */ - (BOOL) killProcess:(unsigned long) pid /*" Kills the process with the given pid. The users needs the #{Process_priv} privilege. "*/ { int theErrorCode; theErrorCode = mysql_kill(mConnection, pid); return (theErrorCode) ? NO : YES; } - (void) disconnect /*" Disconnects a connected SMySQLConnection object; used by #{-dealloc} method. "*/ { if (mConnected) { mysql_close(mConnection); mConnection = NULL; } mConnected = NO; return; } - (void)dealloc /*" The standard deallocation method for SMySQLConnection objects. "*/ { [self disconnect]; [super dealloc]; return; } - (void) setEncoding:(NSStringEncoding) theEncoding /*" Sets the encoding used by the server for data transfert. Used to make sure the output of the query result is ok even for non-ascii characters The character set (encoding) used by the db is passed to the SMySQLConnection object upon connection, so most likely the encoding (from -encoding) method is already the proper one. That is to say : It's unlikely you will need to call this method directly, and #{if ever you use it, do it at your own risks}. "*/ { mEncoding = theEncoding; } - (NSStringEncoding) encoding /*" Gets the encoding for the connection "*/ { return mEncoding; } - (const char *) cStringFromString:(NSString *) theString /*" For internal use only. Transforms a NSString to a C type string (ending with \0) using the character set from the SMySQLConnection. Lossy conversions are enabled. "*/ { NSMutableData *theData; if (! theString) { return (const char *)NULL; } theData = [NSMutableData dataWithData:[theString dataUsingEncoding:mEncoding allowLossyConversion:YES]]; [theData increaseLengthBy:1]; return (const char *)[theData bytes]; } - (NSString *) stringWithCString:(const char *) theCString /*" Returns a NSString from a C style string encoded with the character set of theSMySQLConnection. "*/ { NSData * theData; NSString * theString; if (theCString == NULL) { return @""; } theData = [NSData dataWithBytes:theCString length:(strlen(theCString))]; theString = [[NSString alloc] initWithData:theData encoding:mEncoding]; if (theString) { [theString autorelease]; } return theString; } @end --- SMySQLConnection.m DELETED --- |