+2005-04-13 Helge Hess <helge.hess@opengroupware.org>
+
+ * MySQL4Channel.m: finished fetching code (v4.5.4)
+
2005-04-12 Helge Hess <helge.hess@opengroupware.org>
* MySQL4Channel.m: added some fetch result processing (v4.5.3)
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];
}
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
{
// 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__);
[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 {
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"
- (NSException *)evaluateExpressionX:(NSString *)_expression {
NSMutableString *sql;
- NSException *error;
BOOL result;
const char *s;
- const char *tails = NULL;
int rc;
*(&result) = YES;
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]
@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
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#import "MySQL4Values.h"
-#import "common.h"
+#include "MySQL4Values.h"
+#include "common.h"
@implementation MySQL4DataTypeMappingException
@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];
[self release];
return nil;
}
+#endif
@end /* NSObject(MySQL4Values) */
*/
-#import <Foundation/NSString.h>
+#import <Foundation/NSCalendarDate.h>
#include "MySQL4Channel.h"
#include "common.h"
@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)
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;
}
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 */
format = @"%Y-%m-%d %H:%M:%S%z";
#endif
if (format == nil)
- format = SQLITE3_DATETIME_FORMAT;
+ format = MYSQL4_DATETIME_FORMAT;
[self setTimeZone:serverTimeZone];
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#import <Foundation/NSString.h>
+#import <Foundation/NSValue.h>
#include "MySQL4Channel.h"
#include "common.h"
+#include <mysql/mysql.h>
@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];
}
[self release];
return nil;
}
+#endif
+
+/* generation */
- (NSString *)stringValueForMySQL4Type:(NSString *)_type
attribute:(EOAttribute *)_attribute
#include <NGExtensions/NSString+Ext.h>
#import <Foundation/NSString.h>
#include "common.h"
+#include <mysql/mysql.h>
@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);
[d release];
return self;
}
+#endif
/* generate SQL value */
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];
}
# Version file
-SUBMINOR_VERSION:=3
+SUBMINOR_VERSION:=4
- (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