Optimisation tweaks

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/sqlclient/trunk@38467 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2015-04-30 09:12:47 +00:00
parent 19a68d1abd
commit d70286f339
3 changed files with 280 additions and 180 deletions

View file

@ -1,9 +1,16 @@
2015-04-30 Richard Frith-Macdonald <rfm@gnu.org>
* Postgres.m:
* testPostgres.m:
Fix error parsing timestamps in arrays when the server quoters them.
Also optimise string allocation, and add some tests.
2015-04-28 Richard Frith-Macdonald <rfm@gnu.org>
* SQLClient.h:
* SQLClient.m:
* Postgres.m:
Deprecate trtansaction merging.
Deprecate transaction merging.
Rewrite SQLRecord concrete class to use a new SQLRecordKeys object
shared between all the records produced by a query (as a performance
enhancement for large queries).

View file

@ -73,14 +73,193 @@ typedef struct {
static NSDate *future = nil;
static NSNull *null = nil;
#if defined(GNUSTEP)
static NSString *placeholder = nil;
#else
static Class stringClass = Nil;
static SEL allocStringSel = 0;
static IMP allocStringImp = 0;
#endif
static SEL initStringSel = 0;
static IMP initStringImp = 0;
static NSTimeZone *zones[47]; // For -23 to +23 hours
static inline NSString*
newString(const char *b, int l, NSStringEncoding e)
{
#if defined(GNUSTEP)
return (*initStringImp)(placeholder, initStringSel, b, l, e);
#else
NSString *s = (*allocStringImp)(stringClass, allocStringSel);
return (*initStringImp)(s, initStringSel, b, l, e);
#endif
}
static NSDate*
newDateFromBuffer(const char *b, 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;
}
@implementation SQLClientPostgres
+ (void) initialize
{
if (future == nil)
{
initStringSel = @selector(initWithBytes:length:encoding:);
#if defined(GNUSTEP)
placeholder = [NSString alloc];
initStringImp
= [[placeholder class] instanceMethodForSelector: initStringSel];
#else
stringClass = [NSString class];
allocStringSel = @selector(alloc);
allocStringImp = [stringClass methodForSelector: allocStringSel];
initStringImp = [stringClass instanceMethodForSelector: initStringSel];
#endif
future = [NSCalendarDate dateWithString: @"9999-01-01 00:00:00 +0000"
calendarFormat: @"%Y-%m-%d %H:%M:%S %z"
locale: nil];
@ -89,7 +268,8 @@ static NSTimeZone *zones[47]; // For -23 to +23 hours
[null retain];
for (int i = -23; i <= 23; i++)
{
zones[i + 23] = [[NSTimeZone timeZoneForSecondsFromGMT: i * 60 * 60] retain];
zones[i + 23]
= [[NSTimeZone timeZoneForSecondsFromGMT: i * 60 * 60] retain];
}
}
}
@ -529,7 +709,22 @@ static inline unsigned int trim(char *str, unsigned len)
}
if (len == (p - start))
{
v = [[NSString alloc] initWithUTF8String: start];
if ('T' == t)
{
/* This is expected to be a timestamp
*/
v = newDateFromBuffer(start, p - start);
}
else if ('D' == t)
{
/* This is expected to be bytea data
*/
v = [[self dataFromBLOB: start] retain];
}
else
{
v = newString(start, p - start, NSUTF8StringEncoding);
}
}
else
{
@ -549,7 +744,13 @@ static inline unsigned int trim(char *str, unsigned len)
buf[i++] = *ptr++;
}
buf[len] = '\0';
if ('D' == t)
if ('T' == t)
{
/* This is expected to be a timestamp
*/
v = newDateFromBuffer(buf, len);
}
else if ('D' == t)
{
/* This is expected to be bytea data
*/
@ -588,7 +789,7 @@ static inline unsigned int trim(char *str, unsigned len)
}
else if ('T' == t)
{
v = [[self dbToDateFromBuffer: start length: len] retain];
v = newDateFromBuffer(start, len);
}
else if ('D' == t)
{
@ -603,7 +804,7 @@ static inline unsigned int trim(char *str, unsigned len)
}
else
{
v = [[NSString alloc] initWithUTF8String: start];
v = newString(start, p - start, NSUTF8StringEncoding);
}
*p = save;
}
@ -631,17 +832,15 @@ static inline unsigned int trim(char *str, unsigned len)
switch (t)
{
case 1082: // Date
return [self newDateFromBuffer: p length: trim(p, s)];
return newDateFromBuffer(p, trim(p, s));
case 1083: // Time (treat as string)
s = trim(p, s);
return [[NSString alloc] initWithBytes: p
length: s
encoding: NSASCIIStringEncoding];
return newString(p, s, NSASCIIStringEncoding);
case 1114: // Timestamp without time zone.
case 1184: // Timestamp with time zone.
return [self newDateFromBuffer: p length: trim(p, s)];
return newDateFromBuffer(p, trim(p, s));
case 16: // BOOL
if (*p == 't')
@ -657,18 +856,13 @@ static inline unsigned int trim(char *str, unsigned len)
return [[self dataFromBLOB: p] retain];
case 18: // "char"
return [[NSString alloc] initWithBytes: p
length: s
encoding: NSUTF8StringEncoding];
return newString(p, s, NSUTF8StringEncoding);
case 20: // INT8
case 21: // INT2
case 23: // INT4
s = trim(p, s);
return [[NSString alloc] initWithBytes: p
length: s
encoding: NSASCIIStringEncoding];
break;
return newString(p, s, NSASCIIStringEncoding);
case 1182: // DATE ARRAY
case 1115: // TS without TZ ARRAY
@ -706,9 +900,7 @@ static inline unsigned int trim(char *str, unsigned len)
{
s = trim(p, s);
}
return [[NSString alloc] initWithBytes: p
length: s
encoding: NSUTF8StringEncoding];
return newString(p, s, NSUTF8StringEncoding);
}
}
@ -1229,151 +1421,6 @@ static inline unsigned int trim(char *str, unsigned len)
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)

