mirror of
https://github.com/gnustep/libs-sqlclient.git
synced 2025-02-20 18:32:06 +00:00
Another new method for pools and transactions
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/sqlclient/trunk@38718 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
ba050a9adf
commit
603235b671
4 changed files with 191 additions and 189 deletions
|
@ -5,6 +5,7 @@
|
|||
* SQLClientPool.m:
|
||||
Implement another missing convenience method.
|
||||
Fix locking error when executing a batch.
|
||||
Add -prepare:with: method for use by transactions.
|
||||
|
||||
2015-06-27 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
|
|
|
@ -790,6 +790,11 @@ SQLCLIENT_PRIVATE
|
|||
*/
|
||||
- (NSMutableArray*) prepare: (NSString*)stmt args: (va_list)args;
|
||||
|
||||
/** This method is like -prepare:args: but takes a dictionary of
|
||||
* values to be substituted into the sql string.
|
||||
*/
|
||||
- (NSMutableArray*) prepare: (NSString*)stmt with: (NSDictionary*)values;
|
||||
|
||||
/**
|
||||
* <p>Perform arbitrary query <em>which returns values.</em>
|
||||
* </p>
|
||||
|
@ -1737,6 +1742,7 @@ SQLCLIENT_PRIVATE
|
|||
- (NSInteger) execute: (NSString*)stmt,...;
|
||||
- (NSInteger) execute: (NSString*)stmt with: (NSDictionary*)values;
|
||||
- (NSMutableArray*) prepare: (NSString*)stmt args: (va_list)args;
|
||||
- (NSMutableArray*) prepare: (NSString*)stmt with: (NSDictionary*)values;
|
||||
- (NSMutableArray*) query: (NSString*)stmt,...;
|
||||
- (NSMutableArray*) query: (NSString*)stmt with: (NSDictionary*)values;
|
||||
- (SQLRecord*) queryRecord: (NSString*)stmt,...;
|
||||
|
|
368
SQLClient.m
368
SQLClient.m
|
@ -776,16 +776,6 @@ static NSArray *rollbackStatement = nil;
|
|||
*/
|
||||
- (void) _recordMainThread;
|
||||
|
||||
/**
|
||||
* Internal method to substitute values from the dictionary into
|
||||
* a string containing markup identifying where the values should
|
||||
* appear by name. Non-string objects in the dictionary are quoted.<br />
|
||||
* Returns an array containing the statement as the first object and
|
||||
* any NSData objects following. The NSData objects appear in the
|
||||
* statement strings as the marker sequence - <code>'?'''?'</code>
|
||||
*/
|
||||
- (NSMutableArray*) _substitute: (NSString*)str with: (NSDictionary*)vals;
|
||||
|
||||
/*
|
||||
* Called at one second intervals to ensure that our current timestamp
|
||||
* is reasonably accurate.
|
||||
|
@ -1086,7 +1076,7 @@ static int poolConnections = 0;
|
|||
{
|
||||
NSString *sql = nil;
|
||||
|
||||
sql = [[self _substitute: stmt with: values] objectAtIndex: 0];
|
||||
sql = [[self prepare: stmt with: values] objectAtIndex: 0];
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
@ -1352,7 +1342,7 @@ static int poolConnections = 0;
|
|||
{
|
||||
NSArray *info;
|
||||
|
||||
info = [self _substitute: stmt with: values];
|
||||
info = [self prepare: stmt with: values];
|
||||
return [self simpleExecute: info];
|
||||
}
|
||||
|
||||
|
@ -1594,6 +1584,180 @@ static int poolConnections = 0;
|
|||
return ma;
|
||||
}
|
||||
|
||||
- (NSMutableArray*) prepare: (NSString*)stmt with: (NSDictionary*)values
|
||||
{
|
||||
unsigned int l = [stmt length];
|
||||
NSRange r;
|
||||
NSMutableArray *ma = [NSMutableArray arrayWithCapacity: 2];
|
||||
NSAutoreleasePool *arp = [NSAutoreleasePool new];
|
||||
|
||||
if (l < 2)
|
||||
{
|
||||
[ma addObject: stmt]; // Can't contain a {...} sequence
|
||||
}
|
||||
else if ((r = [stmt rangeOfString: @"{"]).length == 0)
|
||||
{
|
||||
[ma addObject: stmt]; // No '{' markup
|
||||
}
|
||||
else if (l - r.location < 2)
|
||||
{
|
||||
[ma addObject: stmt]; // Can't contain a {...} sequence
|
||||
}
|
||||
else if ([stmt rangeOfString: @"}" options: NSLiteralSearch
|
||||
range: NSMakeRange(r.location, l - r.location)].length == 0
|
||||
&& [stmt rangeOfString: @"{{" options: NSLiteralSearch
|
||||
range: NSMakeRange(0, l)].length == 0)
|
||||
{
|
||||
[ma addObject: stmt]; // No closing '}' or repeated '{{'
|
||||
}
|
||||
else if (r.length == 0)
|
||||
{
|
||||
[ma addObject: stmt]; // Nothing to do.
|
||||
}
|
||||
else
|
||||
{
|
||||
NSMutableString *mtext = [[stmt mutableCopy] autorelease];
|
||||
|
||||
/*
|
||||
* Replace {FieldName} with the value of the field
|
||||
*/
|
||||
while (r.length > 0)
|
||||
{
|
||||
unsigned pos = r.location;
|
||||
unsigned nxt;
|
||||
unsigned vLength;
|
||||
NSArray *a;
|
||||
NSRange s;
|
||||
NSString *v;
|
||||
NSString *alt;
|
||||
id o;
|
||||
unsigned i;
|
||||
|
||||
r.length = l - pos;
|
||||
|
||||
/*
|
||||
* If the length of the string from the '{' onwards is less than two,
|
||||
* there is nothing to do and we can end processing.
|
||||
*/
|
||||
if (r.length < 2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ([mtext characterAtIndex: r.location + 1] == '{')
|
||||
{
|
||||
// Got '{{' ... remove one of them.
|
||||
r.length = 1;
|
||||
[mtext replaceCharactersInRange: r withString: @""];
|
||||
l--;
|
||||
r.location++;
|
||||
r.length = l - r.location;
|
||||
r = [mtext rangeOfString: @"{"
|
||||
options: NSLiteralSearch
|
||||
range: r];
|
||||
continue;
|
||||
}
|
||||
|
||||
r = [mtext rangeOfString: @"}"
|
||||
options: NSLiteralSearch
|
||||
range: r];
|
||||
if (r.length == 0)
|
||||
{
|
||||
break; // No closing bracket
|
||||
}
|
||||
nxt = NSMaxRange(r);
|
||||
r = NSMakeRange(pos, nxt - pos);
|
||||
s.location = r.location + 1;
|
||||
s.length = r.length - 2;
|
||||
v = [mtext substringWithRange: s];
|
||||
|
||||
/*
|
||||
* If the value contains a '?', it is actually in two parts,
|
||||
* the first part is the field name, and the second part is
|
||||
* an alternative text to be used if the value from the
|
||||
* dictionary is empty.
|
||||
*/
|
||||
s = [v rangeOfString: @"?"];
|
||||
if (s.length == 0)
|
||||
{
|
||||
alt = @""; // No alternative value.
|
||||
}
|
||||
else
|
||||
{
|
||||
alt = [v substringFromIndex: NSMaxRange(s)];
|
||||
v = [v substringToIndex: s.location];
|
||||
}
|
||||
|
||||
/*
|
||||
* If the value we are substituting contains dots, we split it apart.
|
||||
* We use the value to make a reference into the dictionary we are
|
||||
* given.
|
||||
*/
|
||||
a = [v componentsSeparatedByString: @"."];
|
||||
o = values;
|
||||
for (i = 0; i < [a count]; i++)
|
||||
{
|
||||
NSString *k = [a objectAtIndex: i];
|
||||
|
||||
if ([k length] > 0)
|
||||
{
|
||||
o = [(NSDictionary*)o objectForKey: k];
|
||||
}
|
||||
}
|
||||
if (o == values)
|
||||
{
|
||||
v = nil; // Mo match found.
|
||||
}
|
||||
else
|
||||
{
|
||||
if ([o isKindOfClass: NSStringClass] == YES)
|
||||
{
|
||||
v = (NSString*)o;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ([o isKindOfClass: [NSData class]] == YES)
|
||||
{
|
||||
[ma addObject: o];
|
||||
v = @"'?'''?'";
|
||||
}
|
||||
else
|
||||
{
|
||||
v = [self quote: o];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ([v length] == 0)
|
||||
{
|
||||
v = alt;
|
||||
if (v == nil)
|
||||
{
|
||||
v = @"";
|
||||
}
|
||||
}
|
||||
vLength = [v length];
|
||||
|
||||
[mtext replaceCharactersInRange: r withString: v];
|
||||
l += vLength; // Add length of string inserted
|
||||
l -= r.length; // Remove length of string replaced
|
||||
r.location += vLength;
|
||||
|
||||
if (r.location >= l)
|
||||
{
|
||||
break;
|
||||
}
|
||||
r.length = l - r.location;
|
||||
r = [mtext rangeOfString: @"{"
|
||||
options: NSLiteralSearch
|
||||
range: r];
|
||||
}
|
||||
[ma insertObject: mtext atIndex: 0];
|
||||
}
|
||||
[arp release];
|
||||
return ma;
|
||||
}
|
||||
|
||||
- (NSMutableArray*) query: (NSString*)stmt, ...
|
||||
{
|
||||
va_list ap;
|
||||
|
@ -1615,7 +1779,7 @@ static int poolConnections = 0;
|
|||
{
|
||||
NSMutableArray *result = nil;
|
||||
|
||||
stmt = [[self _substitute: stmt with: values] objectAtIndex: 0];
|
||||
stmt = [[self prepare: stmt with: values] objectAtIndex: 0];
|
||||
|
||||
result = [self simpleQuery: stmt];
|
||||
|
||||
|
@ -2514,180 +2678,6 @@ static int poolConnections = 0;
|
|||
mainThread = [NSThread currentThread];
|
||||
}
|
||||
|
||||
- (NSMutableArray*) _substitute: (NSString*)str with: (NSDictionary*)vals
|
||||
{
|
||||
unsigned int l = [str length];
|
||||
NSRange r;
|
||||
NSMutableArray *ma = [NSMutableArray arrayWithCapacity: 2];
|
||||
NSAutoreleasePool *arp = [NSAutoreleasePool new];
|
||||
|
||||
if (l < 2)
|
||||
{
|
||||
[ma addObject: str]; // Can't contain a {...} sequence
|
||||
}
|
||||
else if ((r = [str rangeOfString: @"{"]).length == 0)
|
||||
{
|
||||
[ma addObject: str]; // No '{' markup
|
||||
}
|
||||
else if (l - r.location < 2)
|
||||
{
|
||||
[ma addObject: str]; // Can't contain a {...} sequence
|
||||
}
|
||||
else if ([str rangeOfString: @"}" options: NSLiteralSearch
|
||||
range: NSMakeRange(r.location, l - r.location)].length == 0
|
||||
&& [str rangeOfString: @"{{" options: NSLiteralSearch
|
||||
range: NSMakeRange(0, l)].length == 0)
|
||||
{
|
||||
[ma addObject: str]; // No closing '}' or repeated '{{'
|
||||
}
|
||||
else if (r.length == 0)
|
||||
{
|
||||
[ma addObject: str]; // Nothing to do.
|
||||
}
|
||||
else
|
||||
{
|
||||
NSMutableString *mtext = [[str mutableCopy] autorelease];
|
||||
|
||||
/*
|
||||
* Replace {FieldName} with the value of the field
|
||||
*/
|
||||
while (r.length > 0)
|
||||
{
|
||||
unsigned pos = r.location;
|
||||
unsigned nxt;
|
||||
unsigned vLength;
|
||||
NSArray *a;
|
||||
NSRange s;
|
||||
NSString *v;
|
||||
NSString *alt;
|
||||
id o;
|
||||
unsigned i;
|
||||
|
||||
r.length = l - pos;
|
||||
|
||||
/*
|
||||
* If the length of the string from the '{' onwards is less than two,
|
||||
* there is nothing to do and we can end processing.
|
||||
*/
|
||||
if (r.length < 2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ([mtext characterAtIndex: r.location + 1] == '{')
|
||||
{
|
||||
// Got '{{' ... remove one of them.
|
||||
r.length = 1;
|
||||
[mtext replaceCharactersInRange: r withString: @""];
|
||||
l--;
|
||||
r.location++;
|
||||
r.length = l - r.location;
|
||||
r = [mtext rangeOfString: @"{"
|
||||
options: NSLiteralSearch
|
||||
range: r];
|
||||
continue;
|
||||
}
|
||||
|
||||
r = [mtext rangeOfString: @"}"
|
||||
options: NSLiteralSearch
|
||||
range: r];
|
||||
if (r.length == 0)
|
||||
{
|
||||
break; // No closing bracket
|
||||
}
|
||||
nxt = NSMaxRange(r);
|
||||
r = NSMakeRange(pos, nxt - pos);
|
||||
s.location = r.location + 1;
|
||||
s.length = r.length - 2;
|
||||
v = [mtext substringWithRange: s];
|
||||
|
||||
/*
|
||||
* If the value contains a '?', it is actually in two parts,
|
||||
* the first part is the field name, and the second part is
|
||||
* an alternative text to be used if the value from the
|
||||
* dictionary is empty.
|
||||
*/
|
||||
s = [v rangeOfString: @"?"];
|
||||
if (s.length == 0)
|
||||
{
|
||||
alt = @""; // No alternative value.
|
||||
}
|
||||
else
|
||||
{
|
||||
alt = [v substringFromIndex: NSMaxRange(s)];
|
||||
v = [v substringToIndex: s.location];
|
||||
}
|
||||
|
||||
/*
|
||||
* If the value we are substituting contains dots, we split it apart.
|
||||
* We use the value to make a reference into the dictionary we are
|
||||
* given.
|
||||
*/
|
||||
a = [v componentsSeparatedByString: @"."];
|
||||
o = vals;
|
||||
for (i = 0; i < [a count]; i++)
|
||||
{
|
||||
NSString *k = [a objectAtIndex: i];
|
||||
|
||||
if ([k length] > 0)
|
||||
{
|
||||
o = [(NSDictionary*)o objectForKey: k];
|
||||
}
|
||||
}
|
||||
if (o == vals)
|
||||
{
|
||||
v = nil; // Mo match found.
|
||||
}
|
||||
else
|
||||
{
|
||||
if ([o isKindOfClass: NSStringClass] == YES)
|
||||
{
|
||||
v = (NSString*)o;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ([o isKindOfClass: [NSData class]] == YES)
|
||||
{
|
||||
[ma addObject: o];
|
||||
v = @"'?'''?'";
|
||||
}
|
||||
else
|
||||
{
|
||||
v = [self quote: o];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ([v length] == 0)
|
||||
{
|
||||
v = alt;
|
||||
if (v == nil)
|
||||
{
|
||||
v = @"";
|
||||
}
|
||||
}
|
||||
vLength = [v length];
|
||||
|
||||
[mtext replaceCharactersInRange: r withString: v];
|
||||
l += vLength; // Add length of string inserted
|
||||
l -= r.length; // Remove length of string replaced
|
||||
r.location += vLength;
|
||||
|
||||
if (r.location >= l)
|
||||
{
|
||||
break;
|
||||
}
|
||||
r.length = l - r.location;
|
||||
r = [mtext rangeOfString: @"{"
|
||||
options: NSLiteralSearch
|
||||
range: r];
|
||||
}
|
||||
[ma insertObject: mtext atIndex: 0];
|
||||
}
|
||||
[arp release];
|
||||
return ma;
|
||||
}
|
||||
|
||||
+ (void) _tick: (NSTimer*)t
|
||||
{
|
||||
(void) GSTickerTimeNow();
|
||||
|
@ -2943,7 +2933,7 @@ static int poolConnections = 0;
|
|||
query: (NSString*)stmt
|
||||
with: (NSDictionary*)values
|
||||
{
|
||||
stmt = [[self _substitute: stmt with: values] objectAtIndex: 0];
|
||||
stmt = [[self prepare: stmt with: values] objectAtIndex: 0];
|
||||
return [self cache: seconds simpleQuery: stmt];
|
||||
}
|
||||
|
||||
|
@ -3375,7 +3365,7 @@ static int poolConnections = 0;
|
|||
{
|
||||
NSMutableArray *p;
|
||||
|
||||
p = [_db _substitute: stmt with: values];
|
||||
p = [_db prepare: stmt with: values];
|
||||
[self _merge: p];
|
||||
}
|
||||
|
||||
|
|
|
@ -979,6 +979,11 @@
|
|||
return [c[0] prepare: stmt args: args];
|
||||
}
|
||||
|
||||
- (NSMutableArray*) prepare: (NSString*)stmt with: (NSDictionary*)values
|
||||
{
|
||||
return [c[0] prepare: stmt with: values];
|
||||
}
|
||||
|
||||
- (NSMutableArray*) query: (NSString*)stmt, ...
|
||||
{
|
||||
SQLClient *db;
|
||||
|
|
Loading…
Reference in a new issue