From 82a0a113aab3eabc90592723e4770baa99861c9a Mon Sep 17 00:00:00 2001 From: stuconnolly Date: Sat, 8 Sep 2012 08:57:46 +0000 Subject: Rework data type handling. --- .../Source/FLXPostgresConnectionTypeHandling.h | 1 + Frameworks/PostgresKit/Source/FLXPostgresResult.m | 24 ++-- .../Source/FLXPostgresTypeDateTimeHandler.h | 5 - .../Source/FLXPostgresTypeDateTimeHandler.m | 147 +++++++++------------ .../Source/FLXPostgresTypeHandlerProtocol.h | 12 +- .../Source/FLXPostgresTypeNumberHandler.h | 4 - .../Source/FLXPostgresTypeNumberHandler.m | 100 +++++++------- .../Source/FLXPostgresTypeStringHandler.m | 8 +- 8 files changed, 137 insertions(+), 164 deletions(-) (limited to 'Frameworks') diff --git a/Frameworks/PostgresKit/Source/FLXPostgresConnectionTypeHandling.h b/Frameworks/PostgresKit/Source/FLXPostgresConnectionTypeHandling.h index 351b1d24..6567cd0b 100644 --- a/Frameworks/PostgresKit/Source/FLXPostgresConnectionTypeHandling.h +++ b/Frameworks/PostgresKit/Source/FLXPostgresConnectionTypeHandling.h @@ -20,6 +20,7 @@ // the License. #import "FLXPostgresConnection.h" +#import "FLXPostgresTypeHandlerProtocol.h" @interface FLXPostgresConnection (FLXPostgresConnectionTypeHandling) diff --git a/Frameworks/PostgresKit/Source/FLXPostgresResult.m b/Frameworks/PostgresKit/Source/FLXPostgresResult.m index 1aaeb1de..3cb44252 100644 --- a/Frameworks/PostgresKit/Source/FLXPostgresResult.m +++ b/Frameworks/PostgresKit/Source/FLXPostgresResult.m @@ -30,8 +30,8 @@ static NSString *FLXPostgresResultError = @"FLXPostgresResultError"; @interface FLXPostgresResult () - (void)_populateFields; -- (id)_objectForRow:(unsigned int)row column:(unsigned int)column; -- (id )_typeHandlerForColumn:(unsigned int)column withType:(FLXPostgresOid)type; +- (id)_objectForRow:(NSUInteger)row column:(NSUInteger)column; +- (id )_typeHandlerForColumn:(NSUInteger)column withType:(FLXPostgresOid)type; @end @@ -64,10 +64,8 @@ static NSString *FLXPostgresResultError = @"FLXPostgresResultError"; * * @return The result wrapper. */ -- (id)initWithResult:(PGresult *)result connection:(FLXPostgresConnection *)connection -{ - NSParameterAssert(result); - +- (id)initWithResult:(void *)result connection:(FLXPostgresConnection *)connection +{ if ((self = [super init])) { _row = 0; @@ -196,17 +194,14 @@ static NSString *FLXPostgresResultError = @"FLXPostgresResultError"; * * @return The native object or nil if out of this result's range. */ -- (id)_objectForRow:(unsigned int)row column:(unsigned int)column +- (id)_objectForRow:(NSUInteger)row column:(NSUInteger)column { if (row >= _numberOfRows || column >= _numberOfFields) return nil; // Check for null if (PQgetisnull(_result, row, column)) return [NSNull null]; - // Get bytes and length FLXPostgresOid type = PQftype(_result, column); - const void *bytes = PQgetvalue(_result, row, column); - NSUInteger length = PQgetlength(_result, row, column); // Get handler for this type id handler = [self _typeHandlerForColumn:column withType:type]; @@ -214,10 +209,15 @@ static NSString *FLXPostgresResultError = @"FLXPostgresResultError"; if (!handler) { NSLog(@"PostgresKit: Warning: No type handler found for type %d, return NSData.", type); + const void *bytes = PQgetvalue(_result, row, column); + NSUInteger length = PQgetlength(_result, row, column); + + if (!bytes || !length) return nil; + return [NSData dataWithBytes:bytes length:length]; } - return [handler objectFromRemoteData:bytes length:length type:type]; + return [handler objectFromResult:_result atRow:row column:column]; } /** @@ -227,7 +227,7 @@ static NSString *FLXPostgresResultError = @"FLXPostgresResultError"; * * @return The type handler or nil if out of this result's range. */ -- (id )_typeHandlerForColumn:(unsigned int)column withType:(FLXPostgresOid)type +- (id )_typeHandlerForColumn:(NSUInteger)column withType:(FLXPostgresOid)type { if (column >= _numberOfFields) return nil; diff --git a/Frameworks/PostgresKit/Source/FLXPostgresTypeDateTimeHandler.h b/Frameworks/PostgresKit/Source/FLXPostgresTypeDateTimeHandler.h index b83eba76..4b148bbc 100644 --- a/Frameworks/PostgresKit/Source/FLXPostgresTypeDateTimeHandler.h +++ b/Frameworks/PostgresKit/Source/FLXPostgresTypeDateTimeHandler.h @@ -20,13 +20,8 @@ // License for the specific language governing permissions and limitations under // the License. -@class FLXPostgresTypeNumberHandler; - #import "FLXPostgresTypeHandler.h" @interface FLXPostgresTypeDateTimeHandler : FLXPostgresTypeHandler -{ - FLXPostgresTypeNumberHandler *_numberHandler; -} @end diff --git a/Frameworks/PostgresKit/Source/FLXPostgresTypeDateTimeHandler.m b/Frameworks/PostgresKit/Source/FLXPostgresTypeDateTimeHandler.m index 861e1727..1494478c 100644 --- a/Frameworks/PostgresKit/Source/FLXPostgresTypeDateTimeHandler.m +++ b/Frameworks/PostgresKit/Source/FLXPostgresTypeDateTimeHandler.m @@ -26,9 +26,6 @@ #import "FLXPostgresConnection.h" #import "FLXPostgresConnectionTypeHandling.h" -// Microseconds per second -#define USECS_PER_SEC 1000000 - static FLXPostgresOid FLXPostgresTypeDateTimeTypes[] = { FLXPostgresOidDate, @@ -42,11 +39,11 @@ static FLXPostgresOid FLXPostgresTypeDateTimeTypes[] = @interface FLXPostgresTypeDateTimeHandler () -- (NSDate *)_postgresEpochDate; -- (NSDate *)_dateFromBytes:(const void *)bytes length:(NSUInteger)length; -- (NSDate *)_timeFromBytes:(const void *)bytes length:(NSUInteger)length; -- (NSDate *)_timestampFromBytes:(const void *)bytes length:(NSUInteger)length; -- (NSDate *)_dateByAddingComponents:(NSDateComponents *)components toDate:(NSDate *)date; +- (NSDate *)_dateFromResult:(const PGresult *)result atRow:(NSUInteger)row column:(NSUInteger)column; +- (NSDate *)_timeFromResult:(const PGresult *)result atRow:(NSUInteger)row column:(NSUInteger)column; +- (NSDate *)_timestmpFromResult:(const PGresult *)result atRow:(NSUInteger)row column:(NSUInteger)column; + +- (NSDate *)_dateFromComponents:(NSDateComponents *)components; @end @@ -70,25 +67,21 @@ static FLXPostgresOid FLXPostgresTypeDateTimeTypes[] = return nil; } -- (id)objectFromRemoteData:(const void *)bytes length:(NSUInteger)length type:(FLXPostgresOid)type -{ - if (!bytes || !type) return nil; - - if (!_numberHandler) { - _numberHandler = (FLXPostgresTypeNumberHandler *)[_connection typeHandlerForClass:[NSNumber class]]; - } +- (id)objectFromResult:(const PGresult *)result atRow:(unsigned int)row column:(unsigned int)column +{ + FLXPostgresOid type = PQftype(result, column); switch (type) { case FLXPostgresOidDate: - return [self _dateFromBytes:bytes length:length]; + return [self _dateFromResult:result atRow:row column:column]; case FLXPostgresOidTime: case FLXPostgresOidTimeTZ: case FLXPostgresOidAbsTime: - return [self _timeFromBytes:bytes length:length]; + return [self _timeFromResult:result atRow:row column:column]; case FLXPostgresOidTimestamp: case FLXPostgresOidTimestampTZ: - return [self _timestampFromBytes:bytes length:length]; + return [self _timestmpFromResult:result atRow:row column:column]; default: return nil; } @@ -98,112 +91,98 @@ static FLXPostgresOid FLXPostgresTypeDateTimeTypes[] = #pragma mark Private API /** - * Returns the internal expoch date used by Postgres. + * Returns an NSDate created from a date value. * - * @return The epoch date as an NSDate. + * @param result The result to extract the value from. + * @param row The row to extract the value from. + * @param column The column to extract the value from. + * + * @return The NSDate representation. */ -- (NSDate *)_postgresEpochDate -{ - NSDateComponents *components = [[NSDateComponents alloc] init]; - - [components setDay:1]; - [components setMonth:1]; - [components setYear:2000]; - - NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; +- (NSDate *)_dateFromResult:(const PGresult *)result atRow:(NSUInteger)row column:(NSUInteger)column +{ + PGdate date; - NSDate *date = [gregorian dateFromComponents:components]; + PQgetf(result, row, "%date", column, &date); + + NSDateComponents *components = [[NSDateComponents alloc] init]; - [components release]; - [gregorian release]; + [components setDay:date.mday]; + [components setMonth:date.mon + 1]; // Months are indexed from 0 + [components setYear:date.year]; - return date; + return [self _dateFromComponents:components]; } /** - * Converts the supplied bytes representing a date to an NSDate instance. + * Returns an NSDate created from a time value. + * + * @note The date part should be ignored as it's set to a default value. * - * @param bytes The bytes to convert. - * @param length The number of bytes. + * @param result The result to extract the value from. + * @param row The row to extract the value from. + * @param column The column to extract the value from. * * @return The NSDate representation. */ -- (NSDate *)_dateFromBytes:(const void *)bytes length:(NSUInteger)length -{ - NSDateComponents *components = [[NSDateComponents alloc] init]; +- (NSDate *)_timeFromResult:(const PGresult *)result atRow:(NSUInteger)row column:(NSUInteger)column +{ + PGtime time; - [components setDay:[[_numberHandler integerObjectFromBytes:bytes length:length] integerValue]]; + PQgetf(result, row, "%time", column, &time); - NSDate *date = [self _dateByAddingComponents:components toDate:[self _postgresEpochDate]]; + NSDateComponents *components = [[NSDateComponents alloc] init]; - [components release]; + // Default date values; should be ignored + [components setDay:1]; + [components setMonth:1]; + [components setYear:2000]; - return date; -} - -/** - * Converts the supplied bytes representing the time to an NSDate instance. - * - * @param bytes The bytes to convert. - * @param length The number of bytes. - * - * @return The NSDate representation. - */ -- (NSDate *)_timeFromBytes:(const void *)bytes length:(NSUInteger)length -{ - NSNumber *time = [_numberHandler integerObjectFromBytes:bytes length:length]; + [components setHour:time.hour]; + [components setMinute:time.min]; + [components setSecond:time.sec]; + + // TODO: handle timezone - return [NSDate dateWithTimeIntervalSince1970:(NSTimeInterval)[time doubleValue]]; + return [self _dateFromComponents:components]; } /** - * Converts the supplied bytes representing a timestamp to an NSDate instance. + * Returns an NSDate created from a timestamp value. * - * @param bytes The bytes to convert. - * @param length The number of bytes. + * @param result The result to extract the value from. + * @param row The row to extract the value from. + * @param column The column to extract the value from. * * @return The NSDate representation. */ -- (NSDate *)_timestampFromBytes:(const void *)bytes length:(NSUInteger)length +- (NSDate *)_timestmpFromResult:(const PGresult *)result atRow:(NSUInteger)row column:(NSUInteger)column { - NSDate *date = nil; - NSUInteger seconds = 0; - - if ([[[_connection parameters] valueForParameter:FLXPostgresParameterIntegerDateTimes] boolValue]) { - seconds = ([[_numberHandler integerObjectFromBytes:bytes length:length] doubleValue] / (double)USECS_PER_SEC); - } - else { - seconds = [_numberHandler float64FromBytes:bytes]; - } + PGtimestamp timestamp; - NSDateComponents *components = [[NSDateComponents alloc] init]; + PQgetf(result, row, "%timestamp", column, ×tamp); - [components setSecond:seconds]; + // TODO: handle timezone - date = [self _dateByAddingComponents:components toDate:[self _postgresEpochDate]]; - - [components release]; - - return date; + return [NSDate dateWithTimeIntervalSince1970:timestamp.epoch]; } /** - * Returns the result of adding the supplied components to the supplied date. + * Returns an NSDate created from the supplied components. * - * @param components The date components to add. - * @param date The date to add the components to. + * @param The components to create the date from. * - * @return The result of the addition to the date. + * @return The NSDate created. */ -- (NSDate *)_dateByAddingComponents:(NSDateComponents *)components toDate:(NSDate *)date +- (NSDate *)_dateFromComponents:(NSDateComponents *)components { NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; - NSDate *newDate = [gregorian dateByAddingComponents:components toDate:date options:0]; + NSDate *date = [gregorian dateFromComponents:components]; [gregorian release]; - return newDate; + return date; } @end diff --git a/Frameworks/PostgresKit/Source/FLXPostgresTypeHandlerProtocol.h b/Frameworks/PostgresKit/Source/FLXPostgresTypeHandlerProtocol.h index 05b3acef..5c05af63 100644 --- a/Frameworks/PostgresKit/Source/FLXPostgresTypeHandlerProtocol.h +++ b/Frameworks/PostgresKit/Source/FLXPostgresTypeHandlerProtocol.h @@ -20,8 +20,6 @@ // License for the specific language governing permissions and limitations under // the License. -#import "FLXPostgresTypes.h" - @class FLXPostgresConnection; /** @@ -51,14 +49,14 @@ - (NSArray *)classAliases; /** - * Convert the supplied remote data into an object. + * Convert the value at the specified row and column in the supplied result to a native object. * - * @param bytes The remote data to convert. - * @param length The length of the data. - * @param type The type of data. + * @param result The result to extract the value from. + * @param row The row to extract the value from. + * @param column The column to extract the value from. * * @return An object represenation of the data. */ -- (id)objectFromRemoteData:(const void *)bytes length:(NSUInteger)length type:(FLXPostgresOid)type; +- (id)objectFromResult:(const PGresult *)result atRow:(unsigned int)row column:(unsigned int)column; @end diff --git a/Frameworks/PostgresKit/Source/FLXPostgresTypeNumberHandler.h b/Frameworks/PostgresKit/Source/FLXPostgresTypeNumberHandler.h index 375251d4..a3305e19 100644 --- a/Frameworks/PostgresKit/Source/FLXPostgresTypeNumberHandler.h +++ b/Frameworks/PostgresKit/Source/FLXPostgresTypeNumberHandler.h @@ -24,9 +24,5 @@ @interface FLXPostgresTypeNumberHandler : FLXPostgresTypeHandler -- (Float64)float64FromBytes:(const void *)bytes; - -- (NSNumber *)integerObjectFromBytes:(const void *)bytes length:(NSUInteger)length; - @end diff --git a/Frameworks/PostgresKit/Source/FLXPostgresTypeNumberHandler.m b/Frameworks/PostgresKit/Source/FLXPostgresTypeNumberHandler.m index 0a4ad011..2f0fc2ad 100644 --- a/Frameworks/PostgresKit/Source/FLXPostgresTypeNumberHandler.m +++ b/Frameworks/PostgresKit/Source/FLXPostgresTypeNumberHandler.m @@ -21,7 +21,6 @@ // the License. #import "FLXPostgresTypeNumberHandler.h" -#import "FLXPostgresTypes.h" static FLXPostgresOid FLXPostgresTypeNumberTypes[] = { @@ -34,56 +33,70 @@ static FLXPostgresOid FLXPostgresTypeNumberTypes[] = 0 }; +@interface FLXPostgresTypeNumberHandler () + +- (SInt16)_int16FromBytes:(const void *)bytes; +- (SInt32)_int32FromBytes:(const void *)bytes; +- (SInt64)_int64FromBytes:(const void *)bytes; + +- (Float32)_float32FromBytes:(const void *)bytes; +- (Float64)_float64FromBytes:(const void *)bytes; + +@end + @implementation FLXPostgresTypeNumberHandler #pragma mark - #pragma mark Integer & Unsigned Integer -- (SInt16)int16FromBytes:(const void *)bytes -{ - if (!bytes) return 0; +- (NSNumber *)_integerObjectFromBytes:(const void *)bytes length:(NSUInteger)length +{ + switch (length) + { + case 2: + return [NSNumber numberWithShort:[self _int16FromBytes:bytes]]; + case 4: + return [NSNumber numberWithInteger:[self _int32FromBytes:bytes]]; + case 8: + return [NSNumber numberWithLongLong:[self _int64FromBytes:bytes]]; + } + return nil; +} + +- (SInt16)_int16FromBytes:(const void *)bytes +{ return EndianS16_BtoN(*((SInt16 *)bytes)); } -- (SInt32)int32FromBytes:(const void *)bytes +- (SInt32)_int32FromBytes:(const void *)bytes { - if (!bytes) return 0; - return EndianS32_BtoN(*((SInt32 *)bytes)); } -- (SInt64)int64FromBytes:(const void *)bytes -{ - if (!bytes) return 0; - +- (SInt64)_int64FromBytes:(const void *)bytes +{ return EndianS64_BtoN(*((SInt64 *)bytes)); } -- (NSNumber *)integerObjectFromBytes:(const void *)bytes length:(NSUInteger)length -{ - if (!bytes) return nil; - +#pragma mark - +#pragma mark Floating Point + +- (NSNumber *)_floatObjectFromBytes:(const void *)bytes length:(NSUInteger)length +{ switch (length) { - case 2: - return [NSNumber numberWithShort:[self int16FromBytes:bytes]]; case 4: - return [NSNumber numberWithInteger:[self int32FromBytes:bytes]]; + return [NSNumber numberWithFloat:[self _float32FromBytes:bytes]]; case 8: - return [NSNumber numberWithLongLong:[self int64FromBytes:bytes]]; + return [NSNumber numberWithDouble:[self _float64FromBytes:bytes]]; } return nil; } -#pragma mark - -#pragma mark Floating Point - -- (Float32)float32FromBytes:(const void *)bytes +- (Float32)_float32FromBytes:(const void *)bytes { - if (!bytes) return 0; - union { Float32 r; UInt32 i; } u32; u32.r = *((Float32 *)bytes); @@ -92,10 +105,8 @@ static FLXPostgresOid FLXPostgresTypeNumberTypes[] = return u32.r; } -- (Float64)float64FromBytes:(const void *)bytes -{ - if (!bytes) return 0; - +- (Float64)_float64FromBytes:(const void *)bytes +{ union { Float64 r; UInt64 i; } u64; u64.r = *((Float64 *)bytes); @@ -104,25 +115,12 @@ static FLXPostgresOid FLXPostgresTypeNumberTypes[] = return u64.r; } -- (NSNumber *)floatObjectFromBytes:(const void *)bytes length:(NSUInteger)length -{ - switch (length) - { - case 4: - return [NSNumber numberWithFloat:[self float32FromBytes:bytes]]; - case 8: - return [NSNumber numberWithDouble:[self float64FromBytes:bytes]]; - } - - return nil; -} - #pragma mark - #pragma mark Boolean -- (NSNumber *)booleanObjectFromBytes:(const void *)bytes length:(NSUInteger)length +- (NSNumber *)_booleanObjectFromBytes:(const void *)bytes length:(NSUInteger)length { - if (!bytes || length != 1) return nil; + if (length != 1) return nil; return [NSNumber numberWithBool:*((const int8_t *)bytes) ? YES : NO]; } @@ -145,21 +143,25 @@ static FLXPostgresOid FLXPostgresTypeNumberTypes[] = return nil; } -- (id)objectFromRemoteData:(const void *)bytes length:(NSUInteger)length type:(FLXPostgresOid)type +- (id)objectFromResult:(const PGresult *)result atRow:(unsigned int)row column:(unsigned int)column { - if (!bytes || !length || !type) return nil; + FLXPostgresOid type = PQftype(result, column); + NSUInteger length = PQgetlength(result, row, column); + const void *bytes = PQgetvalue(result, row, column); + + if (!bytes || !length) return nil; switch (type) { case FLXPostgresOidInt8: case FLXPostgresOidInt2: case FLXPostgresOidInt4: - return [self integerObjectFromBytes:bytes length:length]; + return [self _integerObjectFromBytes:bytes length:length]; case FLXPostgresOidFloat4: case FLXPostgresOidFloat8: - return [self floatObjectFromBytes:bytes length:length]; + return [self _floatObjectFromBytes:bytes length:length]; case FLXPostgresOidBool: - return [self booleanObjectFromBytes:bytes length:length]; + return [self _booleanObjectFromBytes:bytes length:length]; default: return nil; } diff --git a/Frameworks/PostgresKit/Source/FLXPostgresTypeStringHandler.m b/Frameworks/PostgresKit/Source/FLXPostgresTypeStringHandler.m index a2e364f8..fb72346b 100644 --- a/Frameworks/PostgresKit/Source/FLXPostgresTypeStringHandler.m +++ b/Frameworks/PostgresKit/Source/FLXPostgresTypeStringHandler.m @@ -22,7 +22,6 @@ #import "FLXPostgresTypeStringHandler.h" #import "FLXPostgresConnection.h" -#import "FLXPostgresTypes.h" static FLXPostgresOid FLXPostgresTypeStringTypes[] = { @@ -55,9 +54,12 @@ static FLXPostgresOid FLXPostgresTypeStringTypes[] = return [NSArray arrayWithObject:@"NSCFString"]; } -- (id)objectFromRemoteData:(const void *)bytes length:(NSUInteger)length type:(FLXPostgresOid)type +- (id)objectFromResult:(const PGresult *)result atRow:(unsigned int)row column:(unsigned int)column { - if (!bytes || !type) return nil; + const void *bytes = PQgetvalue(result, row, column); + NSUInteger length = PQgetlength(result, row, column); + + if (!bytes || !length) return @""; return [[[NSString alloc] initWithBytes:bytes length:length encoding:[_connection stringEncoding]] autorelease]; } -- cgit v1.2.3