aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBibiko <bibiko@eva.mpg.de>2010-10-07 22:23:29 +0000
committerBibiko <bibiko@eva.mpg.de>2010-10-07 22:23:29 +0000
commit933bb6c9254ba4761eb960c1b3893a9e57c39fb6 (patch)
treebf50da8ca46d1c60b6de5e23e9881b806c75de51
parent600314d27c03b299e3a9d0f986698a8c2baca9bc (diff)
downloadsequelpro-933bb6c9254ba4761eb960c1b3893a9e57c39fb6.tar.gz
sequelpro-933bb6c9254ba4761eb960c1b3893a9e57c39fb6.tar.bz2
sequelpro-933bb6c9254ba4761eb960c1b3893a9e57c39fb6.zip
• enhanced spatial support
- implemented native routine to immediate AsText() [MULTIPOLYGON and GEOMETRYCOLLECTION are not yet ready] - enabled editing of spatial data in Content View for tables and views and in Custom Query via wkt strings which will be saved automatically as wkb by using GeomFromText()
-rw-r--r--Frameworks/MCPKit/MCPFoundationKit/MCPGeometryData.h25
-rw-r--r--Frameworks/MCPKit/MCPFoundationKit/MCPGeometryData.m126
-rw-r--r--Frameworks/MCPKit/MCPFoundationKit/MCPResult.m2
-rw-r--r--Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m2
-rw-r--r--Source/SPCustomQuery.m7
-rw-r--r--Source/SPTableContent.m15
6 files changed, 161 insertions, 16 deletions
diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPGeometryData.h b/Frameworks/MCPKit/MCPFoundationKit/MCPGeometryData.h
index 60a7febf..c37e286d 100644
--- a/Frameworks/MCPKit/MCPFoundationKit/MCPGeometryData.h
+++ b/Frameworks/MCPKit/MCPFoundationKit/MCPGeometryData.h
@@ -25,15 +25,34 @@
#import <Cocoa/Cocoa.h>
#import <Foundation/Foundation.h>
+enum wkbType
+{
+ wkb_point = 1,
+ wkb_linestring = 2,
+ wkb_polygon = 3,
+ wkb_multipoint = 4,
+ wkb_multilinestring = 5,
+ wkb_multipolygon = 6,
+ wkb_geometrycollection = 7
+};
+
+typedef struct st_point_2d_
+{
+ double x;
+ double y;
+} st_point_2d;
+
@interface MCPGeometryData : NSObject <NSCoding, NSCopying>
{
- char *geoBuffer;
+ Byte *geoBuffer;
NSUInteger bufferLength;
}
-- (id)initWithData:(NSData*)geoData;
-+ (id)dataWithData:(NSData*)geoData;
+- (id)initWithBytes:(Byte*)geoData length:(NSUInteger)length;
++ (id)dataWithBytes:(Byte*)geoData length:(NSUInteger)length;
- (NSString*)description;
- (NSUInteger)length;
+- (NSData*)data;
+- (NSString*)wktString;
@end
diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPGeometryData.m b/Frameworks/MCPKit/MCPFoundationKit/MCPGeometryData.m
index 9f7ac19a..6a41e657 100644
--- a/Frameworks/MCPKit/MCPFoundationKit/MCPGeometryData.m
+++ b/Frameworks/MCPKit/MCPFoundationKit/MCPGeometryData.m
@@ -25,6 +25,11 @@
#import "MCPGeometryData.h"
+#define SIZEOF_STORED_UINT32 4
+#define SIZEOF_STORED_DOUBLE 8
+#define POINT_DATA_SIZE (SIZEOF_STORED_DOUBLE*2)
+#define WKB_HEADER_SIZE (1+SIZEOF_STORED_UINT32)
+
@implementation MCPGeometryData
- (id)copyWithZone:(NSZone *)zone { return [self retain]; }
@@ -38,20 +43,20 @@
return self;
}
-- (id)initWithData:(NSData*)geoData
+- (id)initWithBytes:(Byte*)geoData length:(NSUInteger)length
{
if ((self = [self init])) {
- bufferLength = [geoData length];
+ bufferLength = length;
geoBuffer = malloc(bufferLength);
- memcpy(geoBuffer, [geoData bytes], bufferLength);
+ memcpy(geoBuffer, geoData, bufferLength);
}
return self;
}
-+ (id)dataWithData:(NSData*)geoData
++ (id)dataWithBytes:(Byte*)geoData length:(NSUInteger)length
{
- return [[[MCPGeometryData alloc] initWithData:geoData] autorelease];
+ return [[[MCPGeometryData alloc] initWithBytes:geoData length:length] autorelease];
}
- (NSString*)description
@@ -64,6 +69,117 @@
return bufferLength;
}
+- (NSData*)data
+{
+ return [NSData dataWithBytes:geoBuffer length:bufferLength];
+}
+
+- (NSString*)wktString
+{
+ char byteOrder;
+ UInt32 geoType, c, c1;
+ st_point_2d aPoint;
+ NSUInteger ptr;
+ double x, y;
+ NSMutableString *wkt = [NSMutableString string];
+ NSUInteger i,j;
+ BOOL raw = NO;
+
+ if (bufferLength < WKB_HEADER_SIZE)
+ return @"Error";
+
+ ptr = (raw) ? 0 : 4;
+
+ byteOrder = geoBuffer[ptr];
+
+ if(byteOrder != 0x1)
+ return @"Byte order not yet supported";
+
+ ptr++;
+ geoType = geoBuffer[ptr];
+ ptr += SIZEOF_STORED_UINT32;
+
+ NSData *d;
+ switch(geoType) {
+ case wkb_point:
+ memcpy(&aPoint, &geoBuffer[ptr], POINT_DATA_SIZE);
+ return [NSString stringWithFormat:@"POINT(%.16g %.16g)",aPoint.x, aPoint.y];
+ break;
+ case wkb_linestring:
+ [wkt setString:@"LINESTRING("];
+ c = geoBuffer[ptr];
+ ptr += SIZEOF_STORED_UINT32;
+ for(i=0; i<c; i++) {
+ memcpy(&aPoint, &geoBuffer[ptr], POINT_DATA_SIZE);
+ [wkt appendFormat:@"%.16g %.16g%@", aPoint.x, aPoint.y, (i<c-1) ? @"," : @""];
+ ptr += POINT_DATA_SIZE;
+ }
+ [wkt appendString:@")"];
+ return wkt;
+ break;
+ case wkb_polygon:
+ [wkt setString:@"POLYGON("];
+ c = geoBuffer[ptr];
+ ptr += SIZEOF_STORED_UINT32;
+ for(i=0; i<c; i++) {
+ c1 = geoBuffer[ptr];
+ ptr += SIZEOF_STORED_UINT32;
+ [wkt appendString:@"("];
+ for(j=0; j<c1; j++) {
+ memcpy(&aPoint, &geoBuffer[ptr], POINT_DATA_SIZE);
+ [wkt appendFormat:@"%.16g %.16g%@", aPoint.x, aPoint.y, (j<c1-1) ? @"," : @""];
+ ptr += POINT_DATA_SIZE;
+ }
+ [wkt appendFormat:@")%@", (i<c-1) ? @"," : @""];
+ }
+ [wkt appendString:@")"];
+ return wkt;
+ break;
+ case wkb_multipoint:
+ [wkt setString:@"MULTIPOINT("];
+ c = geoBuffer[ptr];
+ ptr += SIZEOF_STORED_UINT32+WKB_HEADER_SIZE;
+ for(i=0; i<c; i++) {
+ memcpy(&aPoint, &geoBuffer[ptr], POINT_DATA_SIZE);
+ [wkt appendFormat:@"%.16g %.16g%@", aPoint.x, aPoint.y, (i<c-1) ? @"," : @""];
+ ptr += POINT_DATA_SIZE+WKB_HEADER_SIZE;
+ }
+ [wkt appendString:@")"];
+ return wkt;
+ break;
+ case wkb_multilinestring:
+ [wkt setString:@"MULTILINESTRING("];
+ c = geoBuffer[ptr];
+ ptr += SIZEOF_STORED_UINT32+WKB_HEADER_SIZE;
+ for(i=0; i<c; i++) {
+ c1 = geoBuffer[ptr];
+ ptr += SIZEOF_STORED_UINT32;
+ [wkt appendString:@"("];
+ for(j=0; j<c1; j++) {
+ memcpy(&aPoint, &geoBuffer[ptr], POINT_DATA_SIZE);
+ [wkt appendFormat:@"%.16g %.16g%@", aPoint.x, aPoint.y, (j<c1-1) ? @"," : @""];
+ ptr += POINT_DATA_SIZE;
+ }
+ ptr += WKB_HEADER_SIZE;
+ [wkt appendFormat:@")%@", (i<c-1) ? @"," : @""];
+ }
+ [wkt appendString:@")"];
+ return wkt;
+ break;
+ case wkb_multipolygon:
+ // NSLog(@"ml %@", geoData);
+
+ [wkt setString:@"MULTIPOLYGON be patient"];
+ break;
+ case wkb_geometrycollection:
+ [wkt setString:@"GEOMETRYCOLLECTION be patient"];
+ break;
+ default:
+ return @"Error geometry type parsing";
+ }
+ return wkt;
+}
+
- (void)dealloc
{
if(geoBuffer && bufferLength) free(geoBuffer);
diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPResult.m b/Frameworks/MCPKit/MCPFoundationKit/MCPResult.m
index 82b0636e..24d14193 100644
--- a/Frameworks/MCPKit/MCPFoundationKit/MCPResult.m
+++ b/Frameworks/MCPKit/MCPFoundationKit/MCPResult.m
@@ -470,7 +470,7 @@ const OUR_CHARSET our_charsets60[] =
break;
case FIELD_TYPE_GEOMETRY:
- theCurrentObj = [MCPGeometryData dataWithData:[NSData dataWithBytes:theData length:theLengths[i]]];
+ theCurrentObj = [MCPGeometryData dataWithBytes:theData length:theLengths[i]];
break;
default:
diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m b/Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m
index 7822d896..d26dbafc 100644
--- a/Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m
+++ b/Frameworks/MCPKit/MCPFoundationKit/MCPStreamingResult.m
@@ -322,7 +322,7 @@ void _bytes2bin(Byte *n, NSUInteger nbytes, NSUInteger len, char *buf);
break;
case FIELD_TYPE_GEOMETRY:
- cellData = [MCPGeometryData dataWithData:[NSData dataWithBytes:theData length:fieldLengths[i]]];
+ cellData = [MCPGeometryData dataWithBytes:theData length:fieldLengths[i]];
break;
default:
diff --git a/Source/SPCustomQuery.m b/Source/SPCustomQuery.m
index 44ba5987..a945a53d 100644
--- a/Source/SPCustomQuery.m
+++ b/Source/SPCustomQuery.m
@@ -1752,6 +1752,9 @@
else if ([[field objectForKey:@"typegrouping"] isEqualToString:@"integer"]) {
[fieldIDQueryStr appendFormat:@"%@=%@ AND ", [[field objectForKey:@"org_name"] backtickQuotedString], [aValue description]];
}
+ else if ([[field objectForKey:@"typegrouping"] isEqualToString:@"geometry"]) {
+ [fieldIDQueryStr appendFormat:@"%@=X'%@' AND ", [[field objectForKey:@"org_name"] backtickQuotedString], [mySQLConnection prepareBinaryData:[aValue data]]];
+ }
else {
[fieldIDQueryStr appendFormat:@"%@='%@' AND ", [[field objectForKey:@"org_name"] backtickQuotedString], [mySQLConnection prepareString:aValue]];
}
@@ -1848,7 +1851,7 @@
return [prefs objectForKey:SPNullValue];
if ([theValue isKindOfClass:[MCPGeometryData class]])
- return [theValue description];
+ return [theValue wktString];
return theValue;
}
@@ -1902,6 +1905,8 @@
newObject = @"CURRENT_TIMESTAMP";
} else if([anObject isEqualToString:[prefs stringForKey:SPNullValue]]) {
newObject = @"NULL";
+ } else if ([[columnDefinition objectForKey:@"typegrouping"] isEqualToString:@"geometry"]) {
+ newObject = [NSString stringWithFormat:@"GeomFromText('%@')", anObject];
} else if ([[columnDefinition objectForKey:@"typegrouping"] isEqualToString:@"bit"]) {
newObject = [NSString stringWithFormat:@"b'%@'", ((![[anObject description] length] || [[anObject description] isEqualToString:@"0"]) ? @"0" : [anObject description])];
} else if ([[columnDefinition objectForKey:@"typegrouping"] isEqualToString:@"date"]
diff --git a/Source/SPTableContent.m b/Source/SPTableContent.m
index cc5eb6bd..fd8f1703 100644
--- a/Source/SPTableContent.m
+++ b/Source/SPTableContent.m
@@ -1547,6 +1547,9 @@
else if ([[field objectForKey:@"typegrouping"] isEqualToString:@"integer"]) {
[fieldIDQueryStr appendFormat:@"%@=%@ AND ", [[field objectForKey:@"org_name"] backtickQuotedString], [aValue description]];
}
+ else if ([[field objectForKey:@"typegrouping"] isEqualToString:@"geometry"]) {
+ [fieldIDQueryStr appendFormat:@"%@=X'%@' AND ", [[field objectForKey:@"org_name"] backtickQuotedString], [mySQLConnection prepareBinaryData:[aValue data]]];
+ }
else {
[fieldIDQueryStr appendFormat:@"%@='%@' AND ", [[field objectForKey:@"org_name"] backtickQuotedString], [mySQLConnection prepareString:aValue]];
}
@@ -2673,12 +2676,12 @@
if ([[[tableDataInstance columnWithName:NSArrayObjectAtIndex(keys, i)] objectForKey:@"type"] isEqualToString:@"BIT"]) {
[value setString:[NSString stringWithFormat:@"b'%@'", [mySQLConnection prepareString:tempValue]]];
}
+ else if ([tempValue isKindOfClass:[MCPGeometryData class]]) {
+ [value setString:[NSString stringWithFormat:@"X'%@'", [mySQLConnection prepareBinaryData:[tempValue data]]]];
+ }
// BLOB/TEXT data
else if ([tempValue isKindOfClass:[NSData class]]) {
- if([tableDataInstance columnIsGeometry:NSArrayObjectAtIndex(keys, i)])
- [value setString:[NSString stringWithFormat:@"GeomFromText('%@')", [[[NSString alloc] initWithData:tempValue encoding:NSASCIIStringEncoding] autorelease]]];
- else
- [value setString:[NSString stringWithFormat:@"X'%@'", [mySQLConnection prepareBinaryData:tempValue]]];
+ [value setString:[NSString stringWithFormat:@"X'%@'", [mySQLConnection prepareBinaryData:tempValue]]];
}
else
[value setString:[NSString stringWithFormat:@"'%@'", [mySQLConnection prepareString:tempValue]]];
@@ -3401,7 +3404,7 @@
}
if([theValue isKindOfClass:[MCPGeometryData class]])
- return [theValue description];
+ return [theValue wktString];
if ([theValue isNSNull])
return [prefs objectForKey:SPNullValue];
@@ -3542,6 +3545,8 @@
newObject = @"CURRENT_TIMESTAMP";
} else if([anObject isEqualToString:[prefs stringForKey:SPNullValue]]) {
newObject = @"NULL";
+ } else if ([[columnDefinition objectForKey:@"typegrouping"] isEqualToString:@"geometry"]) {
+ newObject = [NSString stringWithFormat:@"GeomFromText('%@')", anObject];
} else if ([[columnDefinition objectForKey:@"typegrouping"] isEqualToString:@"bit"]) {
newObject = [NSString stringWithFormat:@"b'%@'", ((![[anObject description] length] || [[anObject description] isEqualToString:@"0"]) ? @"0" : [anObject description])];
} else if ([[columnDefinition objectForKey:@"typegrouping"] isEqualToString:@"date"]