From 95d2e4acc393e91aa70ed4c71daa1f776454a936 Mon Sep 17 00:00:00 2001 From: Bibiko Date: Thu, 7 Oct 2010 14:15:07 +0000 Subject: =?UTF-8?q?=E2=80=A2=20removed=20approach=20to=20query=20spatial?= =?UTF-8?q?=20data=20by=20using=20AsText()=20since=20it=20breaks=20some=20?= =?UTF-8?q?column=20definition=20approaches=20-=20instead=20introduced=20a?= =?UTF-8?q?=20new=20MCPKit=20class=20MCPGeometryData=20-=20up=20to=20now?= =?UTF-8?q?=20the=20spatial=20data=20will=20be=20displayed=20as=20hex=20by?= =?UTF-8?q?tes=20-=20work=20on=20it=20will=20come=20soon?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MCPKit/MCPFoundationKit/MCPGeometryData.h | 39 +++ .../MCPKit/MCPFoundationKit/MCPGeometryData.m | 73 +++++ Frameworks/MCPKit/MCPFoundationKit/MCPKit.h | 1 + Frameworks/MCPKit/MCPFoundationKit/MCPResult.m | 336 +++++++++++---------- .../MCPKit/MCPFoundationKit/MCPStreamingResult.m | 3 +- 5 files changed, 287 insertions(+), 165 deletions(-) create mode 100644 Frameworks/MCPKit/MCPFoundationKit/MCPGeometryData.h create mode 100644 Frameworks/MCPKit/MCPFoundationKit/MCPGeometryData.m (limited to 'Frameworks/MCPKit/MCPFoundationKit') diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPGeometryData.h b/Frameworks/MCPKit/MCPFoundationKit/MCPGeometryData.h new file mode 100644 index 00000000..60a7febf --- /dev/null +++ b/Frameworks/MCPKit/MCPFoundationKit/MCPGeometryData.h @@ -0,0 +1,39 @@ +// +// $Id$ +// +// MCPGeometryData.h +// sequel-pro +// +// Created by Hans-Jörg Bibiko on October 07, 2010 +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// More info at + +#import +#import + +@interface MCPGeometryData : NSObject +{ + char *geoBuffer; + NSUInteger bufferLength; +} + +- (id)initWithData:(NSData*)geoData; ++ (id)dataWithData:(NSData*)geoData; +- (NSString*)description; +- (NSUInteger)length; + +@end diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPGeometryData.m b/Frameworks/MCPKit/MCPFoundationKit/MCPGeometryData.m new file mode 100644 index 00000000..9f7ac19a --- /dev/null +++ b/Frameworks/MCPKit/MCPFoundationKit/MCPGeometryData.m @@ -0,0 +1,73 @@ +// +// $Id$ +// +// MCPGeometryData.m +// sequel-pro +// +// Created by Hans-Jörg Bibiko on October 07, 2010 +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// More info at + +#import "MCPGeometryData.h" + + +@implementation MCPGeometryData + +- (id)copyWithZone:(NSZone *)zone { return [self retain]; } + +- (id)init +{ + if ((self = [super init])) { + geoBuffer = nil; + bufferLength = 0; + } + return self; +} + +- (id)initWithData:(NSData*)geoData +{ + if ((self = [self init])) { + bufferLength = [geoData length]; + geoBuffer = malloc(bufferLength); + memcpy(geoBuffer, [geoData bytes], bufferLength); + } + return self; +} + + ++ (id)dataWithData:(NSData*)geoData +{ + return [[[MCPGeometryData alloc] initWithData:geoData] autorelease]; +} + +- (NSString*)description +{ + return [[NSData dataWithBytes:geoBuffer length:bufferLength] description]; +} + +- (NSUInteger)length +{ + return bufferLength; +} + +- (void)dealloc +{ + if(geoBuffer && bufferLength) free(geoBuffer); + [super dealloc]; +} + +@end diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPKit.h b/Frameworks/MCPKit/MCPFoundationKit/MCPKit.h index 11d2c72e..b83ebb69 100644 --- a/Frameworks/MCPKit/MCPFoundationKit/MCPKit.h +++ b/Frameworks/MCPKit/MCPFoundationKit/MCPKit.h @@ -37,5 +37,6 @@ #import #import #import +#import #import "mysql.h" diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPResult.m b/Frameworks/MCPKit/MCPFoundationKit/MCPResult.m index be8a85eb..82b0636e 100644 --- a/Frameworks/MCPKit/MCPFoundationKit/MCPResult.m +++ b/Frameworks/MCPKit/MCPFoundationKit/MCPResult.m @@ -30,6 +30,7 @@ #import "MCPNull.h" #import "MCPNumber.h" #import "MCPResult.h" +#import "MCPGeometryData.h" NSCalendarDate *MCPYear0000; @@ -196,28 +197,28 @@ const OUR_CHARSET our_charsets60[] = /** * Hold the results of a query to a MySQL database server. It correspond to the MYSQL_RES structure of the C API, and to the statement handle of the PERL DBI/DBD. * - * Uses the !{mysql_store_result()} function from the C API. + * Uses the !{mysql_store_result()} function from the C API. * * This object is generated only by a MCPConnection object, in this way (see #{MCPConnection} documentation): * * MCPConnection *theConnec = [MCPConnection alloc]; * MCPResult *theRes; - * NSDictionary *theDict; - * NSArray *theColNames; - * int i, j; - * - * theConnec = [theConnec initToHost:@"albert.com" withLogin:@"toto" password:@"albert" usingPort:0]; + * NSDictionary *theDict; + * NSArray *theColNames; + * int i, j; + * + * theConnec = [theConnec initToHost:@"albert.com" withLogin:@"toto" password:@"albert" usingPort:0]; * [theConnec selectDB:@"db1"]; * theRes = [theConnec queryString:@"select * from table1"]; * theColNames = [theRes fetchFiedlsName]; * i = 0; * * while (theDict = [theRes fetchRowAsDictionary]) { - * NSLog(@"Row : %d\n", i); + * NSLog(@"Row : %d\n", i); * for (j=0; j<[theColNames count]; j++) { * NSLog(@" Field : %@, contain : %@\n", [theColNames objectAtIndex:j], [theDict objectForKey:[theColNames objectAtIndex:j]]); * } - * i++; + * i++; * } */ @@ -245,12 +246,12 @@ const OUR_CHARSET our_charsets60[] = mEncoding = [MCPConnection defaultMySQLEncoding]; mReturnDataAsStrings = NO; mTimeZone = nil; - + if (mResult) { mysql_free_result(mResult); mResult = NULL; } - + if (mNames) { [mNames release]; mNames = nil; @@ -258,12 +259,12 @@ const OUR_CHARSET our_charsets60[] = mNumOfFields = 0; } - - return self; + + return self; } /** - * Initialise a MCPResult, it is used internally by MCPConnection !{queryString:} method: the only proper + * Initialise a MCPResult, it is used internally by MCPConnection !{queryString:} method: the only proper * way to get a running MCPResult object. */ - (id)initWithMySQLPtr:(MYSQL *)mySQLPtr encoding:(NSStringEncoding)iEncoding timeZone:(NSTimeZone *)iTimeZone @@ -272,19 +273,19 @@ const OUR_CHARSET our_charsets60[] = mEncoding = iEncoding; mTimeZone = [iTimeZone retain]; mReturnDataAsStrings = NO; - + if (mResult) { mysql_free_result(mResult); mResult = NULL; } - + if (mNames) { [mNames release]; mNames = nil; } - + mResult = mysql_store_result(mySQLPtr); - + if (mResult) { mNumOfFields = mysql_num_fields(mResult); } @@ -292,12 +293,12 @@ const OUR_CHARSET our_charsets60[] = mNumOfFields = 0; } } - + return self; } /** - * This metod is used internally by MCPConnection object when it have already a MYSQL_RES object to initialise + * This metod is used internally by MCPConnection object when it have already a MYSQL_RES object to initialise * MCPResult object. Initialise a MCPResult with the MYSQL_RES pointer (returned by such a function as mysql_list_dbs). * NB: MCPResult should be made by using one of the method of MCPConnection. */ @@ -307,19 +308,19 @@ const OUR_CHARSET our_charsets60[] = mEncoding = iEncoding; mTimeZone = [iTimeZone retain]; mReturnDataAsStrings = NO; - + if (mResult) { mysql_free_result(mResult); mResult = NULL; } - + if (mNames) { [mNames release]; mNames = nil; } - + mResult = mySQLResPtr; - + if (mResult) { mNumOfFields = mysql_num_fields(mResult); } @@ -327,8 +328,8 @@ const OUR_CHARSET our_charsets60[] = mNumOfFields = 0; } } - - return self; + + return self; } #pragma mark - @@ -342,7 +343,7 @@ const OUR_CHARSET our_charsets60[] = if (mResult) { return mysql_num_rows(mResult); } - + return 0; } @@ -354,7 +355,7 @@ const OUR_CHARSET our_charsets60[] = if (mResult) { return mNumOfFields = mysql_num_fields(mResult); } - + return mNumOfFields = 0; } @@ -376,23 +377,23 @@ const OUR_CHARSET our_charsets60[] = */ - (id)fetchRowAsType:(MCPReturnType)aType { - MYSQL_ROW theRow; - unsigned long *theLengths; - MYSQL_FIELD *theField; - NSInteger i; - id theReturn; - + MYSQL_ROW theRow; + unsigned long *theLengths; + MYSQL_FIELD *theField; + NSInteger i; + id theReturn; + if (mResult == NULL) { // If there is no results, returns nil, as after the last row... return nil; } - + theRow = mysql_fetch_row(mResult); - + if (theRow == NULL) { return nil; } - + switch (aType) { case MCPTypeArray: theReturn = [NSMutableArray arrayWithCapacity:mNumOfFields]; @@ -408,13 +409,13 @@ const OUR_CHARSET our_charsets60[] = theReturn = [NSMutableArray arrayWithCapacity:mNumOfFields]; break; } - + theLengths = mysql_fetch_lengths(mResult); theField = mysql_fetch_fields(mResult); - + for (i=0; i= theNumFields) { // Out of range... should raise an exception theRet = 0; @@ -856,7 +864,7 @@ const OUR_CHARSET our_charsets60[] = else { theRet = theField[index].flags; } - + return theRet; } @@ -868,39 +876,39 @@ const OUR_CHARSET our_charsets60[] = NSUInteger theRet; NSUInteger index; MYSQL_FIELD *theField; - + if (mResult == NULL) { // If no results, give an empty array. Maybe it's better to give a nil pointer? return (0); } - + if (mNames == nil) { [self fetchFieldNames]; } - + theField = mysql_fetch_fields(mResult); - + if ([mNames indexOfObject:key] == NSNotFound) { // Non existent key... should raise an exception theRet = 0; } else { index = [mNames indexOfObject:key]; - + theRet = theField[index].flags; } - + return theRet; } /** - * Return YES if the field with the given index is a BLOB. It should be used to discriminates between BLOBs + * Return YES if the field with the given index is a BLOB. It should be used to discriminates between BLOBs * and TEXTs. * - * #{DEPRECATED}, This method is not consistent with the C API which is supposed to return YES for BOTH + * #{DEPRECATED}, This method is not consistent with the C API which is supposed to return YES for BOTH * text and blob (and BTW is also deprecated)... * - * #{NOTE} That the current version handles properly TEXT, and returns those as NSString (and not NSData as + * #{NOTE} That the current version handles properly TEXT, and returns those as NSString (and not NSData as * it used to be). */ - (BOOL)isBlobAtIndex:(NSUInteger)index @@ -908,15 +916,15 @@ const OUR_CHARSET our_charsets60[] = BOOL theRet; NSUInteger theNumFields; MYSQL_FIELD *theField; - + if (mResult == NULL) { // If no results, give an empty array. Maybe it's better to give a nil pointer? return (NO); } - + theNumFields = [self numOfFields]; theField = mysql_fetch_fields(mResult); - + if (index >= theNumFields) { // Out of range... should raise an exception theRet = NO; @@ -934,18 +942,18 @@ const OUR_CHARSET our_charsets60[] = break; } } - + return theRet; } /** - * Return YES if the field (by name) with the given index is a BLOB. It should be used to discriminates + * Return YES if the field (by name) with the given index is a BLOB. It should be used to discriminates * between BLOBs and TEXTs. * - * #{DEPRECATED}, This method is not consistent with the C API which is supposed to return YES for BOTH + * #{DEPRECATED}, This method is not consistent with the C API which is supposed to return YES for BOTH * text and blob (and BTW is also deprecated)... * - * #{NOTE} That the current version handles properly TEXT, and returns those as NSString (and not NSData + * #{NOTE} That the current version handles properly TEXT, and returns those as NSString (and not NSData * as it used to be). */ - (BOOL)isBlobForKey:(NSString *)key @@ -953,25 +961,25 @@ const OUR_CHARSET our_charsets60[] = BOOL theRet; NSUInteger index; MYSQL_FIELD *theField; - + if (mResult == NULL) { // If no results, give an empty array. Maybe it's better to give a nil pointer? return (NO); } - + if (mNames == nil) { [self fetchFieldNames]; } - + theField = mysql_fetch_fields(mResult); - + if ([mNames indexOfObject:key] == NSNotFound) { // Non existent key... should raise an exception theRet = NO; } else { index = [mNames indexOfObject:key]; - + switch(theField[index].type) { case FIELD_TYPE_TINY_BLOB: case FIELD_TYPE_BLOB: @@ -984,7 +992,7 @@ const OUR_CHARSET our_charsets60[] = break; } } - + return theRet; } @@ -1010,22 +1018,22 @@ const OUR_CHARSET our_charsets60[] = - (NSString *)stringWithText:(NSData *)theTextData { NSString *theString; - + if (theTextData == nil) { return nil; } - + theString = [[NSString alloc] initWithData:theTextData encoding:mEncoding]; - + if (theString) { [theString autorelease]; } - + return theString; } /** - * Return a (long) string containing the table of results, first line being the fields name, next line(s) + * Return a (long) string containing the table of results, first line being the fields name, next line(s) * the row(s). Useful to have NSLog logging a MCPResult (example). */ - (NSString *)description @@ -1039,26 +1047,26 @@ const OUR_CHARSET our_charsets60[] = NSArray *theRow; MYSQL_ROW_OFFSET thePosition; BOOL trunc = [MCPConnection truncateLongField]; - + // First line, saying we are displaying a MCPResult [theString appendFormat:@"MCPResult: (encoding : %ld, dim %ld x %ld)\n", (long)mEncoding, (long)mNumOfFields, (long)[self numOfRows]]; - + // Second line: the field names, tab separated [self fetchFieldNames]; - + for (i=0; i<(mNumOfFields-1); i++) { [theString appendFormat:@"%@\t", [mNames objectAtIndex:i]]; } - + [theString appendFormat:@"%@\n", [mNames objectAtIndex:i]]; // Next lines, the records (saving current position to put it back after the full display) thePosition = mysql_row_tell(mResult); [self dataSeek:0]; - - while (theRow = [self fetchRowAsArray]) + + while (theRow = [self fetchRowAsArray]) { id theField = [theRow objectAtIndex:i]; - + if (trunc) { if (([theField isKindOfClass:[NSString class]]) && (kLengthOfTruncationForLog < [(NSString *)theField length])) { theField = [theField substringToIndex:kLengthOfTruncationForLog]; @@ -1067,37 +1075,37 @@ const OUR_CHARSET our_charsets60[] = theField = [NSData dataWithBytes:[theField bytes] length:kLengthOfTruncationForLog]; } } - - for (i=0; i<(mNumOfFields - 1); i++) + + for (i=0; i<(mNumOfFields - 1); i++) { [theString appendFormat:@"%@\t", theField]; } - + [theString appendFormat:@"%@\n", theField]; } - + // Returning to the proper row mysql_row_seek(mResult, thePosition); - + return theString; } } /** - * For internal use only. Transform a NSString to a C type string (ended with \0) using ethe character set + * For internal use only. Transform a NSString to a C type string (ended with \0) using ethe character set * from the MCPConnection. Lossy conversions are enabled. */ - (const char *)cStringFromString:(NSString *)theString { NSMutableData *theData; - + if (!theString) { return (const char *)NULL; } - + theData = [NSMutableData dataWithData:[theString dataUsingEncoding:mEncoding allowLossyConversion:YES]]; [theData increaseLengthBy:1]; - + return (const char *)[theData bytes]; } @@ -1121,38 +1129,38 @@ const OUR_CHARSET our_charsets60[] = { // BOOL isUnsigned = (flags & UNSIGNED_FLAG) != 0; // BOOL isZerofill = (flags & ZEROFILL_FLAG) != 0; - + switch (type) { case FIELD_TYPE_BIT: return @"BIT"; case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_NEWDECIMAL: - //return isUnsigned ? (isZerofill? @"DECIMAL UNSIGNED ZEROFILL" : @"DECIMAL UNSIGNED"): + //return isUnsigned ? (isZerofill? @"DECIMAL UNSIGNED ZEROFILL" : @"DECIMAL UNSIGNED"): return @"DECIMAL"; case MYSQL_TYPE_TINY: - // return isUnsigned ? (isZerofill? @"TINYINT UNSIGNED ZEROFILL" : @"TINYINT UNSIGNED"): + // return isUnsigned ? (isZerofill? @"TINYINT UNSIGNED ZEROFILL" : @"TINYINT UNSIGNED"): return @"TINYINT"; case MYSQL_TYPE_SHORT: - // return isUnsigned ? (isZerofill? @"SMALLINT UNSIGNED ZEROFILL" : @"SMALLINT UNSIGNED"): + // return isUnsigned ? (isZerofill? @"SMALLINT UNSIGNED ZEROFILL" : @"SMALLINT UNSIGNED"): return @"SMALLINT"; case MYSQL_TYPE_LONG: - // return isUnsigned ? (isZerofill? @"INT UNSIGNED ZEROFILL" : @"INT UNSIGNED"): + // return isUnsigned ? (isZerofill? @"INT UNSIGNED ZEROFILL" : @"INT UNSIGNED"): return @"INT"; case MYSQL_TYPE_FLOAT: - // return isUnsigned ? (isZerofill? @"FLOAT UNSIGNED ZEROFILL" : @"FLOAT UNSIGNED"): + // return isUnsigned ? (isZerofill? @"FLOAT UNSIGNED ZEROFILL" : @"FLOAT UNSIGNED"): return @"FLOAT"; case MYSQL_TYPE_DOUBLE: - // return isUnsigned ? (isZerofill? @"DOUBLE UNSIGNED ZEROFILL" : @"DOUBLE UNSIGNED"): + // return isUnsigned ? (isZerofill? @"DOUBLE UNSIGNED ZEROFILL" : @"DOUBLE UNSIGNED"): return @"DOUBLE"; case MYSQL_TYPE_NULL: return @"NULL"; case MYSQL_TYPE_TIMESTAMP: return @"TIMESTAMP"; case MYSQL_TYPE_LONGLONG: - // return isUnsigned ? (isZerofill? @"BIGINT UNSIGNED ZEROFILL" : @"BIGINT UNSIGNED") : + // return isUnsigned ? (isZerofill? @"BIGINT UNSIGNED ZEROFILL" : @"BIGINT UNSIGNED") : return @"BIGINT"; case MYSQL_TYPE_INT24: - // return isUnsigned ? (isZerofill? @"MEDIUMINT UNSIGNED ZEROFILL" : @"MEDIUMINT UNSIGNED") : + // return isUnsigned ? (isZerofill? @"MEDIUMINT UNSIGNED ZEROFILL" : @"MEDIUMINT UNSIGNED") : return @"MEDIUMINT"; case MYSQL_TYPE_DATE: return @"DATE"; @@ -1281,7 +1289,7 @@ const OUR_CHARSET our_charsets60[] = return @"geometry"; default: return @"blobdata"; - + } } @@ -1291,13 +1299,13 @@ const OUR_CHARSET our_charsets60[] = - (NSString *)findCharsetName:(NSUInteger)charsetnr { const OUR_CHARSET * c = our_charsets60; - + do { if (c->nr == charsetnr) return [self stringWithCString:c->name]; ++c; } while (c[0].nr != 0); - + return @"UNKNOWN"; } @@ -1307,13 +1315,13 @@ const OUR_CHARSET our_charsets60[] = - (NSString *)findCharsetCollation:(NSUInteger)charsetnr { const OUR_CHARSET * c = our_charsets60; - + do { if (c->nr == charsetnr) return [self stringWithCString:c->collation]; ++c; } while (c[0].nr != 0); - + return @"UNKNOWN"; } @@ -1324,13 +1332,13 @@ const OUR_CHARSET our_charsets60[] = - (NSUInteger)findCharsetMaxByteLengthPerChar:(NSUInteger)charsetnr { const OUR_CHARSET * c = our_charsets60; - + do { if (c->nr == charsetnr) return c->char_maxlen; ++c; } while (c[0].nr != 0); - + return 1; } diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m b/Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m index 5883bdc2..7822d896 100644 --- a/Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m +++ b/Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m @@ -27,6 +27,7 @@ #import "MCPConnection.h" #import "MCPNull.h" #import "MCPNumber.h" +#import "MCPGeometryData.h" /** * IMPORTANT NOTE @@ -321,7 +322,7 @@ void _bytes2bin(Byte *n, NSUInteger nbytes, NSUInteger len, char *buf); break; case FIELD_TYPE_GEOMETRY: - cellData = [NSData dataWithBytes:theData length:fieldLengths[i]]; + cellData = [MCPGeometryData dataWithData:[NSData dataWithBytes:theData length:fieldLengths[i]]]; break; default: -- cgit v1.2.3