mirror of
https://github.com/gnustep/libs-sqlclient.git
synced 2025-02-15 16:11:42 +00:00
SQLRecord enhancements for KVC and for performance optimisations.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/sqlclient/trunk@24827 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
dd2ac4d9e6
commit
420fe259a8
9 changed files with 465 additions and 52 deletions
17
ChangeLog
17
ChangeLog
|
@ -1,3 +1,20 @@
|
|||
2007-03-08 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* SQLClient.h:
|
||||
* SQLClient.m:
|
||||
* MySQL.m:
|
||||
* ECPG.pgm:
|
||||
* Postgres.m:
|
||||
* Oracle.pm:
|
||||
* SQLite.m:
|
||||
* JDBC.m:
|
||||
Add KVC support for SQLRecord. Make SQLRecord into a class cluster
|
||||
with a single concrete implementation for now. Extend API to allow
|
||||
specifying of an alternative SQLRecord subclass when doing a query
|
||||
so that query results can be efficiently stored into custom subclasses
|
||||
rather than having to first be retrieved into an SQLRecord and then
|
||||
copied.
|
||||
|
||||
2007-02-14 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||
|
||||
* GNUmakefile (BUNDLE_INSTALL_DIR): Set using GNUSTEP_BUNDLES,
|
||||
|
|
8
ECPG.pgm
8
ECPG.pgm
|
@ -355,7 +355,7 @@ static unsigned int trim(char *str)
|
|||
return (str - start);
|
||||
}
|
||||
|
||||
- (NSMutableArray*) backendQuery: (NSString*)stmt
|
||||
- (NSMutableArray*) backendQuery: (NSString*)stmt recordClass: (Class)rClass
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
bool aBool;
|
||||
|
@ -597,9 +597,9 @@ static unsigned int trim(char *str)
|
|||
keys[index-1] = [NSString stringWithUTF8String:
|
||||
fieldName];
|
||||
}
|
||||
record = [SQLRecord newWithValues: values
|
||||
keys: keys
|
||||
count: count];
|
||||
record = [rClass newWithValues: values
|
||||
keys: keys
|
||||
count: count];
|
||||
[records addObject: record];
|
||||
RELEASE(record);
|
||||
}
|
||||
|
|
8
JDBC.m
8
JDBC.m
|
@ -1241,7 +1241,7 @@ static int JDBCVARCHAR = 0;
|
|||
DESTROY(arp);
|
||||
}
|
||||
|
||||
- (NSMutableArray*) backendQuery: (NSString*)stmt
|
||||
- (NSMutableArray*) backendQuery: (NSString*)stmt recordClass: (Class)rClass
|
||||
{
|
||||
NSMutableArray *records = nil;
|
||||
CREATE_AUTORELEASE_POOL(arp);
|
||||
|
@ -1474,9 +1474,9 @@ static int JDBCVARCHAR = 0;
|
|||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
record = [SQLRecord newWithValues: values
|
||||
keys: keys
|
||||
count: fieldCount];
|
||||
record = [rClass newWithValues: values
|
||||
keys: keys
|
||||
count: fieldCount];
|
||||
[records addObject: record];
|
||||
RELEASE(record);
|
||||
}
|
||||
|
|
8
MySQL.m
8
MySQL.m
|
@ -266,7 +266,7 @@ static unsigned int trim(char *str)
|
|||
return (str - start);
|
||||
}
|
||||
|
||||
- (NSMutableArray*) backendQuery: (NSString*)stmt
|
||||
- (NSMutableArray*) backendQuery: (NSString*)stmt recordClass: (Class)rClass
|
||||
{
|
||||
CREATE_AUTORELEASE_POOL(arp);
|
||||
NSMutableArray *records = nil;
|
||||
|
@ -412,9 +412,9 @@ static unsigned int trim(char *str)
|
|||
}
|
||||
values[j] = v;
|
||||
}
|
||||
record = [SQLRecord newWithValues: values
|
||||
keys: keys
|
||||
count: fieldCount];
|
||||
record = [rClass newWithValues: values
|
||||
keys: keys
|
||||
count: fieldCount];
|
||||
[records addObject: record];
|
||||
RELEASE(record);
|
||||
}
|
||||
|
|
|
@ -326,7 +326,7 @@ static unsigned int trim(char *str)
|
|||
return (str - start);
|
||||
}
|
||||
|
||||
- (NSMutableArray*) backendQuery: (NSString*)stmt
|
||||
- (NSMutableArray*) backendQuery: (NSString*)stmt recordClass: (Class)rClass
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
int count;
|
||||
|
@ -597,9 +597,9 @@ static unsigned int trim(char *str)
|
|||
keys[index - 1] = [NSString stringWithUTF8String:
|
||||
fieldName];
|
||||
}
|
||||
record = [SQLRecord newWithValues: values
|
||||
keys: keys
|
||||
count: count];
|
||||
record = [rClass newWithValues: values
|
||||
keys: keys
|
||||
count: count];
|
||||
[records addObject: record];
|
||||
RELEASE(record);
|
||||
}
|
||||
|
|
|
@ -363,7 +363,7 @@ static unsigned int trim(char *str)
|
|||
return (str - start);
|
||||
}
|
||||
|
||||
- (NSMutableArray*) backendQuery: (NSString*)stmt
|
||||
- (NSMutableArray*) backendQuery: (NSString*)stmt recordClass: (Class)rClass
|
||||
{
|
||||
CREATE_AUTORELEASE_POOL(arp);
|
||||
PGresult *result = 0;
|
||||
|
@ -490,9 +490,9 @@ static unsigned int trim(char *str)
|
|||
}
|
||||
values[j] = v;
|
||||
}
|
||||
record = [SQLRecord newWithValues: values
|
||||
keys: keys
|
||||
count: fieldCount];
|
||||
record = [rClass newWithValues: values
|
||||
keys: keys
|
||||
count: fieldCount];
|
||||
[records addObject: record];
|
||||
RELEASE(record);
|
||||
}
|
||||
|
|
127
SQLClient.h
127
SQLClient.h
|
@ -188,15 +188,17 @@
|
|||
@class SQLTransaction;
|
||||
|
||||
/**
|
||||
* An enhanced array to represent a record returned from a query.
|
||||
* <p>An enhanced array to represent a record returned from a query.
|
||||
* You should <em>NOT</em> try to create instances of this class
|
||||
* except via the +newWithValues:keys:count: method.
|
||||
* </p>
|
||||
* <p>NB. SQLRecord is the abstract base class of a class cluster.
|
||||
* If you wish to subclass it you must implement the primitive methods
|
||||
* +newWithValues:keys:count: -count -keyAtIndex: -objectAtIndex:
|
||||
* and -replaceObjectAtIndex:withObject:
|
||||
* </p>
|
||||
*/
|
||||
@interface SQLRecord : NSArray
|
||||
{
|
||||
@private
|
||||
unsigned int count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SQLRecord containing the specified fields.<br />
|
||||
|
@ -212,23 +214,50 @@
|
|||
*/
|
||||
- (NSArray*) allKeys;
|
||||
|
||||
/**
|
||||
* Returns the number of items in the record.<br />
|
||||
* Subclasses must implement this method.
|
||||
*/
|
||||
- (unsigned) count;
|
||||
|
||||
/**
|
||||
* Return the record as a mutable dictionary with the keys as the
|
||||
* record field names standardised to be lowercase strings.
|
||||
*/
|
||||
- (NSMutableDictionary*) dictionary;
|
||||
|
||||
/**
|
||||
* Optimised mechanism for retrieving all keys in order.
|
||||
*/
|
||||
- (void) getKeys: (id*)buf;
|
||||
|
||||
/**
|
||||
* Optimised mechanism for retrieving all objects.
|
||||
*/
|
||||
- (void) getObjects: (id*)buf;
|
||||
|
||||
/** <override-subclass />
|
||||
* Returns the key at the specified indes.<br />
|
||||
*/
|
||||
- (NSString*) keyAtIndex: (unsigned)index;
|
||||
|
||||
/** <override-subclass />
|
||||
* Returns the object at the specified indes.<br />
|
||||
*/
|
||||
- (id) objectAtIndex: (unsigned)index;
|
||||
|
||||
/**
|
||||
* Returns the value of the named field.<br />
|
||||
* The field name is case insensitive.
|
||||
*/
|
||||
- (id) objectForKey: (NSString*)key;
|
||||
|
||||
/**
|
||||
* Replaces the value at the specified index.<br />
|
||||
* Subclasses must implement this method.
|
||||
*/
|
||||
- (void) replaceObjectAtIndex: (unsigned)index withObject: (id)anObject;
|
||||
|
||||
/**
|
||||
* Replaces the value of the named field.<br />
|
||||
* The field name is case insensitive.<br />
|
||||
|
@ -400,6 +429,49 @@ extern unsigned SQLClientTimeTick();
|
|||
*/
|
||||
- (void) begin;
|
||||
|
||||
/**
|
||||
* <p>Build an sql query string using the supplied arguments.
|
||||
* </p>
|
||||
* <p>This method has at least one argument, the string starting the
|
||||
* query to be executed (which must have the prefix 'select ').
|
||||
* </p>
|
||||
* <p>Additional arguments are a nil terminated list which also be strings,
|
||||
* and these are appended to the statement.<br />
|
||||
* Any string arguments are assumed to have been quoted appropriately
|
||||
* already, but non-string arguments are automatically quoted using the
|
||||
* -quote: method.
|
||||
* </p>
|
||||
* <example>
|
||||
* sql = [db buildQuery: @"SELECT Name FROM ", table, nil];
|
||||
* </example>
|
||||
* <p>Upon error, an exception is raised.
|
||||
* </p>
|
||||
* <p>The method returns a string containing sql suitable for passing to
|
||||
* the -simpleQuery:recordClass: or -cache:simpleQuery:recordClass: methods.
|
||||
* </p>
|
||||
*/
|
||||
- (NSString*) buildQuery: (NSString*)stmt,...;
|
||||
|
||||
/**
|
||||
* Takes the query statement and substitutes in values from
|
||||
* the dictionary where markup of the format {key} is found.<br />
|
||||
* Returns the resulting query string.
|
||||
* <example>
|
||||
* sql = [db buildQuery: @"SELECT Name FROM {Table} WHERE ID = {ID}"
|
||||
* with: values];
|
||||
* </example>
|
||||
* <p>Any non-string values in the dictionary will be replaced by
|
||||
* the results of the -quote: method.<br />
|
||||
* The markup format may also be {key?default} where <em>default</em>
|
||||
* is a string to be used if there is no value for the <em>key</em>
|
||||
* in the dictionary.
|
||||
* </p>
|
||||
* <p>The method returns a string containing sql suitable for passing to
|
||||
* the -simpleQuery:recordClass: or -cache:simpleQuery:recordClass: methods.
|
||||
* </p>
|
||||
*/
|
||||
- (NSString*) buildQuery: (NSString*)stmt with: (NSDictionary*)values;
|
||||
|
||||
/**
|
||||
* Return the client name for this instance.<br />
|
||||
* Normally this is useful only for debugging/reporting purposes, but
|
||||
|
@ -548,14 +620,8 @@ extern unsigned SQLClientTimeTick();
|
|||
/**
|
||||
* <p>Perform arbitrary query <em>which returns values.</em>
|
||||
* </p>
|
||||
* <p>This method has at least one argument, the string starting the
|
||||
* statement to be executed (which must have the prefix 'select ').
|
||||
* </p>
|
||||
* <p>Additional arguments are a nil terminated list which also be strings,
|
||||
* and these are appended to the statement.<br />
|
||||
* Any string arguments are assumed to have been quoted appropriately
|
||||
* already, but non-string arguments are automatically quoted using the
|
||||
* -quote: method.
|
||||
* <p>This method handles its arguments in the same way as the -buildQuery:,...
|
||||
* method and returns the result of the query.
|
||||
* </p>
|
||||
* <example>
|
||||
* result = [db query: @"SELECT Name FROM ", table, nil];
|
||||
|
@ -579,8 +645,8 @@ extern unsigned SQLClientTimeTick();
|
|||
|
||||
/**
|
||||
* Takes the query statement and substitutes in values from
|
||||
* the dictionary where markup of the format {key} is found.<br />
|
||||
* Passes the result to the -query:,... method to execute.
|
||||
* the dictionary (in the same manner as the -buildQuery:with: method)
|
||||
* then executes the query and returns the response.<br />
|
||||
* <example>
|
||||
* result = [db query: @"SELECT Name FROM {Table} WHERE ID = {ID}"
|
||||
* with: values];
|
||||
|
@ -702,11 +768,16 @@ extern unsigned SQLClientTimeTick();
|
|||
- (void) simpleExecute: (NSArray*)info;
|
||||
|
||||
/**
|
||||
* Calls -backendQuery: in a safe manner.<br />
|
||||
* Calls -simpleQuery:recordClass: with the default record class.
|
||||
*/
|
||||
- (NSMutableArray*) simpleQuery: (NSString*)stmt;
|
||||
|
||||
/**
|
||||
* Calls -backendQuery:recordClass: in a safe manner.<br />
|
||||
* Handles locking.<br />
|
||||
* Maintains -lastOperation date.
|
||||
*/
|
||||
- (NSMutableArray*) simpleQuery: (NSString*)stmt;
|
||||
- (NSMutableArray*) simpleQuery: (NSString*)stmt recordClass: (Class)cls;
|
||||
|
||||
/**
|
||||
* Return the database user for this instance (or nil).
|
||||
|
@ -802,7 +873,8 @@ extern unsigned SQLClientTimeTick();
|
|||
* <p>Perform arbitrary query <em>which returns values.</em>
|
||||
* </p>
|
||||
* <example>
|
||||
* result = [db backendQuery: @"SELECT Name FROM Table"];
|
||||
* result = [db backendQuery: @"SELECT Name FROM Table"
|
||||
* recordClass: [SQLRecord class]];
|
||||
* </example>
|
||||
* <p>Upon error, an exception is raised.
|
||||
* </p>
|
||||
|
@ -821,6 +893,16 @@ extern unsigned SQLClientTimeTick();
|
|||
* <p>Application code must <em>not</em> call this method directly, it is
|
||||
* for internal use only.
|
||||
* </p>
|
||||
* <p>The cls argument specifies a subclass of [SQLRecord] to be used to
|
||||
* create the records produced by the query.<br />
|
||||
* This is provided as a performance optimisation when you want to store
|
||||
* data directly into a special class of your own.
|
||||
* </p>
|
||||
*/
|
||||
- (NSMutableArray*) backendQuery: (NSString*)stmt recordClass: (Class)cls;
|
||||
|
||||
/**
|
||||
* Calls -backendQuery:recordClass: with the default record class.
|
||||
*/
|
||||
- (NSMutableArray*) backendQuery: (NSString*)stmt;
|
||||
|
||||
|
@ -1015,6 +1097,11 @@ extern unsigned SQLClientTimeTick();
|
|||
query: (NSString*)stmt
|
||||
with: (NSDictionary*)values;
|
||||
|
||||
/**
|
||||
* Calls -cache:simpleQuery:recordClass: with the default record class.
|
||||
*/
|
||||
- (NSMutableArray*) cache: (int)seconds simpleQuery: (NSString*)stmt;
|
||||
|
||||
/**
|
||||
* If the result of the query is already cached and is still valid,
|
||||
* return it. Otherwise, perform the query and cache the result
|
||||
|
@ -1026,7 +1113,9 @@ extern unsigned SQLClientTimeTick();
|
|||
* Handles locking.<br />
|
||||
* Maintains -lastOperation date.
|
||||
*/
|
||||
- (NSMutableArray*) cache: (int)seconds simpleQuery: (NSString*)stmt;
|
||||
- (NSMutableArray*) cache: (int)seconds
|
||||
simpleQuery: (NSString*)stmt
|
||||
recordClass: (Class)cls;
|
||||
|
||||
/**
|
||||
* Sets the cache to be used by the receiver for storing the results of
|
||||
|
|
325
SQLClient.m
325
SQLClient.m
|
@ -285,6 +285,9 @@ typedef struct {
|
|||
@defs(SQLTransaction);
|
||||
} *TDefs;
|
||||
|
||||
@class _SQLRecord;
|
||||
static Class rClass = 0;
|
||||
|
||||
@implementation SQLRecord
|
||||
+ (id) allocWithZone: (NSZone*)aZone
|
||||
{
|
||||
|
@ -298,16 +301,226 @@ typedef struct {
|
|||
if (null == nil)
|
||||
{
|
||||
null = [NSNull new];
|
||||
rClass = [_SQLRecord class];
|
||||
}
|
||||
}
|
||||
|
||||
+ (id) newWithValues: (id*)v keys: (NSString**)k count: (unsigned int)c
|
||||
{
|
||||
return [rClass newWithValues: v keys: k count: c];
|
||||
}
|
||||
|
||||
- (NSArray*) allKeys
|
||||
{
|
||||
unsigned count = [self count];
|
||||
id buf[count];
|
||||
|
||||
while (count-- > 0)
|
||||
{
|
||||
buf[count] = [self keyAtIndex: count];
|
||||
}
|
||||
return [NSArray arrayWithObjects: buf count: count];
|
||||
}
|
||||
|
||||
- (id) copyWithZone: (NSZone*)z
|
||||
{
|
||||
return RETAIN(self);
|
||||
}
|
||||
|
||||
- (unsigned int) count
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary*) dictionary
|
||||
{
|
||||
unsigned count = [self count];
|
||||
id keys[count];
|
||||
id vals[count];
|
||||
|
||||
[self getKeys: keys];
|
||||
[self getObjects: vals];
|
||||
return [NSMutableDictionary dictionaryWithObjects: vals
|
||||
forKeys: keys
|
||||
count: count];
|
||||
}
|
||||
|
||||
- (void) getKeys: (id*)buf
|
||||
{
|
||||
unsigned i = [self count];
|
||||
|
||||
while (i-- > 0)
|
||||
{
|
||||
buf[i] = [self keyAtIndex: i];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) getObjects: (id*)buf
|
||||
{
|
||||
unsigned i = [self count];
|
||||
|
||||
while (i-- > 0)
|
||||
{
|
||||
buf[i] = [self objectAtIndex: i];
|
||||
}
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
NSLog(@"Illegal attempt to -init an SQLRecord");
|
||||
DESTROY(self);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString*) keyAtIndex: (unsigned int)pos
|
||||
{
|
||||
return [self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
- (id) objectAtIndex: (unsigned int)pos
|
||||
{
|
||||
return [self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
- (id) objectForKey: (NSString*)key
|
||||
{
|
||||
unsigned count = [self count];
|
||||
unsigned pos;
|
||||
id keys[count];
|
||||
|
||||
[self getKeys: keys];
|
||||
for (pos = 0; pos < count; pos++)
|
||||
{
|
||||
if ([key isEqualToString: keys[pos]] == YES)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pos == count)
|
||||
{
|
||||
for (pos = 0; pos < count; pos++)
|
||||
{
|
||||
if ([key caseInsensitiveCompare: keys[pos]] == NSOrderedSame)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pos == count)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
return [self objectAtIndex: pos];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) replaceObjectAtIndex: (unsigned)index withObject: (id)anObject
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
- (void) setObject: (id)anObject forKey: (NSString*)aKey
|
||||
{
|
||||
unsigned count = [self count];
|
||||
unsigned pos;
|
||||
id keys[count];
|
||||
|
||||
if (anObject == nil)
|
||||
{
|
||||
anObject = null;
|
||||
}
|
||||
[self getKeys: keys];
|
||||
for (pos = 0; pos < count; pos++)
|
||||
{
|
||||
if ([aKey isEqualToString: keys[pos]] == YES)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pos == count)
|
||||
{
|
||||
for (pos = 0; pos < count; pos++)
|
||||
{
|
||||
if ([aKey caseInsensitiveCompare: keys[pos]] == NSOrderedSame)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pos == count)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Bad key (%@) in -setObject:forKey:", aKey];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self replaceObjectAtIndex: pos withObject: anObject];
|
||||
}
|
||||
}
|
||||
|
||||
- (unsigned) sizeInBytes: (NSMutableSet*)exclude
|
||||
{
|
||||
if ([exclude member: self] != nil)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned size = [super sizeInBytes: exclude];
|
||||
unsigned pos;
|
||||
unsigned count = [self count];
|
||||
id vals[count];
|
||||
|
||||
[self getObjects: vals];
|
||||
for (pos = 0; pos < count; pos++)
|
||||
{
|
||||
size += [vals[pos] sizeInBytes: exclude];
|
||||
}
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation SQLRecord (KVC)
|
||||
- (void) setValue: (id)aValue forKey: (NSString*)aKey
|
||||
{
|
||||
[self setObject: aValue forKey: aKey];
|
||||
}
|
||||
- (id) valueForKey: (NSString*)aKey
|
||||
{
|
||||
id v = [self objectForKey: aKey];
|
||||
|
||||
if (v == nil)
|
||||
{
|
||||
v = [super valueForKey: aKey];
|
||||
}
|
||||
return v;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@interface _SQLRecord : SQLRecord
|
||||
{
|
||||
unsigned count;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation _SQLRecord
|
||||
|
||||
+ (id) newWithValues: (id*)v keys: (NSString**)k count: (unsigned int)c
|
||||
{
|
||||
id *ptr;
|
||||
SQLRecord *r;
|
||||
_SQLRecord *r;
|
||||
unsigned pos;
|
||||
|
||||
r = (SQLRecord*)NSAllocateObject(self, c*2*sizeof(id), NSDefaultMallocZone());
|
||||
r = (_SQLRecord*)NSAllocateObject(self,
|
||||
c*2*sizeof(id), NSDefaultMallocZone());
|
||||
r->count = c;
|
||||
ptr = ((void*)&(r->count)) + sizeof(r->count);
|
||||
for (pos = 0; pos < c; pos++)
|
||||
|
@ -372,6 +585,19 @@ typedef struct {
|
|||
return d;
|
||||
}
|
||||
|
||||
- (void) getKeys: (id*)buf
|
||||
{
|
||||
id *ptr;
|
||||
unsigned pos;
|
||||
|
||||
ptr = ((void*)&count) + sizeof(count);
|
||||
ptr += count; // Step past objects to keys.
|
||||
for (pos = 0; pos < count; pos++)
|
||||
{
|
||||
buf[pos] = ptr[pos];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) getObjects: (id*)buf
|
||||
{
|
||||
id *ptr;
|
||||
|
@ -391,6 +617,20 @@ typedef struct {
|
|||
return self;
|
||||
}
|
||||
|
||||
- (id) keyAtIndex: (unsigned int)pos
|
||||
{
|
||||
id *ptr;
|
||||
|
||||
if (pos >= count)
|
||||
{
|
||||
[NSException raise: NSRangeException
|
||||
format: @"Array index too large"];
|
||||
}
|
||||
ptr = ((void*)&count) + sizeof(count);
|
||||
ptr += count;
|
||||
return ptr[pos];
|
||||
}
|
||||
|
||||
- (id) objectAtIndex: (unsigned int)pos
|
||||
{
|
||||
id *ptr;
|
||||
|
@ -427,6 +667,24 @@ typedef struct {
|
|||
return nil;
|
||||
}
|
||||
|
||||
- (void) replaceObjectAtIndex: (unsigned)index withObject: (id)anObject
|
||||
{
|
||||
id *ptr;
|
||||
|
||||
if (index >= count)
|
||||
{
|
||||
[NSException raise: NSRangeException
|
||||
format: @"Array index too large"];
|
||||
}
|
||||
if (anObject == nil)
|
||||
{
|
||||
anObject = null;
|
||||
}
|
||||
ptr = ((void*)&count) + sizeof(count);
|
||||
ptr += index;
|
||||
ASSIGN(*ptr, anObject);
|
||||
}
|
||||
|
||||
- (void) setObject: (id)anObject forKey: (NSString*)aKey
|
||||
{
|
||||
id *ptr;
|
||||
|
@ -643,10 +901,7 @@ static unsigned int maxConnections = 8;
|
|||
+ (void) initialize
|
||||
{
|
||||
GSTickerTimeNow();
|
||||
if (null == nil)
|
||||
{
|
||||
null = [NSNull new];
|
||||
}
|
||||
[SQLRecord class]; // Force initialisation
|
||||
if (clientsMap == 0)
|
||||
{
|
||||
clientsMap = NSCreateMapTable(NSObjectMapKeyCallBacks,
|
||||
|
@ -770,6 +1025,30 @@ static unsigned int maxConnections = 8;
|
|||
}
|
||||
}
|
||||
|
||||
- (NSString*) buildQuery: (NSString*)stmt, ...
|
||||
{
|
||||
va_list ap;
|
||||
NSString *sql = nil;
|
||||
|
||||
/*
|
||||
* First check validity and concatenate parts of the query.
|
||||
*/
|
||||
va_start (ap, stmt);
|
||||
sql = [[self _prepare: stmt args: ap] objectAtIndex: 0];
|
||||
va_end (ap);
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
- (NSString*) buildQuery: (NSString*)stmt with: (NSDictionary*)values
|
||||
{
|
||||
NSString *sql = nil;
|
||||
|
||||
sql = [[self _substitute: stmt with: values] objectAtIndex: 0];
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
- (NSString*) clientName
|
||||
{
|
||||
return _client;
|
||||
|
@ -1447,9 +1726,19 @@ static unsigned int maxConnections = 8;
|
|||
}
|
||||
|
||||
- (NSMutableArray*) simpleQuery: (NSString*)stmt
|
||||
{
|
||||
return [self simpleQuery: stmt recordClass: rClass];
|
||||
}
|
||||
|
||||
- (NSMutableArray*) simpleQuery: (NSString*)stmt recordClass: (Class)cls
|
||||
{
|
||||
NSMutableArray *result = nil;
|
||||
|
||||
if (cls == 0)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"nil class passed to simpleQuery:recordClass:"];
|
||||
}
|
||||
[lock lock];
|
||||
NS_DURING
|
||||
{
|
||||
|
@ -1459,7 +1748,7 @@ static unsigned int maxConnections = 8;
|
|||
{
|
||||
start = GSTickerTimeNow();
|
||||
}
|
||||
result = [self backendQuery: stmt];
|
||||
result = [self backendQuery: stmt recordClass: cls];
|
||||
_lastOperation = GSTickerTimeNow();
|
||||
if (_duration >= 0)
|
||||
{
|
||||
|
@ -1514,6 +1803,11 @@ static unsigned int maxConnections = 8;
|
|||
}
|
||||
|
||||
- (NSMutableArray*) backendQuery: (NSString*)stmt
|
||||
{
|
||||
return [self backendQuery: stmt recordClass: rClass];
|
||||
}
|
||||
|
||||
- (NSMutableArray*) backendQuery: (NSString*)stmt recordClass: (Class)cls
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"Called -%@ without backend bundle loaded",
|
||||
|
@ -2126,10 +2420,23 @@ static unsigned int maxConnections = 8;
|
|||
return [self cache: seconds simpleQuery: stmt];
|
||||
}
|
||||
|
||||
- (NSMutableArray*) cache: (int)seconds simpleQuery: (NSString*)stmt
|
||||
- (NSMutableArray*) cache: (int)seconds
|
||||
simpleQuery: (NSString*)stmt
|
||||
{
|
||||
return [self cache: seconds simpleQuery: stmt recordClass: rClass];
|
||||
}
|
||||
|
||||
- (NSMutableArray*) cache: (int)seconds
|
||||
simpleQuery: (NSString*)stmt
|
||||
recordClass: (Class)cls
|
||||
{
|
||||
NSMutableArray *result = nil;
|
||||
|
||||
if (cls == 0)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"nil class passed to cache:simpleQuery:recordClass:"];
|
||||
}
|
||||
[lock lock];
|
||||
NS_DURING
|
||||
{
|
||||
|
@ -2148,7 +2455,7 @@ static unsigned int maxConnections = 8;
|
|||
|
||||
if (result == nil)
|
||||
{
|
||||
result = toCache = [self backendQuery: stmt];
|
||||
result = toCache = [self backendQuery: stmt recordClass: cls];
|
||||
_lastOperation = GSTickerTimeNow();
|
||||
if (_duration >= 0)
|
||||
{
|
||||
|
|
8
SQLite.m
8
SQLite.m
|
@ -194,7 +194,7 @@
|
|||
DESTROY(arp);
|
||||
}
|
||||
|
||||
- (NSMutableArray*) backendQuery: (NSString*)stmt
|
||||
- (NSMutableArray*) backendQuery: (NSString*)stmt recordClass: (Class)rClass
|
||||
{
|
||||
CREATE_AUTORELEASE_POOL(arp);
|
||||
NSMutableArray *records = [[NSMutableArray alloc] init];
|
||||
|
@ -281,9 +281,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
record = [SQLRecord newWithValues: values
|
||||
keys: keys
|
||||
count: columns];
|
||||
record = [rClass newWithValues: values
|
||||
keys: keys
|
||||
count: columns];
|
||||
[records addObject: record];
|
||||
RELEASE(record);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue