mirror of
https://github.com/gnustep/libs-sqlclient.git
synced 2025-02-21 02:41:07 +00:00
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:
parent
a810b93f30
commit
9e070b97c9
3 changed files with 254 additions and 90 deletions
|
@ -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:
|
||||
|
|
45
SQLClient.h
45
SQLClient.h
|
@ -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
|
||||
|
|
290
SQLClient.m
290
SQLClient.m
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue