From 26e59fc686e284a85290352d2f70e815534eda08 Mon Sep 17 00:00:00 2001 From: helge Date: Tue, 12 Apr 2005 21:23:15 +0000 Subject: [PATCH] added some fetch support git-svn-id: http://svn.opengroupware.org/SOPE/trunk@735 e4a50df8-12e2-0310-a44c-efbce7f8a7e3 --- sope-gdl1/MySQL4/ChangeLog | 4 + sope-gdl1/MySQL4/MySQL4Channel.h | 11 +- sope-gdl1/MySQL4/MySQL4Channel.m | 248 +++++++++++++++++++------------ sope-gdl1/MySQL4/Version | 2 +- 4 files changed, 159 insertions(+), 106 deletions(-) diff --git a/sope-gdl1/MySQL4/ChangeLog b/sope-gdl1/MySQL4/ChangeLog index 0728516d..399b05c2 100644 --- a/sope-gdl1/MySQL4/ChangeLog +++ b/sope-gdl1/MySQL4/ChangeLog @@ -1,3 +1,7 @@ +2005-04-12 Helge Hess + + * MySQL4Channel.m: added some fetch result processing (v4.5.3) + 2005-04-12 Helge Hess * MySQL4Channel.m: implemented query (v4.5.2) diff --git a/sope-gdl1/MySQL4/MySQL4Channel.h b/sope-gdl1/MySQL4/MySQL4Channel.h index 93b8d0eb..1a8cebb6 100644 --- a/sope-gdl1/MySQL4/MySQL4Channel.h +++ b/sope-gdl1/MySQL4/MySQL4Channel.h @@ -34,15 +34,12 @@ { // connection is valid after an openChannel call void *_connection; - - // valid during -evaluateExpression: - BOOL hasPendingRow; - BOOL isDone; - - void *results; + void *results; + void *fields; + int fieldCount; + #if 0 int tupleCount; - int fieldCount; BOOL containsBinaryData; NSString *cmdStatus; NSString *cmdTuples; diff --git a/sope-gdl1/MySQL4/MySQL4Channel.m b/sope-gdl1/MySQL4/MySQL4Channel.m index 96fd9476..7ae34626 100644 --- a/sope-gdl1/MySQL4/MySQL4Channel.m +++ b/sope-gdl1/MySQL4/MySQL4Channel.m @@ -201,6 +201,9 @@ static int openConnectionCount = 0; } - (void)primaryCloseChannel { + if ([self isFetchInProgress]) + [self cancelFetch]; + if (self->_connection != NULL) { mysql_close(self->_connection); #if 0 @@ -225,66 +228,32 @@ static int openConnectionCount = 0; /* fetching rows */ -- (NSException *)_makeMySQL4Step { - NSString *r; - const char *em; - int rc; - -#if 1 -# warning IMPLEMENT ME -#else - rc = sqlite3_step(self->statement); -#endif -#if 0 - NSLog(@"STEP: %i (row=%i, done=%i, mis=%i)", rc, - SQLITE_ROW, SQLITE_DONE, SQLITE_MISUSE); -#endif - -#if 1 -# warning IMPLEMENT ME -#else - if (rc == SQLITE_ROW) { - self->hasPendingRow = YES; - self->isDone = NO; - return nil /* no error */; - } - if (rc == SQLITE_DONE) { - self->hasPendingRow = NO; - self->isDone = YES; - return nil /* no error */; - } - - if (rc == SQLITE_ERROR) - r = [NSString stringWithUTF8String:sqlite3_errmsg(self->_connection)]; - else if (rc == SQLITE_MISUSE) - r = @"The MySQL4 step function was called in an incorrect way"; - else if (rc == SQLITE_BUSY) - r = @"The MySQL4 is busy."; - else - r = [NSString stringWithFormat:@"Unexpected MySQL4 error: %i", rc]; - - if ((em = sqlite3_errmsg(self->_connection)) != NULL) - r = [r stringByAppendingFormat:@": %s", em]; -#endif - - return [MySQL4Exception exceptionWithName:@"FetchFailed" - reason:r userInfo:nil]; -} - - (void)cancelFetch { + self->fields = NULL; /* apparently we do not need to free those */ + if (self->results != NULL) { mysql_free_result(self->results); self->results = NULL; } - - self->isDone = NO; - self->hasPendingRow = NO; [super cancelFetch]; } +- (MYSQL_FIELD *)_fetchFields { + if (self->results == NULL) + return NULL; + + if (self->fields != NULL) + return self->fields; + + self->fields = mysql_fetch_fields(self->results); + self->fieldCount = mysql_num_fields(self->results); + return self->fields; +} + - (NSArray *)describeResults { // TODO: make exception-less method - int cnt, fieldCount; + MYSQL_FIELD *mfields; + int cnt; NSMutableArray *result = nil; NSMutableDictionary *usedNames = nil; NSNumber *yesObj; @@ -294,29 +263,14 @@ static int openConnectionCount = 0; if (![self isFetchInProgress]) { [MySQL4Exception raise:@"NoFetchInProgress" format:@"No fetch in progress (channel=%@)", self]; - } - - /* we need to fetch a row to get the info */ - - if (!self->hasPendingRow) { - NSException *error; - - if ((error = [self _makeMySQL4Step]) != nil) { - [self cancelFetch]; - [error raise]; // raise error, TODO: make exception-less method - return nil; - } - } - if (!self->hasPendingRow) /* no rows available */ return nil; + } -#if 1 -# warning IMPLEMENT ME -#else - fieldCount = sqlite3_column_count(self->statement); -#endif - - /* old code below */ + if ((mfields = [self _fetchFields]) == NULL) { + [MySQL4Exception raise:@"NoFieldInfo" + format:@"Failed to fetch field info (channel=%@)", self]; + return nil; + } result = [[NSMutableArray alloc] initWithCapacity:fieldCount]; usedNames = [[NSMutableDictionary alloc] initWithCapacity:fieldCount]; @@ -326,12 +280,7 @@ static int openConnectionCount = 0; NSString *columnName = nil; NSString *attrName = nil; -#if 1 -# warning IMPLEMENT ME -#else - columnName = [NSString stringWithCString: - sqlite3_column_name(self->statement, cnt)]; -#endif + columnName = [NSString stringWithUTF8String:mfields[cnt].name]; attrName = [columnName _mySQL4ModelMakeInstanceVarName]; if ([[usedNames objectForKey:attrName] boolValue]) { @@ -360,6 +309,114 @@ static int openConnectionCount = 0; [attribute setName:attrName]; [attribute setColumnName:columnName]; + [attribute setAllowsNull: + (mfields[cnt].flags & NOT_NULL_FLAG) ? NO : YES]; + + /* + We also know whether a field: + is primary + is unique + is auto-increment + is zero-fill + is unsigned + */ + if (mfields[cnt].flags & UNSIGNED_FLAG) { + NSLog(@"ERROR: MySQL4 field is marked unsigned (unsupported): %@", + attribute); + } + + switch (mfields[cnt].type) { + case FIELD_TYPE_STRING: + [attribute setExternalType:@"CHAR"]; + [attribute setValueClassName:@"NSString"]; + // TODO: length etc + break; + case FIELD_TYPE_VAR_STRING: + [attribute setExternalType:@"VARCHAR"]; + [attribute setValueClassName:@"NSString"]; + // TODO: length etc + break; + + case FIELD_TYPE_TINY: + [attribute setExternalType:@"TINY"]; + [attribute setValueClassName:@"NSNumber"]; + [attribute setValueType:@"c"]; + break; + case FIELD_TYPE_SHORT: + [attribute setExternalType:@"SHORT"]; + [attribute setValueClassName:@"NSNumber"]; + [attribute setValueType:@"s"]; + break; + case FIELD_TYPE_LONG: + [attribute setExternalType:@"LONG"]; + [attribute setValueClassName:@"NSNumber"]; + [attribute setValueType:@"l"]; + break; + case FIELD_TYPE_INT24: + [attribute setExternalType:@"INT"]; + [attribute setValueClassName:@"NSNumber"]; + [attribute setValueType:@"i"]; // bumped + break; + case FIELD_TYPE_LONGLONG: + [attribute setExternalType:@"LONGLONG"]; + [attribute setValueClassName:@"NSNumber"]; + [attribute setValueType:@"q"]; + break; + case FIELD_TYPE_DECIMAL: + [attribute setExternalType:@"DECIMAL"]; + [attribute setValueClassName:@"NSNumber"]; + [attribute setValueType:@"f"]; // TODO: need NSDecimalNumber here ... + break; + case FIELD_TYPE_FLOAT: + [attribute setExternalType:@"FLOAT"]; + [attribute setValueClassName:@"NSNumber"]; + [attribute setValueType:@"f"]; + break; + case FIELD_TYPE_DOUBLE: + [attribute setExternalType:@"DOUBLE"]; + [attribute setValueClassName:@"NSNumber"]; + [attribute setValueType:@"d"]; + break; + + case FIELD_TYPE_TIMESTAMP: + [attribute setExternalType:@"TIMESTAMP"]; + [attribute setValueClassName:@"NSCalendarDate"]; + break; + case FIELD_TYPE_DATE: + [attribute setExternalType:@"DATE"]; + [attribute setValueClassName:@"NSCalendarDate"]; + break; + case FIELD_TYPE_DATETIME: + [attribute setExternalType:@"DATETIME"]; + [attribute setValueClassName:@"NSCalendarDate"]; + break; + + case FIELD_TYPE_BLOB: + case FIELD_TYPE_TINY_BLOB: + case FIELD_TYPE_MEDIUM_BLOB: + case FIELD_TYPE_LONG_BLOB: + // TODO: length etc + if (mfields[cnt].flags & BINARY_FLAG) { + [attribute setExternalType:@"BLOB"]; + [attribute setValueClassName:@"NSData"]; + } + else { + [attribute setExternalType:@"TEXT"]; + [attribute setValueClassName:@"NSString"]; + } + break; + + case FIELD_TYPE_NULL: // TODO: whats that? + case FIELD_TYPE_TIME: + case FIELD_TYPE_YEAR: + case FIELD_TYPE_SET: + case FIELD_TYPE_ENUM: + default: + NSLog(@"ERROR(%s): unexpected MySQL4 type at column %i: %@", + __PRETTY_FUNCTION__, cnt, attribute); + break; + } + #if 1 # warning IMPLEMENT ME #else @@ -390,9 +447,6 @@ static int openConnectionCount = 0; [attribute setValueClassName:@"NSNull"]; break; default: - NSLog(@"ERROR(%s): unexpected MySQL4 type at column %i", - __PRETTY_FUNCTION__, cnt); - break; } #endif [result addObject:attribute]; @@ -429,33 +483,35 @@ static int openConnectionCount = 0; schema) */ // TODO: add a primaryFetchAttributesX method? + MYSQL_ROW rawRow; NSMutableDictionary *row = nil; NSException *error; unsigned attrCount = [_attributes count]; unsigned cnt; - -#if 0 - if (self->statement == NULL) { - NSLog(@"ERROR: no fetch in progress?"); + + if (self->results == NULL) { + NSLog(@"ERROR(%s): no fetch in progress?", __PRETTY_FUNCTION__); [self cancelFetch]; return nil; } -#endif + + /* raw fetch */ - if (!self->hasPendingRow && !self->isDone) { - if ((error = [self _makeMySQL4Step]) != nil) { - [self cancelFetch]; - [error raise]; // raise error, TODO: make exception-less method + if ((rawRow = mysql_fetch_row(self->results)) == NULL) { + // TODO: might need to close channel on connect exceptions + const char *error; + + if ((error = mysql_error(self->_connection)) != NULL) { + [MySQL4Exception raise:@"FetchFailed" + format:@"%@",[NSString stringWithUTF8String:error]]; return nil; } - } - if (self->isDone) { /* step was fine, but we are at the end */ + + /* regular end of result set */ [self cancelFetch]; return nil; } - self->hasPendingRow = NO; /* consume the row */ - /* build row */ row = [NSMutableDictionary dictionaryWithCapacity:attrCount]; @@ -580,14 +636,12 @@ static int openConnectionCount = 0; reason:@"MySQL4 connection is not open" userInfo:nil]; } -#if 0 - if (self->statement != NULL) { + if (self->results != NULL) { return [MySQL4Exception exceptionWithName:@"CommandInProgressException" reason:@"an evaluation is in progress" userInfo:nil]; return NO; } -#endif if ([self isFetchInProgress]) { NSLog(@"WARNING: a fetch is still in progress: %@", self); @@ -600,8 +654,6 @@ static int openConnectionCount = 0; /* reset environment */ self->isFetchInProgress = NO; - self->isDone = NO; - self->hasPendingRow = NO; /* start query */ diff --git a/sope-gdl1/MySQL4/Version b/sope-gdl1/MySQL4/Version index 648edbe2..f7ead5f2 100644 --- a/sope-gdl1/MySQL4/Version +++ b/sope-gdl1/MySQL4/Version @@ -1,3 +1,3 @@ # Version file -SUBMINOR_VERSION:=2 +SUBMINOR_VERSION:=3 -- 2.39.5