Transaction manipulation methods added.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/sqlclient/trunk@28628 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
rfm 2009-09-08 08:05:31 +00:00
parent a810b93f30
commit 9e070b97c9
3 changed files with 254 additions and 90 deletions

View file

@ -1,3 +1,12 @@
2009-09-08 Richard Frith-Macdonald <rfm@gnu.org>
* SQLClient.h:
* SQLClient.m:
Add method for executing a batch of statements/transactions and
returning any failed statements/transactions to they can be
re-done. Also add methods to manipulate the statements in a
transaction so we can retry things intelligently.
2008-11-12 Richard Frith-Macdonald <rfm@gnu.org>
* SQLClient.h:

View file

@ -1039,7 +1039,7 @@ extern unsigned SQLClientTimeTick();
/**
* Returns a transaction object configured to handle batching and
* execute part of a batch of statements if execution of the whole
* using the [SQLTransaction-executeBatch] method fails.<br />
* using the [SQLTransaction-executeBatch:] method fails.<br />
* If stopOnFailure is YES than execution of the transaction will
* stop with the first statement to fail, otherwise it will execute
* all the statements it can, skipping any failed statements.
@ -1294,7 +1294,9 @@ extern unsigned SQLClientTimeTick();
- (id) copyWithZone: (NSZone*)z;
/**
* Returns the number of statements in this transaction.
* Returns the number of individual statements ond/r subsidiary transactions
* which have been added to the receiver. For a count of the total number
* of statements, use the -totalCount method.
*/
- (unsigned) count;
@ -1323,6 +1325,11 @@ extern unsigned SQLClientTimeTick();
*/
- (void) execute;
/** Convenience method which calls -executeBatchReturningFailures: with
* a nil argument.
*/
- (unsigned) executeBatch;
/**
* <p>This is similar to the -execute method, but may allow partial
* execution of the transaction if appropriate:
@ -1340,9 +1347,27 @@ extern unsigned SQLClientTimeTick();
* <p>If the transaction was not created using [SQLClient-batch:], then
* calling this method is equivalent to calling the -execute method.
* </p>
* <p>If any statements/transactions in the batch fail, they are added to
* the transaction supplied in the failures parameter (if it's not nil)
* so that you can retry them later.<br />
* NB. statements/transactions which are not executed at all (because the
* batch is set to stop on the first failure) are <em>also</em> added to
* the failures transaction.
* </p>
* The method returns the number of statements which actually succeeded.
*/
- (unsigned) executeBatch;
- (unsigned) executeBatchReturningFailures: (SQLTransaction*)failures;
/**
* Insert trn at the index'th position in the receiver.<br />
* The transaction trn must be non-empty and must use the same
* database client as the receiver.
*/
- (void) insertTransaction: (SQLTransaction*)trn atIndex: (unsigned)index;
/** Remove the index'th transaction or statement from the receiver.
*/
- (void) removeTransactionAtIndex: (unsigned)index;
/**
* Resets the transaction, removing all previously added statements.
@ -1350,6 +1375,20 @@ extern unsigned SQLClientTimeTick();
* transactions.
*/
- (void) reset;
/**
* Returns the total count of statements in this transaction including
* those in any subsidiary transactions. For a count of the statements
* and/or transactions directly added to the receiver, use the -count method.
*/
- (unsigned) totalCount;
/** Return an autoreleased copy of the index'th transaction or statement
* added to the receiver.<br />
* Since the returned transaction contains a copy of the statement/transaction
* in the receiver, you can modify it without effecting the original.
*/
- (SQLTransaction*) transactionAtIndex: (unsigned)index;
@end
#endif

View file

