Author: rfm
Date: Wed Apr 29 19:35:18 2015
New Revision: 38466
URL: http://svn.gna.org/viewcvs/gnustep?rev=38466&view=rev
Log:
some optimisations
Modified:
libs/sqlclient/trunk/Postgres.m
Modified: libs/sqlclient/trunk/Postgres.m
URL:
http://svn.gna.org/viewcvs/gnustep/libs/sqlclient/trunk/Postgres.m?rev=38466&r1=38465&r2=38466&view=diff
==============================================================================
--- libs/sqlclient/trunk/Postgres.m (original)
+++ libs/sqlclient/trunk/Postgres.m Wed Apr 29 19:35:18 2015
@@ -41,6 +41,7 @@
#import <Foundation/NSProcessInfo.h>
#import <Foundation/NSString.h>
#import <Foundation/NSThread.h>
+#import <Foundation/NSTimeZone.h>
#import <Foundation/NSUserDefaults.h>
#import <Foundation/NSValue.h>
@@ -71,6 +72,8 @@
static NSDate *future = nil;
static NSNull *null = nil;
+
+static NSTimeZone *zones[47]; // For -23 to +23 hours
@implementation SQLClientPostgres
@@ -84,6 +87,10 @@
[future retain];
null = [NSNull null];
[null retain];
+ for (int i = -23; i <= 23; i++)
+ {
+ zones[i + 23] = [[NSTimeZone timeZoneForSecondsFromGMT: i * 60 * 60]
retain];
+ }
}
}
@@ -471,28 +478,13 @@
}
}
-static unsigned int trim(char *str)
-{
- char *start = str;
-
- while (isspace(*str))
- {
- str++;
- }
- if (str != start)
- {
- strcpy(start, str);
- }
- str = start;
- while (*str != '\0')
- {
- str++;
- }
- while (str > start && isspace(str[-1]))
- {
- *--str = '\0';
- }
- return (str - start);
+static inline unsigned int trim(char *str, unsigned len)
+{
+ while (len > 0 && isspace(str[len - 1]))
+ {
+ len--;
+ }
+ return len;
}
- (char*) parseIntoArray: (NSMutableArray *)a type: (int)t from: (char*)p
@@ -589,7 +581,7 @@
}
save = *p;
*p = '\0';
- len = trim(start);
+ len = trim(start, p - start);
if (strcmp(start, "NULL") == 0)
{
v = null;
@@ -632,22 +624,24 @@
return p;
}
-- (id) parseField: (char *)p type: (int)t
+- (id) newParseField: (char *)p type: (int)t size: (int)s
{
char arrayType = 0;
switch (t)
{
case 1082: // Date
- return [self dbToDateFromBuffer: p length: trim(p)];
+ return [self newDateFromBuffer: p length: trim(p, s)];
case 1083: // Time (treat as string)
- trim(p);
- return [NSString stringWithUTF8String: p];
+ s = trim(p, s);
+ return [[NSString alloc] initWithBytes: p
+ length: s
+ encoding: NSASCIIStringEncoding];
case 1114: // Timestamp without time zone.
case 1184: // Timestamp with time zone.
- return [self dbToDateFromBuffer: p length: trim(p)];
+ return [self newDateFromBuffer: p length: trim(p, s)];
case 16: // BOOL
if (*p == 't')
@@ -660,16 +654,20 @@
}
case 17: // BYTEA
- return [self dataFromBLOB: p];
+ return [[self dataFromBLOB: p] retain];
case 18: // "char"
- return [NSString stringWithUTF8String: p];
+ return [[NSString alloc] initWithBytes: p
+ length: s
+ encoding: NSUTF8StringEncoding];
case 20: // INT8
case 21: // INT2
case 23: // INT4
- trim(p);
- return [NSString stringWithUTF8String: p];
+ s = trim(p, s);
+ return [[NSString alloc] initWithBytes: p
+ length: s
+ encoding: NSASCIIStringEncoding];
break;
case 1182: // DATE ARRAY
@@ -693,7 +691,7 @@
{
NSMutableArray *a;
- a = [NSMutableArray arrayWithCapacity: 10];
+ a = [[NSMutableArray alloc] initWithCapacity: 10];
p = [self parseIntoArray: a type: arrayType from: p];
if ([self debugging] > 2)
{
@@ -706,9 +704,11 @@
default:
if (YES == _shouldTrim)
{
- trim(p);
+ s = trim(p, s);
}
- return [NSString stringWithUTF8String: p];
+ return [[NSString alloc] initWithBytes: p
+ length: s
+ encoding: NSUTF8StringEncoding];
}
}
@@ -773,6 +773,7 @@
int fmod[fieldCount];
int fformat[fieldCount];
SQLRecordKeys *k = nil;
+ int d = [self debugging];
int i;
for (i = 0; i < fieldCount; i++)
@@ -784,6 +785,20 @@
}
records = [[ltype alloc] initWithCapacity: recordCount];
+
+ /* Create buffers to store the previous row from the
+ * database and the previous objc values.
+ */
+ int len[fieldCount];
+ const char *ptr[fieldCount];
+ id obj[fieldCount];
+
+ for (i = 0; i < fieldCount; i++)
+ {
+ len[i] = -1;
+ obj[i] = nil;
+ }
+
for (i = 0; i < recordCount; i++)
{
SQLRecord *record;
@@ -799,20 +814,34 @@
char *p = PQgetvalue(result, i, j);
int size = PQgetlength(result, i, j);
- if ([self debugging] > 1)
+ if (d > 1)
{
[self debug: @"%@ type:%d mod:%d size: %d\n",
keys[j], ftype[j], fmod[j], size];
}
- if (fformat[j] == 0) // Text
+ /* Often many rows will contain the same data in
+ * one or more columns, so we check to see if the
+ * value we have just read is small and identical
+ * to the value in the same column of the previous
+ * row. Only if it isn't do we create a new object.
+ */
+ if (size != len[j] || size > 20
+ || memcmp(p, ptr[j], (size_t)len) != 0)
{
- v = [self parseField: p type: ftype[j]];
- }
- else // Binary
- {
- NSLog(@"Binary data treated as NSNull "
- @"in %@ type:%d mod:%d size:%d\n",
- keys[j], ftype[j], fmod[j], size);
+ [obj[j] release];
+ if (fformat[j] == 0) // Text
+ {
+ v = [self newParseField: p
+ type: ftype[j]
+ size: size];
+ obj[j] = v;
+ }
+ else // Binary
+ {
+ NSLog(@"Binary data treated as NSNull "
+ @"in %@ type:%d mod:%d size:%d\n",
+ keys[j], ftype[j], fmod[j], size);
+ }
}
}
values[j] = v;
@@ -839,6 +868,10 @@
[records addObject: record];
[record release];
}
+ for (i = 0; i < fieldCount; i++)
+ {
+ [obj[i] release];
+ }
}
else if (PQresultStatus(result) == PGRES_COMMAND_OK)
{
@@ -1196,6 +1229,151 @@
return d;
}
+- (NSDate*) newDateFromBuffer: (char*)b length: (int)l
+{
+ NSCalendarDate *d;
+ NSTimeZone *zone;
+ int milliseconds = 0;
+ int timezone = 0;
+ int day;
+ int month;
+ int year;
+ int hour;
+ int minute;
+ int second;
+ int i;
+
+ i = 0;
+
+ if (i >= l || !isdigit(b[i])) return nil;
+ year = b[i++] - '0';
+ if (i >= l || !isdigit(b[i])) return nil;
+ year = year * 10 + b[i++] - '0';
+ if (i >= l || !isdigit(b[i])) return nil;
+ year = year * 10 + b[i++] - '0';
+ if (i >= l || !isdigit(b[i])) return nil;
+ year = year * 10 + b[i++] - '0';
+
+ if (i >= l || b[i++] != '-') return nil;
+
+ if (i >= l || !isdigit(b[i])) return nil;
+ month = b[i++] - '0';
+ if (i >= l || !isdigit(b[i])) return nil;
+ month = month * 10 + b[i++] - '0';
+ if (month < 1 || month > 12) return nil;
+
+ if (i >= l || b[i++] != '-') return nil;
+
+ if (i >= l || !isdigit(b[i])) return nil;
+ day = b[i++] - '0';
+ if (i >= l || !isdigit(b[i])) return nil;
+ day = day * 10 + b[i++] - '0';
+ if (day < 1 || day > 31) return nil;
+
+ if (i == l)
+ {
+ hour = 0;
+ minute = 0;
+ second = 0;
+ }
+ else
+ {
+ if (i >= l || b[i++] != ' ') return nil;
+
+ if (i >= l || !isdigit(b[i])) return nil;
+ hour = b[i++] - '0';
+ if (i >= l || !isdigit(b[i])) return nil;
+ hour = hour * 10 + b[i++] - '0';
+ if (hour < 0 || hour > 23) return nil;
+
+ if (i >= l || b[i++] != ':') return nil;
+
+ if (i >= l || !isdigit(b[i])) return nil;
+ minute = b[i++] - '0';
+ if (i >= l || !isdigit(b[i])) return nil;
+ minute = minute * 10 + b[i++] - '0';
+ if (minute < 0 || minute > 59) return nil;
+
+ if (i >= l || b[i++] != ':') return nil;
+
+ if (i >= l || !isdigit(b[i])) return nil;
+ second = b[i++] - '0';
+ if (i >= l || !isdigit(b[i])) return nil;
+ second = second * 10 + b[i++] - '0';
+ if (second < 0 || second > 60) return nil;
+
+ if (i < l && '.' == b[i])
+ {
+ i++;
+ if (i >= l || !isdigit(b[i])) return nil;
+ milliseconds = b[i++] - '0';
+ milliseconds *=- 10;
+ if (i < l && isdigit(b[i]))
+ milliseconds += b[i++] - '0';
+ milliseconds *=- 10;
+ if (i < l && isdigit(b[i]))
+ milliseconds += b[i++] - '0';
+ while (i < l && isdigit(b[i]))
+ i++;
+ }
+
+ if (i < l && ('+' == b[i] || '-' == b[i]))
+ {
+ char sign = b[i++];
+
+ if (i >= l || !isdigit(b[i])) return nil;
+ timezone = b[i++] - '0';
+ if (i >= l || !isdigit(b[i])) return nil;
+ timezone = timezone * 10 + b[i++] - '0';
+ if (timezone < 0 || timezone > 23) return nil;
+ timezone *= 60; // Convert to minutes
+ if (i < l && ':' == b[i])
+ {
+ int tzmin;
+
+ if (i >= l || !isdigit(b[i])) return nil;
+ tzmin = b[i++] - '0';
+ if (i >= l || !isdigit(b[i])) return nil;
+ tzmin = tzmin * 10 + b[i++] - '0';
+ if (tzmin < 0 || tzmin > 59) return nil;
+
+ timezone += tzmin;
+ }
+ if ('-' == sign)
+ timezone = -timezone;
+ }
+ }
+ if (timezone % 60 == 0)
+ {
+ zone = zones[timezone / 60];
+ }
+ else
+ {
+ zone = [NSTimeZone timeZoneForSecondsFromGMT: timezone * 60];
+ }
+
+ d = [[NSCalendarDate alloc] initWithYear: year
+ month: month
+ day: day
+ hour: hour
+ minute: minute
+ second: second
+ timeZone: zone];
+
+ if (milliseconds > 0)
+ {
+ NSTimeInterval ti;
+
+ ti = milliseconds;
+ ti /= 1000.0;
+ ti += [d timeIntervalSinceReferenceDate];
+ d = [d initWithTimeIntervalSinceReferenceDate: ti];
+ [d setTimeZone: zone];
+ }
+ [d setCalendarFormat: @"%Y-%m-%d %H:%M:%S %z"];
+ return d;
+}
+
- (void) dealloc
{
if (extra != 0)
_______________________________________________
Gnustep-cvs mailing list
[email protected]
https://mail.gna.org/listinfo/gnustep-cvs