4 Copyright (C) 1999 MDlink online service center GmbH and Helge Hess
6 Author: Helge Hess (helge.hess@mdlink.de)
8 This file is part of the FB Adaptor Library
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Library General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Library General Public License for more details.
20 You should have received a copy of the GNU Library General Public
21 License along with this library; see the file COPYING.LIB.
22 If not, write to the Free Software Foundation,
23 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 // $Id: FBValues.m 1 2004-08-20 10:38:46Z znek $
33 #include "FBException.h"
34 #import <Foundation/NSDate.h>
36 static Class NumberClass = Nil;
38 @interface FBDataTypeMappingException : FrontBaseException
41 @interface NSTimeZone(UsedPrivates)
42 - (NSTimeZoneDetail *)timeZoneDetailForDate:(NSDate *)_date;
45 @implementation FBDataTypeMappingException
47 - (id)initWithObject:(id)_obj forAttribute:(EOAttribute *)_attr
48 andFrontBaseType:(int)_fb inChannel:(FrontBaseChannel *)_channel
50 NSString *typeName = nil;
53 [(id)[[_channel adaptorContext] adaptor] externalNameForTypeCode:_fb];
56 typeName = [NSString stringWithFormat:@"Type[%i]", _fb];
58 [self setName:@"FBDataTypeMappingNotSupported"];
59 [self setReason:[NSString stringWithFormat:
60 @"mapping between %@<Class:%@> and "
61 @"frontbase type %@ is not supported",
63 NSStringFromClass([_obj class]),
66 [self setUserInfo:[NSDictionary dictionaryWithObjectsAndKeys:
74 @end /* FBDataTypeMappingException */
76 static inline void FmtRaiseMapExc(id _object,
78 EOAttribute *_attribute,
80 NSLog(@"%s: FmtRaiseMapExc objectClass=%@ object=%@ "
81 @"type=%i typeName=%@ attribute=%@",
83 NSStringFromClass([_object class]),
86 [(id)[[_channel adaptorContext] adaptor] externalNameForTypeCode:_fb],
89 [[[FBDataTypeMappingException alloc]
90 initWithObject:_object
91 forAttribute:_attribute
93 inChannel:_channel] raise];
95 static inline void RaiseMapExc(id _object, int _type,
96 EOAttribute *_attribute,
98 NSLog(@"%s: RaiseMapExc objectClass=%@ object=%@ type=%i name=%@ attribute=%@",
100 NSStringFromClass([_object class]),
103 [(id)[[_channel adaptorContext] adaptor] externalNameForTypeCode:_type],
106 [[[FBDataTypeMappingException alloc]
107 initWithObject:_object
108 forAttribute:_attribute
109 andFrontBaseType:_type
110 inChannel:_channel] raise];
113 @implementation NSString(FBValues)
115 + (id)valueFromBytes:(const char *)_bytes length:(unsigned)_length
116 frontBaseType:(int)_fb attribute:(EOAttribute *)_attribute
117 adaptorChannel:(FrontBaseChannel *)_channel
124 result = [self stringWithCString:_bytes length:_length];
129 result = [self stringWithCString:_bytes length:_length];
132 case FB_SmallInteger:
133 result = [NSString stringWithFormat:@"%i", *(short *)_bytes];
136 result = [NSString stringWithFormat:@"%i", *(int *)_bytes];
141 result = [NSString stringWithFormat:@"%g", *(double *)_bytes];
145 result = [NSString stringWithFormat:@"%g", *(float *)_bytes];
149 FmtRaiseMapExc(self, _fb, _attribute, _channel);
155 - (NSData *)dataValueForFrontBaseType:(int)_type
156 attribute:(EOAttribute *)_attribute
159 return [NSData dataWithBytes:[self cString] length:[self cStringLength]];
162 - (NSString *)stringValueForFrontBaseType:(int)_type
163 attribute:(EOAttribute *)_attribute
168 return [[NSData dataWithBytes:[self cString] length:[self cStringLength]]
169 stringValueForFrontBaseType:_type attribute:_attribute];
176 expr = [[[EOQuotedExpression alloc] initWithExpression:self
177 quote:@"'" escape:@"''"]
179 expr = [expr expressionValueForContext:nil];
184 case FB_SmallInteger:
190 /* NSLog(@"returning %@ for number type", self); */
194 RaiseMapExc(self, _type, _attribute, nil);
196 NSLog(@"impossible condition reached: %@", self);
201 @end /* NSString(FBValues) */
203 @implementation NSNumber(FBValues)
205 #define ReturnNumber(sybtype, def) {\
206 if (valueType == -1) \
207 return [NumberClass def *(sybtype*)_bytes]; \
208 else if (valueType == 'c') \
209 return [NumberClass numberWithChar:*(sybtype*)_bytes]; \
210 else if (valueType == 'C') \
211 return [NumberClass numberWithUnsignedChar:*(sybtype*)_bytes]; \
212 else if (valueType == 's') \
213 return [NumberClass numberWithShort:*(sybtype*)_bytes]; \
214 else if (valueType == 'S') \
215 return [NumberClass numberWithUnsignedShort:*(sybtype*)_bytes]; \
216 else if (valueType == 'i') \
217 return [NumberClass numberWithInt:*(sybtype*)_bytes]; \
218 else if (valueType == 'I') \
219 return [NumberClass numberWithUnsignedInt:*(sybtype*)_bytes]; \
220 else if (valueType == 'f') \
221 return [NumberClass numberWithFloat:*(sybtype*)_bytes]; \
222 else if (valueType == 'd') \
223 return [NumberClass numberWithDouble:*(sybtype*)_bytes]; \
225 [NSException raise:@"InvalidValueTypeException" \
226 format:@"value type %c is not recognized", valueType];\
230 + (id)valueFromBytes:(const char *)_bytes length:(unsigned)_length
231 frontBaseType:(int)_fb attribute:(EOAttribute *)_attribute
232 adaptorChannel:(FrontBaseChannel *)_channel
236 if ([_attribute valueType])
237 valueType = [[_attribute valueType] cString][0];
243 case FB_VCharacter: {
245 case 'c': return [NumberClass numberWithChar:atoi(_bytes)];
246 case 'C': return [NumberClass numberWithUnsignedChar:atol(_bytes)];
247 case 's': return [NumberClass numberWithShort:atoi(_bytes)];
248 case 'S': return [NumberClass numberWithUnsignedShort:atol(_bytes)];
249 case 'i': return [NumberClass numberWithInt:atoi(_bytes)];
250 case 'I': return [NumberClass numberWithUnsignedInt:atol(_bytes)];
251 case 'f': return [NumberClass numberWithFloat:atof(_bytes)];
252 case 'd': return [NumberClass numberWithDouble:atof(_bytes)];
254 [NSException raise:@"InvalidValueTypeException"
255 format:@"value type %c is not recognized",
263 v = *(unsigned char *)_bytes;
264 return [NumberClass numberWithBool:v];
270 return [NumberClass numberWithInt:v];
272 case FB_SmallInteger: {
274 v = *(short *)_bytes;
275 return [NumberClass numberWithShort:v];
280 ReturnNumber(double, numberWithDouble:);
283 ReturnNumber(float, numberWithFloat:);
288 if (_fmt->scale > 0) {
289 ReturnNumber(CS_REAL, numberWithDouble:);
292 ReturnNumber(int, numberWithInt:);
295 ReturnNumber(double, numberWithDouble:);
298 FmtRaiseMapExc(self, _fb, _attribute, _channel);
301 [NSException raise:@"InvalidFrontBaseValueStateException"
302 format:@"reached invalid state in sybase NSNumber handler"];
309 - (NSData *)dataValueForFrontBaseType:(int)_type
310 attribute:(EOAttribute *)_attribute
312 RaiseMapExc(self, _type, _attribute, nil);
316 - (NSString *)stringValueForFrontBaseType:(int)_type
317 attribute:(EOAttribute *)_attribute
323 case FB_SmallInteger:
329 return [self stringValue];
333 return [NSString stringWithFormat:@"'%s'", [[self stringValue] cString]];
336 RaiseMapExc(self, _type, _attribute, nil);
341 @end /* NSNumber(FBValues) */
343 @implementation NSData(FBValues)
345 + (id)valueFromBytes:(const char *)_bytes length:(unsigned)_length
346 frontBaseType:(int)_fb attribute:(EOAttribute *)_attribute
347 adaptorChannel:(FrontBaseChannel *)_channel
351 case FB_SmallInteger:
361 return [[[self alloc] initWithBytes:_bytes length:_length] autorelease];
364 FmtRaiseMapExc(self, _fb, _attribute, _channel);
369 - (NSData *)dataValueForFrontBaseType:(int)_type
370 attribute:(EOAttribute *)_attribute
375 - (NSString *)stringValueForFrontBaseType:(int)_type
376 attribute:(EOAttribute *)_attribute
380 return [[NumberClass numberWithChar:*(char *)[self bytes]] stringValue];
382 case FB_SmallInteger:
383 return [[NumberClass numberWithShort:*(short *)[self bytes]] stringValue];
386 return [[NumberClass numberWithInt:*(int *)[self bytes]] stringValue];
390 return [[NumberClass numberWithDouble:*(double *)[self bytes]]
394 return [[NumberClass numberWithFloat:*(float *)[self bytes]] stringValue];
400 unsigned final_length = [self length];
401 char *cstr = NULL, *tmp = NULL;
403 const char *iBytes = [self bytes];
405 if (final_length == 0) return @"NULL";
407 final_length = 2 + 2 * final_length + 1;
408 cstr = objc_atomic_malloc(final_length + 4);
414 for (cnt = 0; cnt < [self length]; cnt++, tmp += 2)
415 sprintf(tmp, "%02X", (unsigned char)iBytes[cnt]);
418 return [[[NSString alloc] initWithCStringNoCopy:cstr length:cstr?strlen(cstr):0 freeWhenDone:YES] autorelease];
422 RaiseMapExc(self, _type, _attribute, nil);
427 @end /* NSData(FBValues) */
429 // 1234567890123456789012345
430 // Frontbase Date: 1997-10-21 21:52:26+08:00
431 static NSString *FRONTBASE_DATE_FORMAT = @"%Y-%m-%d %H:%M:%S%z";
433 @implementation NSDate(FBValues)
435 + (id)valueFromBytes:(const char *)_bytes length:(unsigned)_length
436 frontBaseType:(int)_fb attribute:(EOAttribute *)_attribute
437 adaptorChannel:(FrontBaseChannel *)_channel
440 return [NSCalendarDate valueFromBytes:_bytes length:_length
441 frontBaseType:_fb attribute:_attribute
442 adaptorChannel:_channel];
445 - (NSData *)dataValueForFrontBaseType:(int)_type
446 attribute:(EOAttribute *)_attr
449 NSCalendarDate *cdate;
451 cdate = [NSCalendarDate dateWithTimeIntervalSince1970:
452 [self timeIntervalSince1970]];
454 return [cdate dataValueForFrontBaseType:_type attribute:_attr];
457 - (NSString *)stringValueForFrontBaseType:(int)_type
458 attribute:(EOAttribute *)_attr
461 NSCalendarDate *cdate;
463 cdate = [NSCalendarDate dateWithTimeIntervalSince1970:
464 [self timeIntervalSince1970]];
466 return [cdate stringValueForFrontBaseType:_type attribute:_attr];
471 @implementation NSCalendarDate(FBValues)
473 + (id)valueFromBytes:(const char *)_bytes length:(unsigned)_length
474 frontBaseType:(int)_fb attribute:(EOAttribute *)_attribute
475 adaptorChannel:(FrontBaseChannel *)_channel
479 case FB_TimestampTZ: {
480 /* a string of length 25 */
481 NSCalendarDate *date;
482 NSString *str, *stampstr, *tzstr;
485 NSAssert2(_length >= 25,
486 @"byte values for date creation are too short "
487 @"(len required is 25, got %i), attribute=%@",
488 _length, _attribute);
491 NSLog(@"WARNING: invalid length, should be '25', got %i, attribute %@",
492 _length, _attribute);
496 stampstr = [NSString stringWithCString:_bytes length:19];
497 tzstr = [NSString stringWithCString:(_bytes + 19) length:3];
498 str = [NSString stringWithCString:(_bytes + 23) length:2];
499 tzstr = [tzstr stringByAppendingString:str];
500 str = [stampstr stringByAppendingString:tzstr];
502 date = [NSCalendarDate dateWithString:str
503 calendarFormat:FRONTBASE_DATE_FORMAT];
506 NSLog(@"ERROR: couldn't construct calendar date from "
507 @"string %@ (src=%@) column %@.%@ "
508 @"(%i bytes), format=%@",
509 str, [NSString stringWithCString:_bytes length:19],
510 [[_attribute entity] externalName],
511 [_attribute columnName],
516 NSLog(@"info: could construct calendar date from string %@ (len=%i)",
528 NSTimeZone *serverTimeZone;
529 NSCalendarDate *date;
530 NSString *formattedDate;
533 formattedDate = [NSString stringWithCString:_bytes length:_length];
535 serverTimeZone = [_attribute serverTimeZone];
536 format = [_attribute calendarFormat];
538 if (serverTimeZone == nil)
539 serverTimeZone = [NSTimeZone localTimeZone];
541 format = FRONTBASE_DATE_FORMAT;
543 date = [NSCalendarDate dateWithString:formattedDate
544 calendarFormat:format];
546 NSLog(@"ERROR(%s): could not construct date from "
547 @"value '%@' with format '%@'",
548 __PRETTY_FUNCTION__, formattedDate, format);
554 FmtRaiseMapExc(self, _fb, _attribute, _channel);
559 - (NSData *)dataValueForFrontBaseType:(int)_type
560 attribute:(EOAttribute *)_attr
563 RaiseMapExc(self, _type, _attr, nil);
567 - (NSString *)stringValueForFrontBaseType:(int)_type
568 attribute:(EOAttribute *)_attr
572 self = [self copy]; /* copy to rescue timezone setting */
576 case FB_TimestampTZ: {
577 NSTimeZone *serverTimeZone;
579 NSTimeInterval timeZoneOffset;
582 serverTimeZone = [_attr serverTimeZone];
584 if (serverTimeZone == nil)
585 serverTimeZone = [NSTimeZone localTimeZone];
587 #if NeXT_Foundation_LIBRARY
588 timeZoneOffset = [serverTimeZone secondsFromGMTForDate:self];
590 timeZoneOffset = [[serverTimeZone timeZoneDetailForDate:self]
591 timeZoneSecondsFromGMT];
594 [self setTimeZone:serverTimeZone];
596 i = timeZoneOffset > 0;
597 j = (timeZoneOffset > 0 ? timeZoneOffset : -timeZoneOffset) / 60;
599 str = [NSString stringWithFormat:
600 @"TIMESTAMP '%02i-%02i-%02i %02i:%02i:%02i%s%02i:%02i'",
601 [self yearOfCommonEra],
606 [self secondOfMinute],
613 NSTimeZone *serverTimeZone;
617 serverTimeZone = [_attr serverTimeZone];
618 format = [_attr calendarFormat];
621 if (serverTimeZone == nil)
622 serverTimeZone = [NSTimeZone localTimeZone];
625 format = FRONTBASE_DATE_FORMAT;
627 [self setTimeZone:serverTimeZone];
629 expr = [self descriptionWithCalendarFormat:format];
630 expr = [[EOQuotedExpression alloc] initWithExpression:expr
631 quote:@"'" escape:@"''"];
633 expr = [expr expressionValueForContext:nil];
634 expr = [@"TIMESTAMP " stringByAppendingString:expr];
640 RaiseMapExc(self, _type, _attr, nil);
645 @end /* NSCalendarDate(FBValues) */
647 @implementation EONull(FBValues)
649 - (NSData *)dataValueForFrontBaseType:(int)_type
650 attribute:(EOAttribute *)_attr
655 - (NSString *)stringValueForFrontBaseType:(int)_type
656 attribute:(EOAttribute *)_attr
661 @end /* EONull(FBValues) */
663 void __init_FBValues(void) {
664 NumberClass = [NSNumber class];
667 void __link_FBValues() {
668 // used to force linking of object file