View file

@ -229,6 +229,7 @@ main()
{
NSString *oddChars;
NSString *nonLatin;
id e1, e2, e3, e4, e5;
id r0;
id r1;
@ -249,6 +250,7 @@ main()
[db begin];
[db execute: @"create table xxx ( "
@"id int, "
@"k char(40), "
@"char1 char(1), "
@"boolval BOOL, "
@ -264,9 +266,9 @@ main()
@")",
nil];
if (1 != [db execute: @"insert into xxx (k, char1, boolval, intval,"
if (1 != [db execute: @"insert into xxx (id, k, char1, boolval, intval,"
@" when1, when2, b, extra1, extra2, extra3, extra4, extra5) "
@"values ("
@"values (1,"
@"'{hello', "
@"'X', "
@"TRUE, "
@ -275,23 +277,23 @@ main()
@"CURRENT_TIMESTAMP, ",
data, @", ",
[db quoteArray:
[NSArray arrayWithObjects: @"1", @"2", [NSNull null], nil]
(e1 = [NSArray arrayWithObjects: @"1", @"2", [NSNull null], nil])
toString: nil
quotingStrings: NO], @", ",
[db quoteArray:
[NSArray arrayWithObjects: @"on,e", @"t'wo", @"many", nil]
(e2 = [NSArray arrayWithObjects: @"on,e", @"t'wo", @"many", nil])
toString: nil
quotingStrings: YES], @", ",
[db quoteArray:
[NSArray arrayWithObjects: data, nil]
(e3 = [NSArray arrayWithObjects: data, nil])
toString: nil
quotingStrings: YES], @", ",
[db quoteArray:
[NSArray arrayWithObjects: @"TRUE", @"FALSE", nil]
(e4 =[NSArray arrayWithObjects: @"TRUE", @"FALSE", nil])
toString: nil
quotingStrings: NO], @", ",
[db quoteArray:
[NSArray arrayWithObjects: [NSDate date], nil]
(e5 = [NSArray arrayWithObjects: [NSDate date], nil])
toString: nil
quotingStrings: YES], @")",
nil])
@ -304,8 +306,8 @@ main()
[db setDebugging: 0];
[db execute: @"insert into xxx "
@"(k, char1, boolval, intval, when1, when2, b) "
@"values ("
@"(id, k, char1, boolval, intval, when1, when2, b) "
@"values (2,"
@"'hello', "
@"'X', "
@"TRUE, "
@ -316,8 +318,8 @@ main()
@")",
nil];
[db execute: @"insert into xxx "
@"(k, char1, boolval, intval, when1, when2, b) "
@"values (",
@"(id, k, char1, boolval, intval, when1, when2, b) "
@"values (3,",
[db quote: oddChars],
@", ",
[db quote: nonLatin],
@ -330,11 +332,11 @@ main()
nil];
[db commit];
r0 = [db cache: 1 query: @"select * from xxx", nil];
r1 = [db cache: 1 query: @"select * from xxx", nil];
r0 = [db cache: 1 query: @"select * from xxx order by id", nil];
r1 = [db cache: 1 query: @"select * from xxx order by id", nil];
NSCAssert([r0 lastObject] == [r1 lastObject], @"Cache failed");
[NSThread sleepForTimeInterval: 2.0];
records = [db cache: 1 query: @"select * from xxx", nil];
records = [db cache: 1 query: @"select * from xxx order by id", nil];
NSCAssert([r0 lastObject] != [records lastObject], @"Lifetime failed");
[db addObserver: l
@ -372,6 +374,50 @@ main()
{
NSLog(@"Retrieved odd chars (%@) does not match saved string (%@)", o, oddChars);
}
record = [records objectAtIndex: 0];
o = [record objectForKey: @"extra1"];
if ([o isEqual: e1] == NO)
{
NSLog(@"Retrieved extra1 (%@) does not match saved (%@)", o, e1);
}
o = [record objectForKey: @"extra2"];
if ([o isEqual: e2] == NO)
{
NSLog(@"Retrieved extra2 (%@) does not match saved (%@)", o, e2);
}
o = [record objectForKey: @"extra3"];
if ([o isEqual: e3] == NO)
{
NSLog(@"Retrieved extra3 (%@) does not match saved (%@)", o, e3);
}
o = [record objectForKey: @"extra4"];
if ([o count] != [e4 count])
{
NSLog(@"Retrieved extra4 (%@) does not match saved (%@)", o, e4);
}
for (int i = 0; i < [o count]; i++)
{
if ([[o objectAtIndex: i] boolValue]
!= [[e4 objectAtIndex: i] boolValue])
{
NSLog(@"Retrieved extra4 (%@) does not match saved (%@)",
o, e4);
}
}
o = [record objectForKey: @"extra5"];
if ([o count] != [e5 count])
{
NSLog(@"Retrieved extra5 (%@) does not match saved (%@)", o, e5);
}
for (int i = 0; i < [o count]; i++)
{
if (floor([[o objectAtIndex: i] timeIntervalSinceReferenceDate])
!= floor([[e5 objectAtIndex: i] timeIntervalSinceReferenceDate]))
{
NSLog(@"Retrieved extra5 (%@) does not match saved (%@)",
o, e5);
}
}
}
NSLog(@"Records - %@", [GSCache class]);