@ -2756,67 +2756,6 @@ static unsigned int maxConnections = 8;
@implementation SQLTransaction
- (unsigned) count
{
return _count;
}
- (void) dealloc
{
DESTROY(_db);
DESTROY(_info);
[super dealloc];
}
- (NSString*) description
{
return [NSString stringWithFormat: @"%@ with SQL '%@' for %@",
[super description],
(_count == 0 ? (id)@"" : (id)_info), _db];
}
- (void) add: (NSString*)stmt,...
{
va_list ap;
va_start (ap, stmt);
[_info addObject: [_db _prepare: stmt args: ap]];
_count++;
va_end (ap);
}
- (void) add: (NSString*)stmt with: (NSDictionary*)values
{
[_info addObject: [_db _substitute: stmt with: values]];
_count++;
}
- (void) append: (SQLTransaction*)other
{
if (other != nil && other->_count > 0)
{
other = [other copy];
[_info addObject: other];
_count += other->_count;
RELEASE(other);
}
}
- (id) copyWithZone: (NSZone*)z
{
SQLTransaction *c;
c = (SQLTransaction*)NSCopyObject(self, 0, z);
c->_db = RETAIN(c->_db);
c->_info = [c->_info mutableCopy];
return c;
}
- (SQLClient*) db
{
return _db;
}
- (void) _addSQL: (NSMutableString*)sql andArgs: (NSMutableArray*)args
{
unsigned count = [_info count];
@ -2875,6 +2814,73 @@ static unsigned int maxConnections = 8;
}
}
- (void) add: (NSString*)stmt,...
{
va_list ap;
va_start (ap, stmt);
[_info addObject: [_db _prepare: stmt args: ap]];
_count++;
va_end (ap);
}
- (void) add: (NSString*)stmt with: (NSDictionary*)values
{
[_info addObject: [_db _substitute: stmt with: values]];
_count++;
}
- (void) append: (SQLTransaction*)other
{
if (other != nil && other->_count > 0)
{
if (other->_db != _db)
{
[NSException raise: NSInvalidArgumentException
format: @"[%@-%@] database client missmatch",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
}
other = [other copy];
[_info addObject: other];
_count += other->_count;
RELEASE(other);
}
}
- (id) copyWithZone: (NSZone*)z
{
SQLTransaction *c;
c = (SQLTransaction*)NSCopyObject(self, 0, z);
c->_db = RETAIN(c->_db);
c->_info = [c->_info mutableCopy];
return c;
}
- (unsigned) count
{
return [_info count];
}
- (SQLClient*) db
{
return _db;
}
- (void) dealloc
{
DESTROY(_db);
DESTROY(_info);
[super dealloc];
}
- (NSString*) description
{
return [NSString stringWithFormat: @"%@ with SQL '%@' for %@",
[super description],
(_count == 0 ? (id)@"" : (id)_info), _db];
}
- (void) execute
{
if (_count > 0)
@ -2920,6 +2926,11 @@ static unsigned int maxConnections = 8;
}
- (unsigned) executeBatch
{
return [self executeBatchReturningFailures: nil];
}
- (unsigned) executeBatchReturningFailures: (SQLTransaction*)failures
{
unsigned executed = 0;
@ -2945,41 +2956,67 @@ static unsigned int maxConnections = 8;
for (i = 0; i < count; i++)
{
BOOL success = NO;
id o = [_info objectAtIndex: i];
NS_DURING
{
id o = [_info objectAtIndex: i];
if ([o isKindOfClass: NSArrayClass] == YES)
{
if ([o isKindOfClass: NSArrayClass] == YES)
{
NS_DURING
{
[_db simpleExecute: (NSArray*)o];
executed++;
success = YES;
}
else
{
unsigned result;
result = [(SQLTransaction*)o executeBatch];
executed += result;
if (result == [(SQLTransaction*)o count])
{
success = YES;
}
}
}
NS_HANDLER
{
if ([_db debugging] > 0)
NS_HANDLER
{
[_db debug: @"Failure of %d executing batch %@: %@",
i, self, localException];
if (failures != nil)
{
[failures->_info addObject: o];
failures->_count++;
}
if ([_db debugging] > 0)
{
[_db debug:
@"Failure of %d executing batch %@: %@",
i, self, localException];
}
success = NO;
}
success = NO;
}
NS_ENDHANDLER
NS_ENDHANDLER
}
else
{
unsigned result;
result = [(SQLTransaction*)o
executeBatchReturningFailures: failures];
executed += result;
if (result == [(SQLTransaction*)o totalCount])
{
success = YES;
}
}
if (success == NO && _stop == YES)
{
/* We are configured to stop after a failure,
* so we need to add all the subsequent statements
* or transactions to the list of those which have
* not been done.
*/
i++;
while (i < count)
{
id o = [_info objectAtIndex: i++];
if ([o isKindOfClass: NSArrayClass] == YES)
{
[failures->_info addObject: o];
failures->_count++;
}
else
{
[failures append: (SQLTransaction*)o];
}
}
break;
}
}
@ -2990,10 +3027,89 @@ static unsigned int maxConnections = 8;
return executed;
}
- (void) insertTransaction: (SQLTransaction*)trn atIndex: (unsigned)index
{
if (index > [_info count])
{
[NSException raise: NSRangeException
format: @"[%@-%@] index too large",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
}
if (trn == nil || trn->_count == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"[%@-%@] attempt to insert nil/empty transaction",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
}
if (trn->_db != _db)
{
[NSException raise: NSInvalidArgumentException
format: @"[%@-%@] database client missmatch",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
}
trn = [trn copy];
[_info addObject: trn];
_count += trn->_count;
RELEASE(trn);
}
- (void) removeTransactionAtIndex: (unsigned)index
{
id o;
if (index >= [_info count])
{
[NSException raise: NSRangeException
format: @"[%@-%@] index too large",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
}
o = [_info objectAtIndex: index];
if ([o isKindOfClass: NSArrayClass] == YES)
{
_count--;
}
else
{
_count -= [(SQLTransaction*)o totalCount];
}
[_info removeObjectAtIndex: index];
}
- (void) reset
{
[_info removeAllObjects];
_count = 0;
}
- (unsigned) totalCount
{
return _count;
}
- (SQLTransaction*) transactionAtIndex: (unsigned)index
{
id o;
if (index >= [_info count])
{
[NSException raise: NSRangeException
format: @"[%@-%@] index too large",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
}
o = [_info objectAtIndex: index];
if ([o isKindOfClass: NSArrayClass] == YES)
{
SQLTransaction *t = [[self db] transaction];
[t->_info addObject: o];
t->_count = 1;
return t;
}
else
{
o = [o copy];
return AUTORELEASE(o);
}
}
@end