From: helge Date: Tue, 12 Apr 2005 21:54:49 +0000 (+0000) Subject: more work on MySQL fetching X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=97b760cc72ccf97b79ed3d59bd465b4d64a85eb9;p=sope more work on MySQL fetching git-svn-id: http://svn.opengroupware.org/SOPE/trunk@736 e4a50df8-12e2-0310-a44c-efbce7f8a7e3 --- diff --git a/sope-gdl1/MySQL4/ChangeLog b/sope-gdl1/MySQL4/ChangeLog index 399b05c2..81ae9e47 100644 --- a/sope-gdl1/MySQL4/ChangeLog +++ b/sope-gdl1/MySQL4/ChangeLog @@ -1,3 +1,7 @@ +2005-04-13 Helge Hess + + * MySQL4Channel.m: finished fetching code (v4.5.4) + 2005-04-12 Helge Hess * MySQL4Channel.m: added some fetch result processing (v4.5.3) diff --git a/sope-gdl1/MySQL4/MySQL4Channel.m b/sope-gdl1/MySQL4/MySQL4Channel.m index 7ae34626..5531aa38 100644 --- a/sope-gdl1/MySQL4/MySQL4Channel.m +++ b/sope-gdl1/MySQL4/MySQL4Channel.m @@ -417,38 +417,6 @@ static int openConnectionCount = 0; break; } -#if 1 -# warning IMPLEMENT ME -#else - switch (sqlite3_column_type(self->statement, cnt)) { - case SQLITE_INTEGER: - [attribute setExternalType:@"INTEGER"]; - [attribute setValueClassName:@"NSNumber"]; - [attribute setValueType:@"d"]; - break; - case SQLITE_FLOAT: - [attribute setExternalType:@"REAL"]; - [attribute setValueClassName:@"NSNumber"]; - [attribute setValueType:@"f"]; - break; - case SQLITE_TEXT: - [attribute setExternalType:@"TEXT"]; - [attribute setValueClassName:@"NSString"]; - break; - case SQLITE_BLOB: - [attribute setExternalType:@"BLOB"]; - [attribute setValueClassName:@"NSData"]; - break; - case SQLITE_NULL: - NSLog(@"WARNING(%s): got MySQL4 NULL type at column %i, can't derive " - @"type information.", - __PRETTY_FUNCTION__, cnt); - [attribute setExternalType:@"NULL"]; - [attribute setValueClassName:@"NSNull"]; - break; - default: - } -#endif [result addObject:attribute]; [attribute release]; } @@ -459,20 +427,6 @@ static int openConnectionCount = 0; return [result autorelease]; } -- (BOOL)isColumnNullInCurrentRow:(int)_column { - /* - Note: NULL is MySQL4 is represented as empty strings ..., don't know - what to do about that? - At least Sybase 10 doesn't support empty strings strings as well - and converts them to a single space. So maybe it is reasonable to - map empty strings to NSNull? - - Or is this column-type SQLITE_NULL? If so, thats rather weird, - since the type query does not take a row. - */ - return NO; -} - - (NSMutableDictionary *)primaryFetchAttributes:(NSArray *)_attributes withZone:(NSZone *)_zone { @@ -485,9 +439,9 @@ static int openConnectionCount = 0; // TODO: add a primaryFetchAttributesX method? MYSQL_ROW rawRow; NSMutableDictionary *row = nil; - NSException *error; unsigned attrCount = [_attributes count]; unsigned cnt; + unsigned long *lengths; if (self->results == NULL) { NSLog(@"ERROR(%s): no fetch in progress?", __PRETTY_FUNCTION__); @@ -511,20 +465,38 @@ static int openConnectionCount = 0; [self cancelFetch]; return nil; } + + /* ensure field info */ + + if ([self _fetchFields] == NULL) { + [self cancelFetch]; + [MySQL4Exception raise:@"FetchFailed" + format:@"could not fetch field info!"]; + return nil; + } + + if ((lengths = mysql_fetch_lengths(self->results)) == NULL) { + [self cancelFetch]; + [MySQL4Exception raise:@"FetchFailed" + format:@"could not fetch field lengths!"]; + return nil; + } /* build row */ row = [NSMutableDictionary dictionaryWithCapacity:attrCount]; - + for (cnt = 0; cnt < attrCount; cnt++) { EOAttribute *attribute; NSString *attrName; id value = nil; + MYSQL_FIELD mfield; attribute = [_attributes objectAtIndex:cnt]; attrName = [attribute name]; - - if ([self isColumnNullInCurrentRow:cnt]) { + mfield = ((MYSQL_FIELD *)self->fields)[cnt]; + + if (rawRow[cnt] == NULL) { value = [null retain]; } else { @@ -539,40 +511,9 @@ static int openConnectionCount = 0; value = null; continue; } - -#if 1 -# warning IMPLEMENT ME -#else - switch (sqlite3_column_type(self->statement, cnt)) { - case SQLITE_INTEGER: - value = [[valueClass alloc] - initWithMySQL4Int:sqlite3_column_int(self->statement, cnt)]; - break; - case SQLITE_FLOAT: - value = [[valueClass alloc] - initWithMySQL4Double: - sqlite3_column_double(self->statement, cnt)]; - break; - case SQLITE_TEXT: - value = [[valueClass alloc] - initWithMySQL4Text: - sqlite3_column_text(self->statement, cnt)]; - break; - case SQLITE_BLOB: - value = [[valueClass alloc] - initWithMySQL4Data: - sqlite3_column_blob(self->statement, cnt) - length:sqlite3_column_bytes(self->statement, cnt)]; - break; - case SQLITE_NULL: - value = [null retain]; - break; - default: - NSLog(@"ERROR(%s): unexpected MySQL4 type at column %i", - __PRETTY_FUNCTION__, cnt); - continue; - } -#endif + + value = [[valueClass alloc] initWithMySQL4Type:mfield.type + value:rawRow[cnt] length:lengths[cnt]]; if (value == nil) { NSLog(@"ERROR(%s): %@: got no value for column:\n" @@ -596,10 +537,8 @@ static int openConnectionCount = 0; - (NSException *)evaluateExpressionX:(NSString *)_expression { NSMutableString *sql; - NSException *error; BOOL result; const char *s; - const char *tails = NULL; int rc; *(&result) = YES; @@ -735,6 +674,8 @@ static int openConnectionCount = 0; seqName = [adaptor primaryKeySequenceName]; pkey = nil; seq = nil; + + NSLog(@"TODO(%s): implement primary keys for MySQL", __PRETTY_FUNCTION__); seq = ([seqName length] > 0) ? [NSString stringWithFormat:@"SELECT NEXTVAL ('%@')", seqName] diff --git a/sope-gdl1/MySQL4/MySQL4Values.h b/sope-gdl1/MySQL4/MySQL4Values.h index ba884e7b..44a0b467 100644 --- a/sope-gdl1/MySQL4/MySQL4Values.h +++ b/sope-gdl1/MySQL4/MySQL4Values.h @@ -54,10 +54,7 @@ @interface NSObject(MySQL4Values) -- (id)initWithMySQL4Int:(int)_value; -- (id)initWithMySQL4Text:(const unsigned char *)_value; -- (id)initWithMySQL4Double:(double)_value; -- (id)initWithMySQL4Data:(const void *)_data length:(int)_length; +- (id)initWithMySQL4Type:(int)_type value:(const void *)_v length:(int)_len; @end diff --git a/sope-gdl1/MySQL4/MySQL4Values.m b/sope-gdl1/MySQL4/MySQL4Values.m index 15a60008..5bf7dbb6 100644 --- a/sope-gdl1/MySQL4/MySQL4Values.m +++ b/sope-gdl1/MySQL4/MySQL4Values.m @@ -23,8 +23,8 @@ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#import "MySQL4Values.h" -#import "common.h" +#include "MySQL4Values.h" +#include "common.h" @implementation MySQL4DataTypeMappingException @@ -72,6 +72,16 @@ @implementation NSObject(MySQL4Values) +- (id)initWithMySQL4Type:(int)_type value:(const void *)_v length:(int)_len { + [self release]; + + NSLog(@"WARNING(%s): falling back to NSString for MySQL4 value!", + __PRETTY_FUNCTION__); + + return [[NSString alloc] initWithMySQL4Type:_type value:_v length:_len]; +} + +#if 0 - (id)initWithMySQL4Int:(int)_value { if ([self respondsToSelector:@selector(initWithInt:)]) return [(NSNumber *)self initWithInt:_value]; @@ -132,6 +142,7 @@ [self release]; return nil; } +#endif @end /* NSObject(MySQL4Values) */ diff --git a/sope-gdl1/MySQL4/NSCalendarDate+MySQL4Val.m b/sope-gdl1/MySQL4/NSCalendarDate+MySQL4Val.m index 3f078aed..674c62f0 100644 --- a/sope-gdl1/MySQL4/NSCalendarDate+MySQL4Val.m +++ b/sope-gdl1/MySQL4/NSCalendarDate+MySQL4Val.m @@ -24,7 +24,7 @@ */ -#import +#import #include "MySQL4Channel.h" #include "common.h" @@ -34,7 +34,7 @@ @end #endif -static NSString *SQLITE3_DATETIME_FORMAT = @"%b %d %Y %I:%M:%S:000%p"; +static NSString *MYSQL4_DATETIME_FORMAT = @"%b %d %Y %I:%M:%S:000%p"; @implementation NSCalendarDate(MySQL4Values) @@ -46,12 +46,41 @@ static NSString *SQLITE3_DATETIME_FORMAT = @"%b %d %Y %I:%M:%S:000%p"; Matthew: "07/25/2003 06:00:00 CDT". */ -static Class NSCalDateClass = Nil; static NSTimeZone *DefServerTimezone = nil; +#if 0 static NSTimeZone *gmt = nil; static NSTimeZone *gmt01 = nil; static NSTimeZone *gmt02 = nil; +#endif +- (id)initWithMySQL4Type:(int)_type value:(const void *)_v length:(int)_len { + NSString *s; + NSString *calfmt; + + s = [[NSString alloc] initWithCString:_v length:_len]; // Unicode + calfmt = nil; + + // TODO: avoid using format strings + + switch (_len) { // as suggested by SQLClient + case 14: calfmt = @"%Y%m%d%H%M%S"; break; + case 12: calfmt = @"%y%m%d%H%M%S"; break; + case 10: calfmt = @"%y%m%d%H%M"; break; + case 8: calfmt = @"%y%m%d%H"; break; + case 6: calfmt = @"%y%m%d"; break; + case 4: calfmt = @"%y%m"; break; + default: + calfmt = _len > 14 ? @"%Y-%m-%d %H:%M:%S" : @"%y"; + break; + } + + self = [self initWithString:s calendarFormat:calfmt]; + [s release]; + [self setCalendarFormat:MYSQL4_DATETIME_FORMAT]; + return self; +} + +#if 0 - (id)initWithMySQL4Data:(const void *)_value length:(int)_length { static unsigned char buf[28]; // reused buffer, THREAD const char *_cstr = _value; @@ -147,17 +176,7 @@ static NSTimeZone *gmt02 = nil; } return date; } - -- (id)initWithMySQL4Double:(double)_value { - return [self initWithTimeIntervalSince1970:_value]; -} -- (id)initWithMySQL4Int:(int)_value { - return [self initWithMySQL4Double:_value]; -} - -- (id)initWithMySQL4Text:(const unsigned char *)_value { - return [self initWithMySQL4Data:_value length:strlen(_value)]; -} +#endif /* generating value */ @@ -205,7 +224,7 @@ static NSTimeZone *gmt02 = nil; format = @"%Y-%m-%d %H:%M:%S%z"; #endif if (format == nil) - format = SQLITE3_DATETIME_FORMAT; + format = MYSQL4_DATETIME_FORMAT; [self setTimeZone:serverTimeZone]; diff --git a/sope-gdl1/MySQL4/NSNumber+MySQL4Val.m b/sope-gdl1/MySQL4/NSNumber+MySQL4Val.m index 9fdcdc87..71837017 100644 --- a/sope-gdl1/MySQL4/NSNumber+MySQL4Val.m +++ b/sope-gdl1/MySQL4/NSNumber+MySQL4Val.m @@ -23,12 +23,31 @@ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#import +#import #include "MySQL4Channel.h" #include "common.h" +#include @implementation NSNumber(MySQL4Values) - + +- (id)initWithMySQL4Type:(int)_type value:(const void *)_v length:(int)_len { + if (_v == NULL) { + [self release]; + return nil; + } + + switch (_type) { + case FIELD_TYPE_TINY: + // ??: SQLClient => v = [NSString stringWithFormat: @"%u", *p]; + ; /* fall through */ + default: + NSLog(@"ERROR: unsupported MySQL type: %i", _type); + [self release]; + return nil; + } +} + +#if 0 - (id)initWithMySQL4Int:(int)_value { return [self initWithInt:_value]; } @@ -52,6 +71,9 @@ [self release]; return nil; } +#endif + +/* generation */ - (NSString *)stringValueForMySQL4Type:(NSString *)_type attribute:(EOAttribute *)_attribute diff --git a/sope-gdl1/MySQL4/NSString+MySQL4Val.m b/sope-gdl1/MySQL4/NSString+MySQL4Val.m index 479713f7..47a56e07 100644 --- a/sope-gdl1/MySQL4/NSString+MySQL4Val.m +++ b/sope-gdl1/MySQL4/NSString+MySQL4Val.m @@ -27,11 +27,32 @@ #include #import #include "common.h" +#include @implementation NSString(MySQL4Values) static Class EOExprClass = Nil; +- (id)initWithMySQL4Type:(int)_type value:(const void *)_v length:(int)_len { + if (_v == NULL) { + [self release]; + return nil; + } + + switch (_type) { + case FIELD_TYPE_BLOB: + case FIELD_TYPE_TINY_BLOB: + case FIELD_TYPE_MEDIUM_BLOB: + case FIELD_TYPE_LONG_BLOB: + ; /* fall through */ + + default: + /* we always fallback to the UTF-8 string ... */ + return [self initWithUTF8String:_v]; + } +} + +#if 0 - (id)initWithMySQL4Int:(int)_value { char buf[256]; sprintf(buf, "%i", _value); @@ -55,6 +76,7 @@ static Class EOExprClass = Nil; [d release]; return self; } +#endif /* generate SQL value */ @@ -93,7 +115,7 @@ static Class EOExprClass = Nil; if (EOExprClass == Nil) EOExprClass = [EOQuotedExpression class]; expr = [[EOExprClass alloc] initWithExpression:expr quote:@"'" escape:@"\\'"]; - s = [[expr expressionValueForContext:nil] retain]; + s = [[(EOQuotedExpression *)expr expressionValueForContext:nil] retain]; [expr release]; return [s autorelease]; } diff --git a/sope-gdl1/MySQL4/Version b/sope-gdl1/MySQL4/Version index f7ead5f2..23e43c1d 100644 --- a/sope-gdl1/MySQL4/Version +++ b/sope-gdl1/MySQL4/Version @@ -1,3 +1,3 @@ # Version file -SUBMINOR_VERSION:=3 +SUBMINOR_VERSION:=4 diff --git a/sope-gdl1/SQLite3/SQLiteChannel.m b/sope-gdl1/SQLite3/SQLiteChannel.m index 179dc373..b77a05cd 100644 --- a/sope-gdl1/SQLite3/SQLiteChannel.m +++ b/sope-gdl1/SQLite3/SQLiteChannel.m @@ -361,7 +361,7 @@ static int openConnectionCount = 0; - (BOOL)isColumnNullInCurrentRow:(int)_column { /* - Note: NULL is SQLite is represented as empty strings ..., don't know + Note: NULL in SQLite is represented as empty strings ..., don't know what to do about that? At least Sybase 10 doesn't support empty strings strings as well and converts them to a single space. So maybe it is reasonable to